前言:R中提供了许多用来整合(aggregate)和重塑(reshape)数据的强大方法。在整合数据时,
往往将多组观测替换为根据这些观测计算的描述性统计量。在重塑数据时,则会通过修改数据的
结构(行和列)来决定数据的组织方式。本篇文章描述了用来完成这些任务的多种方式。
在R中使用一个或多个by变量和一个预先定义好的函数来折叠(collapse)数据是比较容易的。
调用格式为:
aggregate(x, by, FUN)
其中x
是待折叠的数据对象,by
是一个变量名组成的列表,这些变量将被去掉以形成新的观测,
而FUN
则是用来计算描述性统计量的标量函数,它将被用来计算新观测中的值。
options(digits=3) # 设置参数,保留3位有效数字
attach(mtcars) # mtcars是自带的一个数据集
aggdata <- aggregate(mtcars, by=list(cyl,gear),FUN=mean,na.rm=TRUE)
aggdata
> aggdata
Group.1 Group.2 mpg cyl disp hp drat wt qsec vs am gear
1 4 3 21.5 4 120 97 3.70 2.46 20.0 1.0 0.00 3
2 6 3 19.8 6 242 108 2.92 3.34 19.8 1.0 0.00 3
3 8 3 15.1 8 358 194 3.12 4.10 17.1 0.0 0.00 3
4 4 4 26.9 4 103 76 4.11 2.38 19.6 1.0 0.75 4
5 6 4 19.8 6 164 116 3.91 3.09 17.7 0.5 0.50 4
6 4 5 28.2 4 108 102 4.10 1.83 16.8 0.5 1.00 5
7 6 5 19.7 6 145 175 3.62 2.77 15.5 0.0 1.00 5
8 8 5 15.4 8 326 300 3.88 3.37 14.6 0.0 1.00 5
carb
1 1.00
2 1.00
3 3.08
4 1.50
5 4.00
6 2.00
7 6.00
8 6.00
在结果中,Group.1表示汽缸数量(4、6或8),Group.2代表挡位数(3、4或5)。举例来说,
拥有4个汽缸和3个挡位车型的每加仑汽油行驶英里数(mpg)均值为21.5。
by
后面指出的变量,而值为除了by
后变量外的所有变量。你可以在列表中为各组声明自定义的名称, 例如by=list(Group.cyl=cyl, Group. gears=gear)
。指定的函数可为任意的内建或自编函数,这就为整合命令赋予了强大的力量。但说到力量,没有什么可以比reshape2
包更强。
reshape2包是一套重构和整合数据集的绝妙的万能工具。由于它的这种万能特性,可能学
起来会有一点难度。我们将慢慢地梳理整个过程,并使用一个小型数据集作为示例,这样每一步发生了什么就很清晰了。由于reshape2包并未包含在R的标准安装中,在第一次使用它之前需要使用install.packages("reshape2")
进行安装。
大致说来,你需要首先将数据融合(melt),以使每一行都是唯一的标识符~变量组合。然后将数据重铸(cast)为你想要的任何形状。在重铸过程中,你可以使用任何函数对数据进行整合。将使用的数据集如下标所示。
(ID, Time) | X1 | X2 |
---|---|---|
(1, 1) | 5 | 6 |
(1, 2) | 3 | 5 |
(2, 1) | 6 | 1 |
(2, 2) | 2 | 4 |
注:标识符变量
(ID,Time,X1)
或(ID,Time,X2)
相当于((ID,Time),X1)
或((ID,Time),X2)
,也就是说,以(ID,Time)
为横坐标,X1
或者X2
为纵坐标。
在这个数据集中,测量(measurement)是指最后两列中的值(5、6、3、5、6、1、2、4)。每个测量都能够被标识符变量(在本例中,标识符是指ID、Time以及观测属于X1还是X2)唯一地确定。举例来说,在知道ID为1、Time为1,以及属于变量X1之后,即可确定测量值为第一行中的5。
library(reshape2)
ID <- c(1, 1, 2, 2)
Time <- c(1, 2, 1, 2)
X1 <- c(5, 3, 6, 2)
X2 <- c(6, 5, 1, 4)
mydata <- data.frame(ID, Time, X1, X2)
数据集的融合是将它重构为这样一种格式:每个测量变量独占一行,行中带有要唯一确定这个测量所需的标识符变量。要融合表5-8中的数据,可使用以下代码:
md <- melt(mydata, id=c("ID", "Time"))
md
> md
ID Time variable value
1 1 1 X1 5
2 1 2 X1 3
3 2 1 X1 6
4 2 2 X1 2
5 1 1 X2 6
6 1 2 X2 5
7 2 1 X2 1
8 2 2 X2 4
注意,必须指定要唯一确定每个测量所需的变量(ID和Time),而表示测量变量名的变量(X1或X2)将由程序为你自动创建。
既然已经拥有了融合后的数据,现在就可以使用dcast()函数将它重铸为任意形状了。
dcast()函数读取已融合的数据,并使用你提供的公式和一个(可选的)用于整合数据的函数将其重塑。调用格式为:
newdata <- dcast(md, formula, fun.aggregate)
其中的md为已融合的数据,formula描述了想要的最后结果,而fun.aggregate是(可选的)数据整合函数。其接受的公式形如:
rowvar1 + rowvar2 + … ~ colvar1 + colvar2 + …
在这一公式中,rowvar1 + rowvar2 + …定义了要划掉的变量集合,以确定各行的内容,而colvar1 + colvar2 + …则定义了要划掉的、确定各列内容的变量集合。参见下图中的示例。
我们以上图中(a)对应的表格为例,ID~variable
可以理解为以ID
的所有情况为横坐标,variable
的所有类别(X1,X2)为列坐标。因为列坐标和横坐标相同的数可能有多个,我们采用fun.aggregate指定的函数整合它们,比如对于坐标为(ID,X2)
的数由两个,分别为6和5,取平均为5.5,与(a)中的数一致。
再以(e)为例,ID+variable
中的ID有两种取值,variable有两种情况,组合起来就是4种组合,故有4种横坐标;Time
有两种取值,故有2种纵坐标
例(a、b和c)中指定了mean作为整合函数,从而就对数据同时进行了重塑与整合。例如,示例(a)中给出了每个观测所有时刻中在X1和X2上的均值;示例(b)则给出了X1和X2在时刻1和时刻2的均值,对不同的观测进行了平均;在©中则是每个观测在时刻1和时刻2的均值,对不同的X1和X2进行了平均。
总的来说,融合(melt)相当于将一个大的整体化为一个个小个体,类似于化为一个个不同的基本粒子,然后再用重铸(dcast)的方法将粒子按formula指定的格式合并成一个大的个体。