Суммирование строк на основе конкретных комбинаций факторов

Это, наверное, глупый вопрос, но я прочитал главу Crawley о dataframes и просмотрел Интернет и еще не смог заставить что-либо работать.

Вот примерный набор данных, похожий на мой:

> 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  

Я бы хотел создать сценарий, где "семена" и "фрукты" суммируются всякий раз, когда существуют уникальные комбинации сайтов и растений, а также комбинации 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

Этот пример довольно простой (мой набор данных составляет ~ 5000 строк), и хотя здесь вы видите только две строки, которые должны быть суммированы, количество строк, которые нужно суммировать, варьируется и варьируется от 1 до ~ 45.

Я пробовал rowsum() и tapply() с довольно мрачными результатами до сих пор (ошибки говорят мне, что эти функции не имеют смысла для факторов), поэтому, если бы вы могли даже указать мне в правильном направлении, я бы очень ценю это!

Большое спасибо!

Ответ 1

Надеюсь, что следующий код достаточно понятен. Он использует базовую функцию "aggregate", и в основном это говорит для каждой уникальной комбинации сайта, растения, обработки и plant_num смотреть на сумму фруктов и сумму семян.

# 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

Порядок строк изменяется (и сортируется по сайту, растению,...), но, надеюсь, это не слишком беспокоит.

Альтернативный способ сделать это - использовать ddply из пакета plyr.

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

Ответ 2

И для полноты, вот решение 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

Часть lapply(.SD, sum) суммирует все ваши столбцы, которые не являются частью набора группировок (то есть столбцы не в функции by)

Ответ 3

Просто, чтобы обновить этот ответ спустя долгое время, решение dplyr/tidyverse будет

library(tidyverse)

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