R語言入門之建立資料集——向量、矩陣、陣列、資料框和列表
摘要
隨著大資料的火爆發展,適合資料分析及生成圖表的R語言也在“最受歡迎的程式語言”中上升到了17位。R語言的種種特性令其十分易於進行資料分析,並因其能通過簡短的程式碼生成一目瞭然的圖令眾多資料分析師垂涎三尺。進行資料分析的第一步是先拿到資料,本文就簡單描述一下R語言的各種資料集——向量、矩陣、陣列、資料框和列表的建立及使用。
向量
向量是用於儲存數值型、字元型或邏輯型資料的一維陣列。執行組合功能的函式c()可用來 建立向量。值得注意的是,單個向量中的資料型別是固定的,比如數值型向量中的元素就必須全為向量。
#向量建立使用示例
> a <- c(1,2,5,3,6,-2 ,4) #數值型向量
> a
[1] 1 2 5 3 6 -2 4
> b <- c("one","two","three") #字元型向量
> b
[1] "one" "two" "three"
> c <- c(TRUE,TRUE,T,FALSE,TRUE,F) #邏輯型向量
> c
[1] TRUE TRUE TRUE FALSE TRUE FALSE
注意這裡的邏輯型向量中,TRUE/FALSE是R語言中自帶的,是無法被使用者所重寫的。而T/F卻不同,所以就算能將TRUE/FALSE簡寫為T/F。但建議還是不要這樣做。這是一個好習慣。
通過在方括號中給定元素所處位置的數值,我們可以訪問向量中的元素。例如:
> a[1]
[1] 1
> a[c(1,3)]
[1] 1 5
> b[1:3]
[1] "one" "two" "three"
最後一個語句中使用的冒號用於生成一個數值序列。例如,a <- c(1:3)等價於a <- c(1, 2, 3。
矩陣
矩陣是一個二維陣列,只是每個元素都擁有相同的模式(數值型、字元型或邏輯型)。可通 過函式matrix建立矩陣。一般使用格式為:
> mymatrix <- matrix(vector,nrow=number_of_rows,ncol=number_of_columns,
+ byrow=logical_value,dimnames=list(
+ char_vector_rowname,char_vector_colnames))
其中vector包含了矩陣的元素,nrow和ncol用以指定行和列的維數,dimnames包含了可選的、 以字元型向量表示的行名和列名。選項byrow則表明矩陣應當按行填充(byrow=TRUE)還是按 列填充(byrow=FALSE),預設情況下按列填充。簡單示例如下:
> y <- matrix(1:20,nrow=5,ncol=4) #建立一個5*4的矩陣
> y
[,1] [,2] [,3] [,4]
[1,] 1 6 11 16
[2,] 2 7 12 17
[3,] 3 8 13 18
[4,] 4 9 14 19
[5,] 5 10 15 20
> #按行填充的2*2矩陣
> cells <- c(1,26,24,68)
> rnames <- c("R1","R2")
> cname <- c("C1","C2")
> > mymatrix <- matrix(cells,nrow=2,ncol=2,byrow=TRUE,
+ dimnames=list(rnames,cname))
> mymatrix
C1 C2
R1 1 26
> #按列填充的2*2矩陣
> mymatrix <- matrix(cells,nrow=2,ncol=2,byrow=FALSE,
+ dimnames=list(rnames,cname))
> mymatrix
C1 C2
R1 1 24
R2 26 68
我們可以使用下標和方括號來選擇矩陣中的行、列或元素。X[i,]指矩陣X中的第i 行,X[,j] 指第j 列,X[i, j]指第i 行第j 個元素。選擇多行或多列時,下標i 和j 可為數值型向量,如:
> x <- matrix(1:10,nrow=2)
> x
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 5 7 9
[2,] 2 4 6 8 10
> x[2,]
[1] 2 4 6 8 10
> x[,2]
[1] 3 4
> x[1,4]
[1] 7
> x[1,c(4,5)]
[1] 7 9
矩陣都是二維的,和向量類似,矩陣中也僅能包含一種資料型別。當維度超過2時,不妨使 用陣列。當有多種模式的資料時,不妨使用資料框。
陣列
陣列(array)與矩陣類似,但是維度可以大於2。陣列可通過array函式建立,形式如下:
> myarray <- array(vector,dimensions,dimnames)
其中vector包含了陣列中的資料,dimensions是一個數值型向量,給出了各個維度下標的大 值,而dimnames是可選的、各維度名稱標籤的列表。
建立三維 (2×3×4)數值型陣列:
> z <- array(1:24, c(2,3,4),dimnames=list(dim1,dim2,dim3))
> z
, , C1
B1 B2 B3
A1 1 3 5
A2 2 4 6
, , C2
B1 B2 B3
A1 7 9 11
A2 8 10 12
, , C3
B1 B2 B3
A1 13 15 17
A2 14 16 18
, , C4
B1 B2 B3
A1 19 21 23
A2 20 22 24
如你所見,陣列是矩陣的一個自然推廣。它們在編寫新的統計方法時可能很有用。像矩陣一 樣,陣列中的資料也只能擁有一種模式。 從陣列中選取元素的方式與矩陣相同。上例中,元素z[1,2,3]為15
資料框
由於不同的列可以包含不同模式(數值型、字元型等)的資料,資料框的概念較矩陣來說更 為一般。資料框將是你在R中常處理的 資料結構。
資料框可通過函式data.frame()建立:
> mydata <- data.frame(col1,col2,col3,…)
其中的列向量col1, col2, col3,… 可為任何型別(如字元型、數值型或邏輯型)。每一列的 名稱可由函式names指定。
用法:
> patientID <- c(1,2,3,4)
> age <- c(25,34,28,52)
> diabetes <- c("Type1","Type2","Type1","Type1")
> status <- c("Poor","Improved","Excellent","Poor")
> patientdata <- data.frame(patientID,age,diabetes,status)
> patientdata
patientID age diabetes status
1 1 25 Type1 Poor
2 2 34 Type2 Improved
3 3 28 Type1 Excellent
4 4 52 Type1 Poor
每一列資料的模式必須唯一,不過你卻可以將多個模式的不同列放到一起組成資料框。
選取資料框中元素的方式有若干種。你可以使用前述(如矩陣中的)下標記號,亦可直接指 定列名。如:
> patientdata
patientID age diabetes status
1 1 25 Type1 Poor
2 2 34 Type2 Improved
3 3 28 Type1 Excellent
4 4 52 Type1 Poor
> patientdata[1:2]
patientID age
1 1 25
2 2 34
3 3 28
4 4 52
> patientdata[c("diabetes","status")]
diabetes status
1 Type1 Poor
2 Type2 Improved
3 Type1 Excellent
4 Type1 Poor
> patientdata$age
[1] 25 34 28 52
第三個例子中的記號$是新出現的 。它被用來選取一個給定資料框中的某個特定變數。例 如,如果你想生成糖尿病型別變數diabetes和病情變數status的列聯表,使用以下程式碼即可:
> table(patientdata$diabetes,patientdata$status)
Excellent Improved Poor
Type1 1 0 2
Type2 0 1 0
在每個變數名前都鍵入一次patientdata$可能會讓人生厭,所以不妨走一些捷徑。可以聯 合使用函式attach()和detach()或單獨使用函式with()來簡化程式碼。
- attach()、detach()和with() 函式attach()可將資料框新增到R的搜尋路徑中。R在遇到一個變數名以後,將檢查搜尋路 徑中的資料框,以定位到這個變數。
> summary(mtcars$mpg)
Min. 1st Qu. Median Mean 3rd Qu. Max.
10.40 15.42 19.20 20.09 22.80 33.90
> plot(mtcars$mpg,mtcars$disp)
> #也可寫成:
> attach(mtcars)
> plot(mpg,disp)
> detach(mtcars)
函式detach()將資料框從搜尋路徑中移除。
當名稱相同的物件不止一個時,這種方法的侷限性就很明顯了。
> mpg <- c(25,36,47)
> attach(mtcars)
The following object is masked _by_ .GlobalEnv: mpg
> plot(mpg,wt)
Error in xy.coords(x, y, xlabel, ylabel, log) :
'x' and 'y' lengths differ
> mpg
[1] 25 36 47
> plot(mtcars$mpg,wt)
這裡,在資料框mtcars被繫結(attach)之前,我們的環境中已經有了一個名為mpg的物件。 在這種情況下,原始物件將取得優先權,故而報錯,這個時候想使用mpg時,便要像最後一段程式碼示例那般。
除此之外,另一種方式是使用函式with()。你可以這樣重寫上例:
> with(mtcars,{
+ plot(mpg,disp)
+ })
在這種情況下,大括號{}之間的語句都針對資料框mtcars執行,這樣就無須擔心名稱衝突 了。如果僅有一條語句(例如summary(mpg)),那麼大括號{}可以省略。 函式with()的侷限性在於,賦值僅在此函式的括號內生效。如:
> with(mtcars,{stats <-summary(mpg)
+ stats
+ })
Min. 1st Qu. Median Mean 3rd Qu. Max.
10.40 15.42 19.20 20.09 22.80 33.90
> stats
錯誤: 找不到物件'stats'
如果你需要建立在with()結構以外存在的物件,使用特殊賦值符<<-替代標準賦值符(<-) 即可,它可將物件儲存到with()之外的全域性環境中。如:
> with(mtcars,{
+ nokeepstats <- summary(mpg)
+ keepstats <<- summary(mpg)
+ })
> nokeepstats
錯誤: 找不到物件'nokeepstats'
> keepstats
Min. 1st Qu. Median Mean 3rd Qu. Max.
10.40 15.42 19.20 20.09 22.80 33.90
因子
如你所見,變數可歸結為名義型、有序型或連續型變數。名義型變數是沒有順序之分的類別 變數。糖尿病型別Diabetes(Type1、Type2)是名義型變數的一例。即使在資料中Type1編碼 為1而Type2編碼為2,這也並不意味著二者是有序的。有序型變量表示一種順序關係,而非數量 關係。病情Status(poor, improved, excellent)是順序型變數的一個上佳示例。我們明白, 病情為poor(較差)病人的狀態不如improved(病情好轉)的病人,但並不知道相差多少。連續 型變數可以呈現為某個範圍內的任意值,並同時表示了順序和數量。年齡Age就是一個連續型變 量,它能夠表示像14.5或22.8這樣的值以及其間的其他任意值。很清楚,15歲的人比14歲的人年 長一歲。
類別(名義型)變數和有序類別(有序型)變數在R中稱為因子(factor)。因子在R中非常重 要,因為它決定了資料的分析方式以及如何進行視覺呈現。你將在本書中通篇看到這樣的例子。 函式factor()以一個整數向量的形式儲存類別值,整數的取值範圍是[1… k ](其中k 是名義 型變數中唯一值的個數),同時一個由字串(原始值)組成的內部向量將對映到這些整數上。
舉例來說,假設有向量:
> diabetes <- c("Type1","Type2","Type1","Type1")
語句diabetes <- factor(diabetes)將此向量儲存為(1, 2, 1, 1),並在內部將其關聯為 1=Type1和2=Type2(具體賦值根據字母順序而定)。針對向量diabetes進行的任何分析都會將 其作為名義型變數對待,並自動選擇適合這一測量尺度的統計方法。 要表示有序型變數,需要為函式factor()指定引數ordered=TRUE。給定向量:
> status <- c("Poor","Improved","Excellent","Poor")
語句status <- factor(status, ordered=TRUE)會將向量編碼為(3, 2, 1, 3),並在內部將這 些值關聯為1=Excellent、2=Improved以及3=Poor。
對於字元型向量,因子的水平預設依字母順序建立。這對於因子status是有意義的,因為 “Excellent”、“Improved”、“Poor”的排序方式恰好與邏輯順序相一致。如果“Poor”被編碼為 “Ailing”,會有問題,因為順序將為“Ailing”、“Excellent”、“Improved”。如果理想中的順序是 “Poor”、“Improved”、“Excellent”,則會出現類似的問題。按預設的字母順序排序的因子很少能 夠讓人滿意。 你可以通過指定levels選項來覆蓋預設排序。例如:
> status <- factor(status,orde=TRUE,
+ levels=c("Poor","Improved","Excellent")
+ )
因子的使用:
> patientdata <-data.frame(patientID,age,diabetes,status)
> str(patientdata)
'data.frame': 4 obs. of 4 variables:
$ patientID: num 1 2 3 4
$ age : num 25 34 28 52
$ diabetes : Factor w/ 2 levels "Type1","Type2": 1 2 1 1
$ status : Ord.factor w/ 3 levels "Poor"<"Improved"<..: 1 2 3 1
> summary(patientdata)
patientID age diabetes status
Min. :1.00 Min. :25.00 Type1:3 Poor :2
1st Qu.:1.75 1st Qu.:27.25 Type2:1 Improved :1
Median :2.50 Median :31.00 Excellent:1
Mean :2.50 Mean :34.75
3rd Qu.:3.25 3rd Qu.:38.50
Max. :4.00 Max. :52.00
此例子中使用的資料集都是前面例子中用到的,忘記的看客可以上去看看。
str(patientdata)清楚地顯示diabetes是一個因子,而status是一個有序型因子, 以及此資料框在內部是如何進行編碼的。注意,函式summary()會區別對待各個變數 。它顯示 了連續型變數age的小值、大值、均值和各四分位數,並顯示了類別型變數diabetes和 status(各水平)的頻數值。
列表
列表(list)是R的資料型別中為複雜的一種。一般來說,列表就是一些物件(或成分, component)的有序集合。列表允許你整合若干(可能無關的)物件到單個物件名下。例如,某個 列表中可能是若干向量、矩陣、資料框,甚至其他列表的組合。可以使用函式list()建立列表
> mylist <- list(object1,object2,…)
其中的物件可以是目前為止講到的任何結構。你還可以為列表中的物件命名:
> mylist <- list(name1=object1,name2=object2,…)
例如:
> g <- "My First List"
> h <- c(25,26,18,39)
> j <- matrix(1:10,nrow=5)
> k <- c("one","two","three")
> mylist <- list(title=g,ages=h,j,k)
> mylist
$title
[1] "My First List"
$ages
[1] 25 26 18 39
[[3]]
[,1] [,2]
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
[[4]]
[1] "one" "two" "three"
本例建立了一個列表,其中有四個成分:一個字串、一個數值型向量、一個矩陣以及一個 字元型向量。可以組合任意多的物件,並將它們儲存為一個列表。 你也可以通過在雙重方括號中指明代表某個成分的數字或名稱來訪問列表中的元素。此例 中,mylist[[2]]和mylist[[“ages”]]均指那個含有四個元素的向量。由於兩個原因,列表 成為了R中的重要資料結構。首先,列表允許以一種簡單的方式組織和重新呼叫不相干的資訊。 其次,許多R函式的執行結果都是以列表的形式返回的。需要取出其中哪些成分由分析人員決定。