第 7 章 Data Frame and Matrix

7.1 主要參考資料

  • 曾意儒, Chapter 2.5

  • RDS: Chapter 11 Data import

  • Matrix (矩陣)- A matrix is a collection of data elements arranged in a two-dimensional rectangular layout (方/長方形排列).

  • DataFrame - A dataframe is used for storing data tables. It is a list of vectors of equal length.

7.2 Matrix

Matrix:

Mat1 <- matrix(
  c(1:6), 2,3
)
Mat1

Matrix只是vector的一種新的排列形式,雖然它的class自成一格為matrix,但它的type依然會是它架構根源的atomic vector形式。

class(Mat1)
typeof(Mat1)
Mat2 <- matrix(
  c("a","b","c","d"), 2, 2
)
Mat2

注意:Matrix是以atomic vector為基礎的一種排列形式,所以它的元素type一定齊質。

7.3 Data Frame

考慮以下資料,它含有學號,姓名,成績等三個資料變數,變數裡的元素各別代表一筆資料:

list:因為三個變數向量的type不相同,只能用list儲存。

StuList <- list(
  學號=c(172,214,322,425,517),
  姓名=c("小明","大雄","胖虎","小新","大白"),
  成績=c(80,60,90,70,50)
  )
StuList 

data frame:若每個變數相同元素位置來自於同一筆資料,我們可以使用data frame的class來儲存這樣的(長)方形資料表。

StuDF <- data.frame(
  學號=c(172,214,322,425,517),
  姓名=c("小明","大雄","胖虎","小新","大白"),
  成績=c(80,60,90,70,50)
  )
StuDF 

data.frame()遇到變數輸入為character class時,內定會被轉成factor。

class(StuDF$姓名)

StuDF$姓名 <- as.character(StuDF$姓名)
class(StuDF$姓名)

取消內定character為factor的方式:as.data.frame(..., stringsAsFactors = FALSE)

class(StuList)
as.data.frame(StuList) -> StuDF3

class(StuDF3)
StuDF3
as.data.frame(StuList,stringsAsFactors = F) -> StuDF4
class(StuDF4)
StuDF4

data.frame(..., stringsAsFactors = FALSE)

StuDF2 <- data.frame(
  學號=c(172,214,322,425,517),
  姓名=c("小明","大雄","胖虎","小新","大白"),
  成績=c(80,60,90,70,50),
  stringsAsFactors = FALSE
  )
StuDF2 

Data frame其本質(即type)是list vector,但因它的資料表配置特性而會有更豐富的特質,因此其class會自成一類。

class(StuDF)
typeof(StuDF)

data frame的建立也可以用list去建好,再透過as.data.frame()去改變其class成data frame.

7.4 [.R , .C] object extraction

[.R,.C]: 為方形資料class(即matrix和data frame),獨有的object extraction。

  • 只有一個[]中括號,所以和[.].有相同的規則: .R.C可以用

    • 數值向量:如c(1,8,12)

    • 邏輯向量:如c(T,T,F)

    • 元素名稱向量(當元素有名字時)

  • .R: 代表哪幾列(rows); .C: 代表哪幾欄/行(columns)

LETTERS # R內設元素值為英文字母群的character vector
chosenLETTERS <- LETTERS[1:15]
matObj1 <- matrix(chosenLETTERS,5,3)
matObj1
chosenLETTERS[8]
matObj1[8]
matObj1
matObj1[3,2] 
matObj1[c(F,F,TRUE,F,F),c(F,TRUE,F)]

若只用[.] extraction, 如何取出matObj1[c(1,5),c(2,3)]的元素值?

StuDF
StuDF[c("姓名","成績")] 
StuDF[1:5,c("姓名","成績")] 

.R, .C不填寫,則表示「全取」的意思:

StuDF[,c("姓名","成績")]

請出matObj1的第3欄。

matObj1[,3]
cbind(matObj1,letters[1:5])

請取出StuDF中小新的成績:

StuDF
StuList

若是用StuList,你要怎麼取?

StuDF[4,c("成績")]

7.5 names, colnames, rownames

  • names():

    • vector角度對元素進行名稱查詢

    • names() <-:可用來命名。

Vector1 <- letters[1:6]
Vector1

names(Vector1)
names(Vector1) <- c('名稱1','名稱2','名稱3','名稱4','名稱5','名稱6')
names(Vector1)
Mat1
names(Mat1) 
names(Mat1) <- letters[1:6]
names(Mat1)

請將StuDF的欄位變數名稱改成StudentID, Name, Grade。

  • colnames()rownames()

    • 分別對方形資料class(即matrix與data frame)的欄(column)及行(row)進行名稱查詢。

    • colnames() <-rownames() <-:可用來命名。

matObj1
colnames(matObj1) 
rownames(matObj1)
colnames(matObj1) <-c('欄位1','欄位2','欄位3')
colnames(matObj1)
matObj1
rownames(matObj1) <- c('行:1','行:2','行:3','行:4','行:5')
matObj1

請使用字串名稱,用[,]取出row 3, 5及column 1,3的值。

7.6 新增/替換元素

元素提取[.],[[.]],$.也可用來進行元素「值」修改或「新增」。

  • .所指定的元素不存在,則為「新增」。

  • .所指定的元素存在,則為「修改」。

7.6.1 使用[[.]] <-$. <-

範例

a <- c("1","b","TRUE")
a
a[[2]] <- "c" # 元素存在
a[[5]] <- "7" # 元素不存在
a

請將下面的TRUE換成FALSE, 並增加第5個元素其值為數字7。

b <- list(
  元素1=1,
  元素2="Hello",
  元素3=TRUE
)

List物件比atomic vector多了使用$.提取元素的選擇,

  • .必需是元素名稱。

  • 由於data frame也是list type,所以也可以用$.來提取/新增/修改變數欄位值。

使用$.將上一個練習b的第2個元素改成“Hi”,且新增一個名為「新成員」的整數向量其值為整數2,5,1。(「新成員」的class是integer)

引入以下匯率資料:

library(readr)
exData3 <- read_csv("https://raw.githubusercontent.com/tpemartin/github-data/master/exData3.csv",
                    col_types = cols(
                      匯率 = col_number(),
                      期間 = col_character()))
  • 取出「期間」變數轉成date class。

  • 增加一個「isAsiaCrisis」的logical變數,其值為TRUE若「期間」介於1997-06-01到1998-12-01(含前後)。

  • 利用「isAsiaCrisis」值,結合使用[.R,.C]取出1997-06-01到1998-12-01亞洲金融危機的子樣本。

7.6.2 使用[.] <-

由於[.]是一個中括號取法,

  • 主要用於增加多個元素。

然而一個中括號會保留母層結構,所以<-右側要保留母層資料創立方式(即被提取物件的class):

  • 母層若為list,則需用list(...)方式增加。

  • 母層若為data frame,則需用data.frame(...)方式增加。

  • 母層若為atomic vector,則用c(...)方式增加。

範例

a2 <- c(2,5,10)
a2
a2[c(3,7)] <- c(-1,0)
a2

範例

b2 <- list(
  元素1=c(1,4,9),
  元素2=c("Hello"),
  元素3=c(T,T,F,F,F,T,T)
)
b2
b2[c(2,4)] <- list(
  c("Hi","How are you?"),
  c(-1,-2)
)
b2

執行以下程序:

StuDF <- data.frame(
  學號=c(172,214,322,425,517),
  姓名=c("小明","大雄","胖虎","小新","大白"),
  成績=c(80,60,90,70,50)
  )

將成績各減5分,同時增加一個logical class變數叫「及格」其值為TRUE代表成績大於等於60。請使用[.]一次完成這兩件事。

[.].若使用數字向量來取元素,數字向量不一定要由小到大排列:

a3 <- c('Q','B','W','U','J','D','L','V','X','G')
a3
a3[c(2,4,5)]
a3[c(5,2,4)]

我們可以輕易重新排列元素:

revert <- seq(10,1,by=-1)
revert
a3 <- c('Q','B','W','U','J','D','L','V','X','G')
a3
a3[revert]-> a3
a3

課堂練習

1.

以下各題以課堂調查的classSurvey資料框(data frame)為主:

library(readr)
classSurvey <- read_csv("https://raw.githubusercontent.com/tpemartin/github-data/master/classSurvey.csv")

1.1 使用dim()查詢classSurvey有多少觀察值?有多少變數?(前者也可以用nrow(), 後者也可以用ncol())

1.2 新增一個變數叫年級,它必需是個factor,且有四個levels:大一,大二,大三,大四及以上。(hint: 取出適當的學號碼,透過as.factor(),levels()來達成。)

1.3 各年級有多少人?

1.4 在課堂調查的classSurvey裡大二(含)以上的人有多少比例為男性? (hint: length()可計算vector(如一個變數)有多少元素,dim()計算矩陣或data frame有多少個row(即觀測值個數)及多少個column(即變數數目))

1.5 大一的男性比例又有多少呢?

1.6 學生參加最多的課外活動是什麼?請適當利用table()呈現。

1.7 學生來自的縣市分佈如何?請適當利用table()呈現。