根据特定因素组合对行进行求和

11

这可能是一个愚蠢的问题,但我已经阅读了Crawley关于数据帧的章节,并在互联网上搜索了很多,但仍然无法使任何东西工作。

这里有一个类似于我的示例数据集:

> data<-data.frame(site=c("A","A","A","A","B","B"), plant=c("buttercup","buttercup",
"buttercup","rose","buttercup","rose"), treatment=c(1,1,2,1,1,1), 
plant_numb=c(1,1,2,1,1,2), fruits=c(1,2,1,4,3,2),seeds=c(45,67,32,43,13,25))
> data
  site     plant treatment plant_numb fruits seeds
1    A buttercup         1          1      1    45
2    A buttercup         1          1      2    67
3    A buttercup         2          2      1    32
4    A      rose         1          1      4    43
5    B buttercup         1          1      3    13
6    B      rose         1          2      2    25  
我想要做的是创建一个情境,其中只有当唯一的 site、plant、treatment 和 plant_numb 组合存在时,“seeds”和“fruits”才会被加起来。理想情况下,这将导致行数减少,但原始列(即我需要上面的示例看起来像这样)得到保留。
  site     plant treatment plant_numb fruits seeds
1    A buttercup         1          1      3   112
2    A buttercup         2          2      1    32
3    A      rose         1          1      4    43
4    B buttercup         1          1      3    13
5    B      rose         1          2      2    25

这个例子相当基础(我的数据集大约有5000行),虽然你只看到需要求和的两行数据,但需要求和的行数会不同,范围从1到大约45。

我已经尝试过使用rowsum()和tapply()函数,但结果非常糟糕(错误提示告诉我这些函数对因子无效),所以如果您能指导一下正确的方向,我将不胜感激!

非常感谢!


看看 plyrdata.table 标签。很多问题基本上都涉及到这个。祝你好运! - Chase
请参见 http://4dpiecharts.com/2011/12/16/a-quick-primer-on-split-apply-combine-problems/。 - Richie Cotton
3个回答

11
希望以下代码相当易于理解。它使用基础函数“aggregate”,基本上是在为每个唯一的站点、植物、处理和植物数量组合查看水果总数和种子总数。
# Load your data
data <- data.frame(site=c("A","A","A","A","B","B"), plant=c("buttercup","buttercup",
"buttercup","rose","buttercup","rose"), treatment=c(1,1,2,1,1,1), 
plant_numb=c(1,1,2,1,1,2), fruits=c(1,2,1,4,3,2),seeds=c(45,67,32,43,13,25)) 

# Summarize your data
aggregate(cbind(fruits, seeds) ~ 
      site + plant + treatment + plant_numb, 
      sum, 
      data = data)
#  site     plant treatment plant_numb fruits seeds
#1    A buttercup         1          1      3   112
#2    B buttercup         1          1      3    13
#3    A      rose         1          1      4    43
#4    B      rose         1          2      2    25
#5    A buttercup         2          2      1    32

行的顺序会改变(并且按网站、工厂…排序),但希望这不会太过于关注。

另一种方法是使用plyr包中的ddply。

library(plyr)
ddply(data, .(site, plant, treatment, plant_numb), 
      summarize, 
      fruits = sum(fruits), 
      seeds = sum(seeds))
#  site     plant treatment plant_numb fruits seeds
#1    A buttercup         1          1      3   112
#2    A buttercup         2          2      1    32
#3    A      rose         1          1      4    43
#4    B buttercup         1          1      3    13
#5    B      rose         1          2      2    25

太棒了 - 我刚问完问题就开始尝试使用聚合函数,但是你的帮助让我进展神速。感谢你的帮助。不过还有一个问题:当我按照你所示输入代码时,出现了错误“Error in as.data.frame.default(x) : cannot coerce class "formula" into a data.frame”。有什么办法可以解决吗? - user1371443
很不幸,两者都是一样的错误信息。我在示例和实际数据集(无空格)中都得到了相同的错误消息:> aggregate(cbind(fruits, seeds) ~ site + plant + treatment + plant_numb, sum, data = data) Error in as.data.frame.default(x) : cannot coerce class "formula" into a data.frame - user1371443
plyr解决方案应该仍能正常工作,我猜测。但是听起来你没有公式版本的aggregate。你使用的R版本是哪个?我认为自2.11版本以来,aggregate已经允许公式输入。 - Dason

4

为了完整起见,这里是使用data.table解决方案,由@Chase提出。对于较大的数据集,这可能是最快的方法:

library(data.table)
data.dt <- data.table(data)
setkey(data.dt, site)
data.dt[, lapply(.SD, sum), by = list(site, plant, treatment, plant_numb)]

     site     plant treatment plant_numb fruits seeds
[1,]    A buttercup         1          1      3   112
[2,]    A buttercup         2          2      1    32
[3,]    A      rose         1          1      4    43
[4,]    B buttercup         1          1      3    13
[5,]    B      rose         1          2      2    25
< p > lapply(.SD, sum) 部分对不在分组集中的所有列求和(即不在 by函数中的列)。


0

仅为更新此答案,较长时间后,dplyr/tidyverse 的解决方案如下:

library(tidyverse)

data %>% 
  group_by(site, plant, treatment, plant_numb) %>% 
  summarise(fruits=sum(fruits), seeds=sum(seeds))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接