汇总、透视、提炼、凝炼,对数据处理来说这些词的意思都差不多,R语言提供了很多函数处理这些事情,还有一些软件包也提供了非常方便的数据汇总功能,方法
不胜枚举。summary是获取数据概要最常用的函数,应该很熟悉了。这里只简单介绍rowSums, colSums, rowMeans,
colMeans, table、apply、lapply、sapply、vapply、tapply、mapply、by 和
aggregate 等函数的用法。
一、行列求和、平均值和频度
rowSums, colSums, rowMeans, colMeans
可以简单理解为按行或列求和或求均值,table把数字或字符当成因子统计频度,都相当简单:
> a
> a
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 1 2 3
[3,] 1 2 3
> rowSums(a)
[1] 6 6 6
> colSums(a)
[1] 3 6 9
> table(a)
a
1 2 3
3 3 3
对于多维数组,rowSums, colSums, rowMeans, colMeans的使用稍为复杂点。它们的参数为:
colSums (x, na.rm = FALSE, dims = 1)
rowSums (x, na.rm = FALSE, dims = 1)
colMeans(x, na.rm = FALSE, dims = 1)
rowMeans(x, na.rm = FALSE, dims = 1)
其中dims为整数,表示哪个或哪些维数被看做行或列,对于row统计函数,dims+1及以后的维度被看做行,对于col函数,dims及以前的维度(1:dims)被看做列:
> b
> b
, , 1
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 1
[3,] 1 1 1
, , 2
[,1] [,2] [,3]
[1,] 2 2 2
[2,] 2 2 2
[3,] 2 2 2
, , 3
[,1] [,2] [,3]
[1,] 3 3 3
[2,] 3 3 3
[3,] 3 3 3
> rowSums(b)
[1] 18 18 18
> rowSums(b,dims=1)
[1] 18 18 18
> rowSums(b,dims=2)
[,1] [,2] [,3]
[1,] 6 6 6
[2,] 6 6 6
[3,] 6 6 6
> colSums(b)
[,1] [,2] [,3]
[1,] 3 6 9
[2,] 3 6 9
[3,] 3 6 9
> colSums(b,dims=2)
[1] 9 18 27
table可以统计数字出现的频率,也可以统计其他可以被看做因子的数据类型:
>
table(b)
b
1 2 3
9 9 9
> c
sample(letters[1:5],
10,
replace=TRUE)
> c
[1]
"a" "c" "b" "d"
"a" "e" "d" "e"
"c" "a"
>
table(c)
c
a b c d e
3 1 2 2
2
如果参数不只一个,它们的长度应该一样,结果是不同因子组合的频度表:
> a
rep(letters[1:3],
each=4)
> b
sample(LETTERS[1:3],12,replace=T)
>
table(a,b)
b
a A B C
a 0 3 1
b 3 0 1
c 1 1 2
二、apply系列函数:
如果我们关心的不仅仅是求和、平均值和频度这些指标的计算,可以用apply系列函数来处理,这些函数包括apply、lapply、sapply、vapply、tapply和mapply。这些函数的使用可以从目标数据类型和返回值类型两个方面进行了解。
1、apply函数:
这个函数的使用格式为:apply(X, MARGIN, FUN, ...)。它应用的数据类型是数组或矩阵,返回值类型由FUN函数结果的长度确定。
X参数为数组或矩阵;MARGIN为要应用计算函数的边/维,MARGIN=1为第一维(行),2为第二维(列),...;FUN为要应用的计算函数,后面可以加FUN的有名参数。比如,要按行或列计算数组a的标准差就可以这样:
>
apply(a,
MARGIN=1,
FUN=sd)
[1] 1
1 1
>
apply(a,
MARGIN=2,
FUN=sd)
[1] 0
0 0
MARGIN的长度可以不是1(多维应用),如果长度等于X的维数,应用到FUN函数的数据就只有一个值,结果没什么意义,甚至函数会获得无效值:
>
apply(b,
MARGIN=3,
FUN=sum)
[1] 9 18 27
>
apply(b,
MARGIN=1:2,
FUN=sum)
[,1]
[,2]
[,3]
[1,] 6 6 6
[2,] 6 6 6
[3,] 6 6 6
>
apply(a,
MARGIN=1:2,
FUN=sd)
[,1]
[,2]
[,3]
[1,] NA NA NA
[2,] NA NA NA
[3,] NA NA NA
上面我们使用的sd、sum或mean函数的返回值的向量长度都是1(每一次单独计算),apply函数结果的维数与MARGIN的向量长度相同;如果FUN函数返回值的长度不是1而是每次都为n,apply函数的结果是维度为c(n,
dim(X)[MARGIN]):
> a
[,1]
[,2]
[,3]
[1,] 1 2 3
[2,] 1 2 3
[3,] 1 2 3
>
apply(a,
MARGIN=1,
FUN=quantile,
probs=seq(0,1,
0.25))
[,1]
[,2]
[,3]
0% 1.0 1.0 1.0
25% 1.5 1.5 1.5
50% 2.0 2.0 2.0
75% 2.5 2.5 2.5
100% 3.0 3.0 3.0
>
apply(a,
MARGIN=2,
FUN=quantile,
probs=seq(0,1,
0.25))
[,1]
[,2]
[,3]
0% 1 2 3
25% 1 2 3
50% 1 2 3
75% 1 2 3
100% 1 2 3
如果FUN函数返回值的长度不一样,情况就复杂了,apply函数的结果会是列表。
2、lapply、sapply和vapply函数:
这几个函数是一套,前两个参数都为X和FUN,其他参数在R的函数帮助文档里有相信介绍。它们应用的数据类型都是列表,对每一个列表元素应用FUN函数,但返回值类型不大一样。lappy是最基本的原型函数,sapply和vapply都是lapply的改进版。
2.1 lapply返回的结果为列表,长度与X相同
> scores
list(YuWen=c(80,88,94,70),
ShuXue=c(99,87,100,68,77))
>
lapply(scores,
mean)
$YuWen
[1] 83
$ShuXue
[1] 86.2
>
lapply(scores,
quantile,
probs=c(0.5,0.7,0.9))
$YuWen
50% 70% 90%
84.0 88.6 92.2
$ShuXue
50% 70% 90%
87.0 96.6 99.6
2.2 sapply返回的结果比较“友好”,如果结果很整齐,就会得到向量或矩阵或数组
sapply是simplify了的lapply,所谓的simplify,是指对结果的数据结构进行了simplify,方便后续处理。
>
sapply(scores,
mean)
YuWen
ShuXue
83.0 86.2
>
sapply(scores,
quantile,
probs=c(0.5,0.7,0.9))
YuWen ShuXue
50% 84.0 87.0
70% 88.6 96.6
90% 92.2 99.6
2.3 vapply函数:对返回结果(value)进行类型检查的sapply
虽
然sapply的返回值比lapply好多了,但可预测性还是不好,如果是大规模的数据处理,后续的类型判断工作会很麻烦而且很费时。vapply增加的
FUN.VALUE参数可以直接对返回值类型进行检查,这样的好处是不仅运算速度快,而且程序运算更安全(因为结果可控)。下面代码的rt.value变
量设置返回值长度和类型,如果FUN函数获得的结果和rt.value设置的不一致(长度和类型)都会出错:
> probs
c(1:3/4)
> rt.value
c(0,0,0)
#设置返回值为3个数字
>
vapply(scores,
quantile,
FUN.VALUE=rt.value,
probs=probs)
YuWen ShuXue
25% 77.5
77
50% 84.0
87
75% 89.5
99
> probs
c(1:4/4)
>
vapply(scores,
quantile,
FUN.VALUE=rt.value,
probs=probs)
错误于vapply(scores,
quantile,
FUN.VALUE =
rt.value,
probs = probs)
:
值的长度必需为3,
但FUN(X[[1]])结果的长度却是4
> rt.value
c(0,0,0,0)
#返回值类型为4个数字
>
vapply(scores,
quantile,
FUN.VALUE=rt.value,
probs=probs)
YuWen ShuXue
25% 77.5
77
50% 84.0
87
75% 89.5
99
100% 94.0
100
> rt.value
c(0,0,0,'')
#设置返回值为3个数字和1个字符串
>
vapply(scores,
quantile,
FUN.VALUE=rt.value,
probs=probs)
错误于vapply(scores,
quantile,
FUN.VALUE =
rt.value,
probs = probs)
:
值的种类必需是'character',
但FUN(X[[1]])结果的种类却是'double'
FUN.VALUE为必需参数。
3、 mapply函数:
R的在线文档说mapply是sapply的多变量版本(multivariate
sapply),但它的参数顺序和sapply却不一样:
mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES =
TRUE)
mapply应用的数据类型为向量或列表,FUN函数对每个数据元素应用FUN函数;如果参数长度为1,得到的结果和sapply是一样的;但如果参数长度不是1,FUN函数将按向量顺序和循环规则(短向量重复)逐个取参数应用到对应数据元素:
>
sapply(X=1:4,
FUN=rep,
times=4)
[,1]
[,2]
[,3]
[,4]
[1,] 1
2 3 4
[2,] 1
2 3 4
[3,] 1
2 3 4
[4,] 1
2 3 4
>
mapply(rep,
x =
1:4,
times=4)
[,1]
[,2]
[,3]
[,4]
[1,] 1
2 3 4
[2,] 1
2 3 4
[3,] 1
2 3 4
[4,] 1
2 3 4
>
mapply(rep,
x =
1:4,
times=1:4)
[[1]]
[1] 1
[[2]]
[1] 2
2
[[3]]
[1] 3
3 3
[[4]]
[1] 4
4 4 4
>
mapply(rep,
x =
1:4,
times=1:2)
[[1]]
[1] 1
[[2]]
[1] 2
2
[[3]]
[1] 3
[[4]]
[1] 4
4
4、tapply 和 by
函数:
tapply函数可以看做是table函数的扩展:table函数按因子组合计算频度,而tapply可以按因子组合应用各种函数。使用格式为:tapply(X,
INDEX, FUN = NULL, ..., simplify = TRUE)
X为要应用函数的数据,通常为向量;INDEX为因子,和table函数一样,它的长度必需和X相同。
> (x
1:10)
[1] 1
2 3 4 5
6 7 8 9
10
> (f
gl(2,5,
labels=c("CK",
"T")))
[1] CK CK CK CK CK T T
T T T
Levels: CK T
>
tapply(x,
f, length)
#FUN函数是length,得到的结果和table类似
CK T
5 5
>
table(f)
f
CK T
5 5
>
tapply(x,
f, sum)
CK T
15 40
by函数是tapply函数针对数据框类型数据的应用,但结果不怎么友好,你可以用下面语句看看情况:
with(mtcars,
by(mtcars,
cyl,
summary))
三、aggregate函数
这个函数的功能比较强大,它首先将数据进行分组(按行),然后对每一组数据进行函数统计,最后把结果组合成一个比较nice的表格返回。根据数据对象不同它有三种用法,分别应用于数据框(data.frame)、公式(formula)和时间序列(ts):
aggregate(x, by, FUN, ..., simplify = TRUE)
aggregate(formula, data, FUN, ..., subset, na.action =
na.omit)
aggregate(x, nfrequency = 1, FUN = sum, ndeltat = 1, ts.eps =
getOption("ts.eps"), ...)
我们通过 mtcars 数据集的操作对这个函数进行简单了解。mtcars 是不同类型汽车道路测试的数据框类型数据:
>
str(mtcars)
'data.frame': 32 obs.
of 11
variables:
$ mpg :
num 21 21
22.8 21.4 18.7
18.1 14.3 24.4
22.8 19.2 ...
$ cyl :
num 6 6
4 6 8 6
8 4 4 6
...
$ disp:
num 160
160 108 258 360
...
$ hp : num 110
110 93 110 175
105 245 62 95
123 ...
$ drat:
num 3.9
3.9 3.85 3.08
3.15 2.76 3.21
3.69 3.92 3.92
...
$ wt : num 2.62
2.88 2.32 3.21
3.44 ...
$ qsec:
num 16.5
17 18.6 19.4 17
...
$ vs : num 0
0 1 1 0
1 0 1 1
1 ...
$ am : num 1
1 1 0 0
0 0 0 0
0 ...
$ gear:
num 4 4
4 3 3 3
3 4 4 4
...
$ carb:
num 4 4
1 1 2 1
4 2 2 4
...
先用attach函数把mtcars的列变量名称加入到变量搜索范围内,然后使用aggregate函数按cyl(汽缸数)进行分类计算平均值:
> attach(mtcars)
> aggregate(mtcars, by=list(cyl), FUN=mean)
Group.1 mpg cyl disp hp drat wt qsec vs am gear carb
1 4 26.66364 4 105.1364 82.63636 4.070909 2.285727 19.13727 0.9090909 0.7272727 4.090909 1.545455
2 6 19.74286 6 183.3143 122.28571 3.585714 3.117143 17.97714 0.5714286 0.4285714 3.857143 3.428571
3 8 15.10000 8 353.1000 209.21429 3.229286 3.999214 16.77214 0.0000000 0.1428571 3.285714 3.500000
by参数也可以包含多个类型的因子,得到的就是每个不同因子组合的统计结果:
> aggregate(mtcars, by=list(cyl, gear), FUN=mean)
Group.1 Group.2 mpg cyl disp hp drat wt qsec vs am gear carb
1 4 3 21.500 4 120.1000 97.0000 3.700000 2.465000 20.0100 1.0 0.00 3 1.000000
2 6 3 19.750 6 241.5000 107.5000 2.920000 3.337500 19.8300 1.0 0.00 3 1.000000
3 8 3 15.050 8 357.6167 194.1667 3.120833 4.104083 17.1425 0.0 0.00 3 3.083333
4 4 4 26.925 4 102.6250 76.0000 4.110000 2.378125 19.6125 1.0 0.75 4 1.500000
5 6 4 19.750 6 163.8000 116.5000 3.910000 3.093750 17.6700 0.5 0.50 4 4.000000
6 4 5 28.200 4 107.7000 102.0000 4.100000 1.826500 16.8000 0.5 1.00 5 2.000000
7 6 5 19.700 6 145.0000 175.0000 3.620000 2.770000 15.5000 0.0 1.00 5 6.000000
8 8 5 15.400 8 326.0000 299.5000 3.880000 3.370000 14.5500 0.0 1.00 5 6.000000
公式(formula)是一种特殊的R数据对象,在aggregate函数中使用公式参数可以对数据框的部分指标进行统计:
> aggregate(cbind(mpg,hp) ~ cyl+gear, FUN=mean)
cyl gear 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
上面的公式 cbind(mpg,hp) ~ cyl+gear 表示使用 cyl 和 gear 的因子组合对
cbind(mpg,hp) 数据进行操作。
aggregate在时间序列数据上的应用请参考R的函数说明文档。