3.2.1 表格table()
分组数据表示的信息用表格描述,表格是双向(two-way)的。分组数据中因子的数量称为频数,table()生成频数表描述因子或数据向量的数值分布概况,相对频数又称为频率。table族函数有marqin.table()计算边际表格,prop.table()计算相对频数,addmagins()计算条件频数(边际值)。
table()的另一个功能是对数据框和列表进行多维分组,用多个变量或元素分组另一个变量或元素,结果用逻辑值表示位置上有值,实现将变量数据分组到高维数组的不同层。因此,高维数组和table()有关联。table()的函数有dimnames()获得维度的名称和水平值。
eg1.计算数字出现的相对频数
>dv1.1=c(22,23,24,22,23,23,12,13,14,14,14,23,23,22)
>dv1.2=c(14,23,13,13,12,13,13,22,12,11,22,21)
>dv1=c(dv1.1,dv1.2)
>dtable1=table(dv1)
>dtable1
11 12 13 14 21 22 23 24
1 3 5 4 1 5 6 1
>dv2=as.vector(dtable1)
[1] 1 3 5 4 1 5 6 1
>dtable2=prop.table(dtable1)
dv1
11 12 13 14 21 22 23
0.03846154 0.11538462 0.19230769 0.15384615 0.03846154 0.19230769 0.23076923
24
0.03846154
>dv3=as.vector(dtable2)
> dv3
[1] 0.03846154 0.11538462 0.19230769 0.15384615 0.03846154 0.19230769
[7] 0.23076923 0.03846154
>dafr1=data.frame(dv2,dv3)
> dafr1
dv2 dv3
1 1 0.03846154
2 3 0.11538462
3 5 0.19230769
4 4 0.15384615
5 1 0.03846154
6 5 0.19230769
7 6 0.23076923
8 1 0.03846154
看到编号不容易理解,则将编号替换为数字:
>dimnames(dafr1)=list(c('11','12','13','14','','21','22','23','24'),c("频数","频率"))
> dafr1
频数 频率
11 1 0.03846154
12 3 0.11538462
13 5 0.19230769
14 4 0.15384615
21 1 0.03846154
22 5 0.19230769
23 6 0.23076923
24 1 0.03846154
tapply()帮助文件中的例题比较table()与tapply()的不同,包括对因子向量分类,用因子向量分类数据向量用法的比较等。
eg2.tapply()与table()统计groups分类后的频数
>require(stats)
>groups=as.factor(rbinom(32, n = 5, prob = 0.4)) #创建因子
#二项分布B(5,0.4)的32个随机数
>groups
##[1] 15 13 13 16 12
##Levels: 12 13 15 16
>tapply(groups, groups, length) #对groups进行分类,应用length()
##12 13 15 16
##1 2 1 1
>table(groups) #比较table(),对同一个向量分类的频数计算相同
##groups
##12 13 15 16
## 1 2 1 1
tapply()是建立在table()上,对分组应用函数。
eg3.tapply()与table()用因子对数据向量分类的用法比较
>n=17
>fac=factor(rep(1:3, length=n), levels=1:5) #fac是因子
> fac
[1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
Levels: 1 2 3 4 5
> dv1=tapply(1:n,fac,length) #分类{1,2,...,n},统计分组数据的数量
> dv1
1 2 3 4 5 #按位置分类,对应因子相同的元素则是同一类
6 6 5 NA NA
> dv2=tapply(1:n, fac, sum) #分类数据向量,计算分组数据的总值
> dv2
1 2 3 4 5
51 57 45 NA NA
> tapply(1:n, fac, sum, simplify = FALSE) #输出列表
$`1`
[1] 51
$`2`
[1] 57
$`3`
[1] 45
$`4`
NULL
$`5`
NULL
> range(1,2,3) #分析range()的用法,数据范围i
[1] 1 3
> range(1,2,3,1,2,3)
[1] 1 3
> tapply(1:n, fac, range) #对分类数据是每一类的范围
$`1`
[1] 1 16
$`2`
[1] 2 17
$`3`
[1] 3 15
$`4`
NULL
$`5`
NULL
> range(1:n)
[1] 1 17
> dv=1:n
> tapply(dv,fac,range)
$`1`
[1] 1 16
$`2`
[1] 2 17
$`3`
[1] 3 15
$`4`
NULL
$`5`
NULL
> range(dlist) #dlist范围不变
[1] 1 17
> dv1=11:27
> dlist1=split(dv1,fac)
> dlist1
$`1`
[1] 11 14 17 20 23 26
$`2`
[1] 12 15 18 21 24 27
$`3`
[1] 13 16 19 22 25
$`4`
integer(0)
$`5`
integer(0)
> lapply(dlist1,range) #range()仍然是数据向量范围
$`1`
[1] 11 26
$`2`
[1] 12 27
$`3`
[1] 13 25
$`4`
[1] Inf -Inf
$`5`
[1] Inf -Inf
eg4.对列表或数据框建立表格,与tapply()的比较
>ind=list(c(1, 2, 2), c("A", "A", "B"))
>table(ind)
ind.2
ind.1 A B
1 1 0
2 1 1
用c("A", "A", "B"))分类c(1, 2, 2),则在"A"位置上有{1,2},而在"B"位置上只有{2}。建立双向表格,是二维逻辑值表格。
>tapply(1:3, ind) # 用列表ind分组向量1:3
[1] 1 2 4
> tapply(c(0,0,0),ind)
[1] 1 2 4
表明输出与数据向量没有元素的关系,因此是位置的记录。用ind的table()形式分组,则在table()的对应位置有元素,因此按列输出元素下标。
>tapply(1:3, ind, sum) #形式是table(),所以
A B
1 1 NA
2 2 3
> ind1=list(c(1,2,2),c(2,2,4)) #分组效果与ind相同
> tapply(c(1,1,1),ind1)
[1] 1 2 4
> ind1=list(c(1,2,2),c(2,2,4),c(4,4,5)) #三个元素的列表
> tapply(c(1,1,1),ind1)
[1] 1 2 8
在ind1的table()形式分组,输出元素的下标。
> table(ind1) #建立列表ind1的table()
, , ind1.3 = 4 #在4的位置分类
ind1.2
ind1.1 2 4
1 1 0
2 1 0
, , ind1.3 = 5
ind1.2
ind1.1 2 4
1 0 0
2 0 1
与4相同行列c(1,2),c(2,2),所以ind1.2的4对应位置为0。然后再分组ind1.2的2对应ind1.2的两个元素。在5的位置相同行列元素c(2),c(4),然后再分组,ind1.2的4的位置有ind1.2的2。c(1,2,3)分组后下标分别是c(1,2,8)。
eg5.对学生分组没有按照分数等级,而是其他方法
> class=c(1,2,3,2,1,2,1,3)
> class
[1] 1 2 3 2 1 2 1 3
> student=c(81,65,72,88,73,91,56,90)
>student
[1] 81 65 72 88 73 91 56 90
>class=factor(class)
> tapply(student,class,mean)
1 2 3
70.00000 81.33333 81.00000
> tapply(student,class)
[1] 1 2 3 2 1 2 1 3
> tapply(student,class,min)
1 2 3
56 65 72
> tapply(student,class,max)
1 2 3
81 91 90
> table(class)
class
1 2 3 #对class进行分组
3 3 2
> dar1=table(student,class) #class对student分组
> dar1
class
student 1 2 3
56 1 0 0
65 0 1 0
72 0 0 1
73 1 0 0
81 1 0 0
88 0 1 0
90 0 0 1
91 0 1 0
> class(dar1) #dar1的类型是table而不是矩阵
[1] "table"
> dim(dar1)
[1] 8 3
> str(dar1) #dar1有两个成员
'table' int [1:8, 1:3] 1 0 0 1 1 0 0 0 0 1 ...
- attr(*, "dimnames")=List of 2
..$ student: chr [1:8] "56" "65" "72" "73" ...
..$ class : chr [1:3] "1" "2" "3"
> typeof(dar1)
[1] "integer"
> mode(dar1)
[1] "numeric"
> dar1$student #dar1不能用$得到分量
Error in dar1$student : $ operator is invalid for atomic vectors
> dar1[1]
[1] 1
> dar1[2]
[1] 0
> dar1[1,] #访问第一行,与数据框相同
1 2 3
1 0 0
> dar1[,1] #访问第一列,与数据框相同
56 65 72 73 81 88 90 91
1 0 0 1 1 0 0 0
3.2.2 aggregate()
整合函数aggregate()用因子组合折叠(叠加)数据框,对数据框的分组数据应用函数f()。参数by用列表设置因子组合。把结果组合成表格返回。tapply()只能对一个变量的分组数据应用函数,因此返回向量。而函数by()对数据框的子集应用函数,而数据框的子集是一维的,实际上by()是tapply()对数据框的应用。
编程格式:
aggregate(data,by,f())
根据data的数据类型不同有三种用法,
1. data=data.frame是数据框
aggregate(data, by, FUN, ..., simplify = TRUE)
2.data=formula是公式
aggregate(formula, data, FUN, ..., subset, nana.action = na.omit)
3.data=ts是时间序列
aggregate(ts, nfrequency=1, FUN=sum, ndeltat =1, ts.eps=getOption("ts.eps"), ...)
eg6.1 数据集mtcars用cyl分组所有变量计算mean
>aggregate(mtcars,list(mtcars$cyl),mean)
Group.1 mpg cyl disp hp drat wt qsec
1 4 26.66364 4 105.1364 82.63636 4.070909 2.285727 19.13727
2 6 19.74286 6 183.3143 122.28571 3.585714 3.117143 17.97714
3 8 15.10000 8 353.1000 209.21429 3.229286 3.999214 16.77214
vs am gear carb
1 0.9090909 0.7272727 4.090909 1.545455
2 0.5714286 0.4285714 3.857143 3.428571
3 0.0000000 0.1428571 3.285714 3.500000
叠加Group.1表示汽缸数cyl,则拥有4个气缸的汽车每加仑汽油行驶公里数均值是26.66364.(空天,兰月亮,网络)
eg6.2 数据集mtcars用cyl和hp分组所有变量计算mean
>aggregate(mtcars,list(mtcars$cyl,mtcars$gear),mean)
Group.1 Group.2 mpg cyl disp hp drat wt qsec vs
1 4 3 21.500 4 120.1000 97.0000 3.700000 2.465000 20.0100 1.0
2 6 3 19.750 6 241.5000 107.5000 2.920000 3.337500 19.8300 1.0
3 8 3 15.050 8 357.6167 194.1667 3.120833 4.104083 17.1425 0.0
4 4 4 26.925 4 102.6250 76.0000 4.110000 2.378125 19.6125 1.0
5 6 4 19.750 6 163.8000 116.5000 3.910000 3.093750 17.6700 0.5
6 4 5 28.200 4 107.7000 102.0000 4.100000 1.826500 16.8000 0.5
7 6 5 19.700 6 145.0000 175.0000 3.620000 2.770000 15.5000 0.0
8 8 5 15.400 8 326.0000 299.5000 3.880000 3.370000 14.5500 0.0
am gear carb
1 0.00 3 1.000000
2 0.00 3 1.000000
3 0.00 3 3.083333
4 0.75 4 1.500000
5 0.50 4 4.000000
6 1.00 5 2.000000
7 1.00 5 6.000000
8 1.00 5 6.000000
在结果中,折叠group.1cyl和group.2 gear挡位数两组分类“因子”,产生8个数据框分组数据,例如汽车的汽缸数是4,挡位数是5,则每加仑汽油行驶公里数均值是28.200,是所有分组中的最大值,表明此车型性能最好。
若对数据框的变量子集应用分类因子分组,则可用formular公式或表达式的方式,~表示因子组合。
>aggregate(cbind(mtcars$mpg,mtcars$hp)~mtcars$cyl+mtcars$gear,FUN=mean)
#用cyl和gear因子组合分类变量mpg和hp组成的新数据框
mtcars$cyl mtcars$gear V1 V2
1 4 3 21.500 97.0000
2 6 3 19.750 107.5000
3 8 3 15.050 194.1667
4 4 4 26.925 76.0000
5 6 4 19.750 116.5000
6 4 5 28.200 102.0000
7 6 5 19.700 175.0000
8 8 5 15.400 299.5000
此命令的结果和下面的命令相同。
> aggregate(mtcars[c("mpg","hp")],list(mtcars$cyl,mtcars$gear),mean)
Group.1 Group.2 mpg hp
1 4 3 21.500 97.0000
2 6 3 19.750 107.5000
3 8 3 15.050 194.1667
4 4 4 26.925 76.0000
5 6 4 19.750 116.5000
6 4 5 28.200 102.0000
7 6 5 19.700 175.0000
8 8 5 15.400 299.5000