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
对数据框的变量设置因子,可用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. 创建列表
向量、矩阵、数据框、列表。列表是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()转换产生列表。