我经常遇到的一般问题:我想对 data.frame 执行一些操作,每个因子级别都会产生一个数字,为此它使用来自多个列的信息。如何在 R 中编写它?
我考虑了这些功能:
- tapply - 不在多列上操作
- 聚合 - 函数分别给出列
- ave - 结果与输入的行数相同,而不是因子级别数
- by - 这是最热门的候选人,但我讨厌返回的格式 - 列表。我想要
data.frame
结果,我知道我可以转换它,但它很难看,我更喜欢另一种解决方案!
基本 R 解决方案是使用lapply
和的组合split
:
> data.frame(lapply(split(iris[,1:4], iris[,5]), colMeans))
setosa versicolor virginica
Sepal.Length 5.006 5.936 6.588
Sepal.Width 3.428 2.770 2.974
Petal.Length 1.462 4.260 5.552
Petal.Width 0.246 1.326 2.026
...或者您可以将其包装起来do.call(rbind, ...)
以稍微不同的形式获得输出:
> data.frame(do.call(rbind,lapply(split(iris[,1:4], iris[,5]), colMeans)))
Sepal.Length Sepal.Width Petal.Length Petal.Width
setosa 5.006 3.428 1.462 0.246
versicolor 5.936 2.770 4.260 1.326
virginica 6.588 2.974 5.552 2.026
...或者sapply
如果您的数据可以存储在矩阵中,请使用:
> sapply(split(iris[,1:4], iris[,5]), colMeans)
setosa versicolor virginica
Sepal.Length 5.006 5.936 6.588
Sepal.Width 3.428 2.770 2.974
Petal.Length 1.462 4.260 5.552
Petal.Width 0.246 1.326 2.026
OP 要求一个一般性的答案,所以我认为“plyr”包是最合适的。'plyr' 包在处理大型数据集时有局限性,但对于日常使用(在原始帖子中暗示),'plyr' 函数对于任何 R 用户来说都是极好的资产。
设置:这是一个供我们使用的快速数据示例。
data <- data.frame(id=1:50, group=sample(letters[1:3], 50, rep=TRUE), x_Value=sample(1:500, 50), y_Value=sample(2:5, 50, rep=TRUE)*100)
如何使用 plyr:我将在这里以基本用途为例,让事情开始。首先,加载包。
library(plyr)
现在,让我们开始计算。使用“plyr”函数,您可以根据输入和输出选择函数的前两个字母。在这个例子中,我将输入一个数据帧 (d) 并输出一个数据帧 (d),所以我将使用“ddply”函数。
'ddply' 函数使用以下语法:
ddply(
data_source,
.(grouping_variables),
function,
column_definitions)
首先,让我们快速找出有多少条目属于组 a、b 和 c:
ddply(
data,
.(group),
summarize,
N=length(id))
# group N
# 1 a 17
# 2 b 16
# 3 c 17
在这里,我们首先指定了数据源,然后指定了我们想要通过“组”变量对行进行分组。我们使用“summarize”函数来删除除 grouping_variables 和 column_definitions 中的列之外的所有列。使用“长度”功能基本上只是为此目的的一个计数。
现在,让我们在数据中添加一列,显示 x 和 y 值的组均值。
ddply(
data,
.(group),
mutate,
group_mean_x=mean(x_Value),
group_mean_y=mean(y_Value))
# id group x_Value y_Value group_mean_x group_mean_y
# 1 8 a 301 300 218.7059 394.1176
# 2 13 a 38 500 218.7059 394.1176
# 3 14 a 425 300 218.7059 394.1176
# .....................................................
# 17 47 a 191 300 218.7059 394.1176
# 18 5 b 411 500 235.1875 325.0000
# 19 6 b 121 400 235.1875 325.0000
# 20 11 b 151 200 235.1875 325.0000
# .....................................................
# 33 49 b 354 200 235.1875 325.0000
# 34 1 c 482 400 246.1765 400.0000
# 35 2 c 43 300 246.1765 400.0000
# .....................................................
# 50 50 c 248 500 246.1765 400.0000
我已经截断了结果以使其更短。在这里,我们使用了相同的数据源和分组变量,但是“mutate”函数在添加列的同时保留了数据源中的所有数据。
现在,让我们对之前的数据进行两步操作。让我们在汇总表中显示 x 和 y 平均值之间的平均值和差异。
ddply(
data,
.(group),
summarize,
group_mean_x=mean(x_Value),
group_mean_y=mean(y_Value),
difference=group_mean_x - group_mean_y)
# group group_mean_x group_mean_y difference
# 1 a 218.7059 394.1176 -175.4118
# 2 b 235.1875 325.0000 -89.8125
# 3 c 246.1765 400.0000 -153.8235
我向您展示这个示例,因为发生了一些重要的事情......我们正在使用我们刚刚定义为不同列定义的一部分的列。这在创建汇总表时非常非常有用。
最后,让我们按两个因素进行分组:组和 x 值的 10^2 位中的数字。让我们创建一个汇总表,显示每个组的平均 x 和 y 值以及 10^2 位的 x 值。
ddply(
data,
.(group, x_100=as.integer(x_Value/100)),
summarize,
mean_x=mean(x_Value),
mean_y=mean(y_Value))
# group x_100 mean_x mean_y
# 1 a 0 20.0000 425.0000
# 2 a 1 145.6667 333.3333
# 3 a 2 272.0000 400.0000
# 4 a 3 328.6667 433.3333
# 5 a 4 427.5000 350.0000
# 6 b 0 37.0000 200.0000
# 7 b 1 148.6667 383.3333
# 8 b 2 230.0000 325.0000
# 9 b 3 363.0000 200.0000
# 10 b 4 412.5000 400.0000
# 11 c 0 55.6000 360.0000
# 12 c 1 173.5000 350.0000
# 13 c 2 262.5000 450.0000
# 14 c 3 355.6667 400.0000
# 15 c 4 481.0000 433.3333
这个例子很重要,因为它向我们展示了两件事:我们可以使用向量化语句创建分组列,并且我们可以通过用逗号分隔列列表来按多个列进行分组。
这组快速示例应该足以开始使用“plyr”包。更多细节可以在 中找到help(plyr)
。
在 SO 上搜索会产生很多答案,这里有一个简单的例子。
library(data.table)
dt = data.table(a = c(1:6), b = c(1,1,1,2,2,2), c = c(1,2,1,2,1,2))
dt
# a b c
#1: 1 1 1
#2: 2 1 2
#3: 3 1 1
#4: 4 2 2
#5: 5 2 1
#6: 6 2 2
dt[, sum(a), by = list(b, c)]
# b c V1
#1: 1 1 4
#2: 1 2 2
#3: 2 2 10
#4: 2 1 5
即使在这个简单的例子中,我们也可以看到优于plyr
's的优势ddply
——更简单(更人性化和更短)的语法、保留分组顺序,当然还有更快的速度。(供参考的plyr
版本是ddply(dt, .(b, c), summarize, sum(a))
)
plyr 包中的 ddply 按一个或多个因子拆分 data.frame,为每个拆分执行一个函数并返回一个 data.frame 作为结果。你可能想看看那里。