第二章第二節 R語言因子與列表
R語言的因子實現統計功能,因此稱為R語言的先鋒不為過份。因子用以資料分類,它有兩個內容,一是資料,二是資料的分類,稱為水平levels。列表類似C語言的結構struct,元素可選擇任意資料結構,是R語言資料結構在型別上的“開拓”。
2.4.1 因子factor
分類變數刻畫資料的細分屬。統計分析常用分類,在R中稱為因子(factor)。因子應用統計學的名義變數(nominal variable)和有序變數,功能是記載資料的分組和分類,是R語言統計功能的基礎。因子有輔助資訊水平(levels)作為分類集合,因子的元素是不同值的levels集元素。水平可為分類設定有意義的標籤。
因子的水平是分類資訊,然而分類並不表示有序,例如:疾病有迴圈系統、肺部、消化系統疾病,沒有先後、程度、輕重的區別,稱為名義型類別變數。而人的健康有疾病、疲勞(亞健康)、健康、身體素質好,這四種程度是有順序的。因此因子具有普通因子和有序因子兩個型別。
應用因子生成更有意義的summary()統計資訊。
1.建立因子
函式factor()建立資料集所有元素的分類。為資料框建立因子是良好的程式設計習慣,建立向量的因子的標準格式:
factor(vector,levels=c(),ordered=TRUE)
引數levels定義水平集合,是一個整數向量,ordered表示有序分類,區分普通因子和有序因子。
eg1.建立向量的因子
>dv1=c(1,10,13,10)
>df1=factor(dv2) #factor()將dv1向量的元素進行分類,建立因子df1
>df1
[1] 1 10 13 10 #因子的元素
levels: 1 10 13 #levels集
>str(df1) #df1的內部結構
Factor w/3 levels:”1” “10” “13”:1 2 3 2 #分成三類:1,10,13
as.factor()可將資料轉換為因子。
2.資料管理
length()是因子的長度,儲存因子元素的數量而不是levels集的數量。
3.因子的操作
(1)設定有意義的levels集元素
當一個向量不允許有重複值時,因子可以檢視分類的錯誤。
eg2.1 levels()提取水平的名稱
>pain=c(0,3,2,2,1) #《R語言統計入門》p15的例子,對醫學資料的操作
>fpain=factor(pain,levels=0:3) #建立pain的因子,水平的編碼0:3
>levels(fpain)=c("none","mild","medium","severe")
以上例題為因子fpain的水平設定有意義的標籤,則fpain的元素將用標籤代替。
(2)因子元素與分類的關係
eg2.2 因子的操作
>fpain
[1] none severe medium medium mild
Levels: none mild medium severe
>as.numeric(fpain) #將fpain的元素轉換為整數
[1] 1 4 3 3 2 #數值從1開始
>levels(fpain)
[1] "none","mild","medium","severe"
以上程式表明as.numeric()只能轉換因子fpain的元素,卻不能處理levels集。
(3)分類水平的合併
若某一個分類的觀測少不能有效統計,則將兩個水平合併到一個新的因子水平中。
>ftpain1=fpain
>levels(fpain)=list(none="none",
intermediate=c("mild","medium"),
severe="severe") #合併分類用列表實現
>levels(fpain)
[1] "none","intermediate","severe"
(4)有序因子
eg3.建立醫學資料的有序因子
>patientID=c(1,2,3,4) #每個病人的ID號不同
>statu=c(“Poor”,”Excellent”,”Improved”,”Improved”) #病情
>patientdata=data.frame(patientID,statue) #先建立資料框,再建立因子
>fstat=factor(statu,levels=c(“Poor”,”Improved”,”Excellent”),ordered=TRUE)
#有序因子,詞語是有序的
>str(fstat)
ord.factor w/ 3 levels "Poor"<"Improved"<..: 1 3 2 2 #”<”表示有序因子
>patiendata$fstat=fstat
> summary(patientdata) #summary()中可知每個分類的元素數量
patientID status fstatu #有序因子
Min. :1.00 Excellent:1 Poor :1 #有一個病人情況不好
1st Qu.:1.75 Improved :2 Improved :2 #兩個病人病情好轉
Median :2.50 Poor :1 Excellent:1 #有一個病人幾乎痊癒
Mean :2.50
3rd Qu.:3.25
Max. :4.00
> unclass(patientdata)
$patientID
[1] 1 2 3 4
$status??????????
[1] Poor Excellent Improved Improved
Levels: Excellent Improved Poor
$fstat
[1] Poor Excellent Improved Improved
Levels: Poor < Improved < Excellent
引數ordered很有意義,應掌握使用方法。
3.因子的應用
(1)資料框設定因子變數
在資料框中生成重要的變數的因子,為接下來的資料分析做好準備。
將ISwR軟體包的醫學資料集thuesen的血糖含量設定分類{1,2,3,4,5,6,7,8,9,10,11,12},1對應[0,1.0)的變數值,...,12對應[11.0,12.0)。瞭解血糖的範圍可用函式range()。源程式見eg4.
eg4.設定資料框變數的因子
>library(ISwR)
>data(thuesen)
>dim1=dim(thuesen)
>dim1
[1] 24 2
>thuesen
## blood.glucose short.velocity
##1 15.3 1.76
##2 10.8 1.34
##3 8.1 1.27
##4 19.5 1.47
##5 7.2 1.27
##6 5.3 1.49
##7 9.3 1.31
##8 11.1 1.09
##9 7.5 1.18
##10 12.2 1.22
##11 6.7 1.25
##12 5.2 1.19
##13 19.0 1.95
##14 15.1 1.28
##15 6.7 1.52
##16 8.6 NA
##17 4.2 1.12
##18 10.3 1.37
##19 12.5 1.19
##20 16.1 1.05
##21 13.3 1.32
##22 4.9 1.03
##23 8.8 1.12
##24 9.5 1.70
>range(thuesen[1])
[1] 4.2 19.5
>levels=seq(4,20,1) #4,20是range的整數
>levl=length(levles)
>ln=dim1[1]
>fthues=factor(1:ln,levels)
>fthues
##[1] <NA> <NA> <NA> 4 5 6 7 8 9 10 11 12 13 14
##[15] 15 16 17 18 19 20 <NA> <NA> <NA> <NA>
Levels: 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
> typeof(fthues) #資料型別
[1] "integer"
> class(fthues) #型別
[1] "factor"
> str(fthues) #fthues內部結構
Factor w/ 16 levels "4","5","6","7",..: 12 7 5 16 4 2 6 8 4 9 ...
#可用迴圈語句實現而不是簡單羅立
>for(i in 1:levl-1) #i是向量levels的下標,不可與levels元素的值混淆
#i=1,levels[i]=4;i=2,levels[i]=5
{
logthes=thuesen$blood.glu<levels[i+1]$thuesen$blood.glu>=levels[i]
#logthes是邏輯向量,表示下標有效的邏輯值
#levels[levl]=20是為程式設計設定的一個值,無實際意義
fthues[logthes]=levels[i]
#fthues[logthes]不等於levels的下標i,應仔細不可疏忽
}
>fthues
##[1] 15 10 8 19 7 5 9 11 7 12 6 5 19 15 6 8 4 10 12 16 13 4 8 9
##Levels: 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
>fthues=factor(fthues,levels=seq(4,19,1),ordered=TRUE)
>str(fthues)
ord.factor w/ 16 levels "4"<"5"<"6"<"7"<..: 12 7 5 16 4 2 6 8 4 9 ...
>thuesen$fthues=fthues
>summary(thuesen)
blood.glucose short.velocity fthues #因子fthues頻數的統計
Min. : 4.200 Min. :1.030 8 : 3
1st Qu.: 7.075 1st Qu.:1.185 4 : 2
Median : 9.400 Median :1.270 5 : 2
Mean :10.300 Mean :1.326 6 : 2
3rd Qu.:12.700 3rd Qu.:1.420 7 : 2
Max. :19.500 Max. :1.950 9 : 2
NA's :1 (Other):11
對資料框的變數設定因子,可用summary()統計每一類的元素數量,並且可應用tapply()函式對每一個進行相同的計算f()。
(2)線性迴歸的應用
因子線上性迴歸函式的資料擬閤中應用,使得輸出變短。因子的統計資訊可用匯總統計函式summary()表示。函式summary()體現資料框所有變數的彙總資訊,顯示數值連續型變數的最小值、最大值、均值和各四分位數,factor變數各水平的頻數值。因此,因子變數的應用線上性迴歸函式lm()的統計資訊中,可使輸出更短小精悍。
>summary(thuesen)
4.因子的函式
unclass()顯示因子的分類,而且有attr()等。
>unclass(df1)
[1] 1 2 3 2
>unclass(fthues)
>unclass(pathtiendata$fstatu)
5.tapply()應用和factor因子
eg5. tapply(data,index,f())的應用
> ages <-c(26,28,56,38,25,42)
> affits <-c("R","D","D","R","U","D") #用途類似levels,但是沒有生成factor
>tapply(ages,affits,means) #應用affits對ages向量進行分類,計算每類的means
D R U
42 32 25
函式tapply()把向量affits當作因子,levels={"D","R","U"},”D”出現在下標2,3,6的位置,”R”出現在1,4的位置,”U”出現在5。因此,ages向量的分組是(26,55,42),(25,37),(21)。然後,tapply()對所有分組計算means均值,分別是41,31,21。此程式設計方法是對資料設定向量作為因子,因此並不是根據資料的可管理特性應用factor()進行分類,而是根據實際應用的要求。不能用factor()對向量元素進行分類時可用此方法,但是對大量資料設定每個元素的分類則很費力,例如ISwR軟體包的thuesen資料集。
函式tapply()的功能是,根據分類向量levels分組資料向量data,可得到多個分組資料,然後對所有分組應用函式f()。因此tapply()函式可不需要對資料框的不同變數應用計算f(),而是對不同長度的分組資料應用計算f()。
2.4.2 列表list
列表(list)像C的結構struct或python語言的字典型別。列表的元件(components)稱為分量或元素,元件名則為標籤tags。R語言資料框和麵向物件程式設計的基礎是列表。列表元素的長度可不相同,型別可是單元素或者列表,因此在遞迴型recursive資料結構的基礎上看,列表是資料結構中的廣義表。
1. 建立列表
函式list()建立不同部件組成的列表,分量可以是不同型別和長度的向量、矩陣、資料框、列表。列表是R語言多數函式的返回值型別,因此R語言函式可返回多個值組成一個列表,與C語言不同。list()的標準格式:
list(tag1=compon1,tag2=compon2,...,tagR=componR)
列表的常用應用有多維陣列的標籤,新增資料框的觀察,以及構成實際的報表格式。建立列表還可用函式vector(),引數mode=list。
eg1.三維陣列標籤的產生
dim1=c(“A1”,”A2”,”A3”)
dim2=c(“B1”,”B2”)
dim3=c(“C1”,”C2”,”C3”)
dimnames=list(dim1,dim2,dim3)
eg2.列表構成的報表
報表名稱:一個字串,gs=”This is 2016 fist list”
報表的主要物件:一個數值型向量,ha=c(20,29,39,43)
報表的主要內容:一個矩陣,salaryM=matrix(1:10,nrow=5)
報表的註釋:一個字元型向量,notes=c(“one”,”two”,”three”)
則,生成報表,dlist1=list(Title=gs,age=ha,salaryM,notes)。
只有前兩個元件有標籤。元件的編號又稱為索引。?
eg3.用vector()建立列表,因為列表是向量。
>dlist2=vector(mode=list)
>dlist2[["events"]]=c("writing Docx ","studying","research")
>dist2
$events
[1] "writing Docx" "studying" "research"
2.資料管理
資料型別 mode()、列表元件個數 length()、獲得標籤 names()。
3.列表元件的訪問
選取列表元件的方法有三個,list$標籤,list[["標籤"]],list[[元件編號]]。若要訪問分量中的元素,則用list[[元件編號]][元素下標範圍s:t]或list$[元件名][s:t]。元素下標範圍同樣可用條件選擇的方法。
>dlist2[[1]]
[1] "writing Docx" "studying" "research"
>dlist2[[1]][2:3]
[1] "studying" "research"
4.資料操作
(1)增加列表元件
方法一,元件賦值dlist2$timecha=c("Lqm","Lih","Sh"),方法二,元件下標索引賦值dlist2[[3]]=c(20,20,20,100,100,30),則列表dlist2有三個元件。
(2)刪除列表元素
將列表元件設定為NULL,應注意此元素後面元件的下標索引都減1。
(3)生成子列表[]
用list["標籤"]和list[元件編號]返回子列表,而list[[]]訪問元件,返回元件的型別。
>dlist3=dlist2[2] #此方法類似資料框[列下標]
>class(dlist3)
[1] "list"
>dlist3
$timecha
[1] "Lqm" "Lih" "Sh"
(4)c()拼接合並多個列表
然而c()合併的列表中,元件的層次相同。若要保持元件是一個列表,應用list()更恰當。
>dlist4=c(list("tomorrow",2016-10-19,5),list(read,writing))
>class(dlist4)
[1] "list"
>length(dlist4)
[1] 5
>dlist4
>str(dlist4)
>dlist5=list(list("tomorrow",2016-10-19,5),list(read,writing))
>str(dlist5)
5.列表的函式
(1)unlist()
unlist()把列表轉換為向量,獲取列表的值,而且此向量的元素有標籤。去掉元素標籤用函式unnames()。若列表元素是字串則unlist()的返回值是字串,若列表元素都是數值型則產生數值向量。若兩類元素都有或者列表元素型別不同,則執行強制轉換,生成大多數元素的型別,例如字串。
>dv1=unlist(dlist4)
>class(dv1)
[1] character
>length(dv1)
[1] 5
6.應用apply族函式
7.型別轉換
is.recursive(x)可判斷列表是否遞迴型別。Is.list()可發現函式的返回值是否列表。as.list()轉換產生列表。