Суммирование строк на основе конкретных комбинаций факторов
Это, наверное, глупый вопрос, но я прочитал главу 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))