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

Вероятно, это глупый вопрос, но я прочитал главу Кроули о фреймах данных и прошерстил Интернет, но пока ничего не смог заставить работать.

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

> 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 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() с довольно мрачными результатами (ошибки говорят мне, что эти функции не имеют значения для факторов), поэтому, если бы вы могли даже указать мне правильное направление, я был бы очень признателен. !

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


person user1371443    schedule 03.05.2012    source источник
comment
посмотрите на теги plyr и data.table. Многие вопросы в основном касаются этого. Удачи!   -  person Chase    schedule 03.05.2012
comment
См. также 4dpiecharts.com/2011. /12/16/   -  person Richie Cotton    schedule 03.05.2012


Ответы (3)


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

# 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
person Dason    schedule 03.05.2012
comment
Круто - я просто играл с агрегатом после того, как задал вопрос, но вы меня сильно ускорили. Спасибо за вашу помощь. Однако еще один вопрос: когда я ввожу код, как вы показали, я получаю сообщение об ошибке Error in as.data.frame.default(x): невозможно преобразовать формулу класса в data.frame. Любые идеи о том, как заставить его работать? - person user1371443; 03.05.2012
comment
Оба, к сожалению. Я получаю одно и то же сообщение об ошибке как для примера, так и для моих фактических наборов данных (без пробелов): › агрегат (cbind (фрукты, семена) ~ сайт + растение + обработка + номер растения, сумма, данные = данные) Ошибка в as. data.frame.default(x): невозможно принудительно преобразовать формулу класса в data.frame - person user1371443; 03.05.2012
comment
Думаю, решение plyr все еще должно работать. Но похоже, что у вас нет версии формулы агрегата. Какую версию R вы используете? Я думаю, что агрегат позволяет вводить формулы с версии 2.11. - person Dason; 03.05.2012

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

person Ben    schedule 03.05.2012

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

library(tidyverse)

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