我的数据框有两列用作分组键,17列需要在每个组中求和,而一列应该是平均值 . 让我在一个不同的数据框架 diamonds
来自 ggplot2
来说明这一点 .
我知道我可以这样做:
ddply(diamonds, ~cut, summarise, x=sum(x), y=sum(y), z=sum(z), price=mean(price))
但是虽然对于3列是合理的,但对于其中的17列是不可接受的 .
在研究这个时,我找到了 colwise
函数,但我想出的最好的是:
cbind(ddply(diamonds, ~cut, colwise(sum, 7:9)), price=ddply(diamonds, ~cut, summarise, mean(price))[,2])
是否有可能进一步改善这一点?我想以更简单的方式做这件事,比如(虚构的命令):
ddply(diamonds, ~cut, colwise(sum, 7:9), price=mean(price))
要么:
ddply(diamonds, ~cut, colwise(sum, 7:9), colwise(mean, ~price))
总结一下:
-
我不想显式地键入所有17列,就像第一个示例使用
x
,y
和z
. -
理想情况下,我想通过单次调用
ddply
来实现,而不需要使用cbind
(或类似函数),如第二个示例所示 .
作为参考,我期望的结果是5行和5列:
cut x y z price
1 Fair 10057.50 9954.07 6412.26 4358.758
2 Good 28645.08 28703.75 17855.42 3928.864
3 Very Good 69359.09 69713.45 43009.52 3981.760
4 Premium 82385.88 81985.82 50297.49 4584.258
5 Ideal 118691.07 118963.24 73304.61 3457.542
7 回答
使用
dplyr
的Antoher解决方案 . 首先,在要聚合的每个变量上应用两个聚合函数 . 在结果变量中,您只选择所需的函数/变量组合 .我想为此建议
data.table
解决方案 . 您可以通过位置或名称轻松预定义要操作的列,然后重复使用相同的代码,无论您要操作多少列 .预定义列名称
运行代码
对于您的具体示例,这可以简化为
针对您的特定情况的另一种方法(在我看来更容易阅读)(
mean = sum/n
!)或更通用的,
只是投入另一个解决方案:
想法是函数
makeList
为ddply
创建一个参数列表 . 通过这种方式,您可以非常轻松地将术语添加到列表中(如function.name = column.indices
),ddply
将按预期工作:它使用
dplyr
,但我相信这将完全以合理易读的语法完成指定的目标:唯一的“技巧”是合并内部有一个管道表达式,它与总和的计算分开处理平均价格的计算 .
我根据@David Arenburg(使用
data.table
)和@thothal(使用plyr
,问题请求)提供的解决方案对此解决方案进行了基准测试,重复5000次 . 这里data.table
比plyr
和dplyr
慢了 .dplyr
比plyr
快 . 可以想象,基准测试结果可能会根据列数,分组因子中的级别数以及应用的特定函数而发生变化 . 例如,MarkusN在我完成初始基准测试后提交了一个答案,该测试基本上比先前提交的样本数据答案快得多 . 他通过计算许多不需要的汇总统计数据来完成这一点,然后将它们扔掉......当然,必须有一个点,在这个点上,这种方法的成本超过了优势 .当然速度不是唯一的考虑因素 . 特别是,dplyr和plyr对它们的加载顺序(dplyr之前的plyr)很挑剔,并且有几个相互掩盖的函数 .
不是100%你正在寻找什么,但它可能会给你另一个想法如何做到这一点 . 使用
data.table
你可以这样做:要缩短代码(你尝试用colwise做什么),你可能必须编写一些函数来实现你想要的 .
为了完整起见,这里有一个基于
dplyr
的解决方案和Veerendra Gadekar in another question和here by MarkusN发布的答案 .在这种特殊情况下,可以首先将
sum
应用于某些列,然后mean
应用于所有感兴趣的列:这是可能的,因为
mean
不会更改列8:10
的计算总和,并将计算所需的平均价格 . 但是如果我们想要计算价格的标准差而不是平均值,那么这种方法就不会起作用,因为列8:10
都会为0 .更通用的方法可能是:
人们可能不会对之前命名的重复列规范感到满意,但这似乎是一个优雅的解决方案 .
它具有优于MarkusN的优势解决方案,它不需要匹配新创建的列,也不会更改其名称 .
Veerendra Gadekar的解决方案应以
select(cut, 8:10, price) %>% arrange(cut)
结束,以产生预期结果(列的子集,以及按分组键排序的行) . Hong Ooi的建议类似于第一个,但假设没有其他专栏 .最后,它似乎比
data.table
解决方案更容易理解和易于理解,例如the one proposed by David Arenburg .