Рассчитать среднемесячную сумму по группам из таблицы данных. В R
У меня есть таблица data.table со строкой для каждого дня в течение 30-летнего периода с несколькими различными столбцами переменной. Причиной использования data.table является то, что файл CSV, который я использую, огромен (приблизительно 1,2 миллиона строк), поскольку для нескольких групп, характеризуемых столбцом под названием "ключ", существует 30-летняя стоимость данных.
Примерный набор данных показан ниже:
Key Date Runoff
A 1980-01-01 2
A 1980-01-02 1
A 1981-01-01 0.1
A 1981-01-02 3
A 1982-01-01 2
A 1982-01-02 5
B 1980-01-01 1.5
B 1980-01-02 0.5
B 1981-01-01 0.3
B 1981-01-02 2
B 1982-01-01 1.5
B 1982-01-02 4
Выше приведен пример двух "ключей", с некоторыми данными за январь в течение трех лет, чтобы показать, что я имею в виду. Фактический набор данных содержит сотни "ключей" и 30-летнюю ценность данных для каждого "ключа".
То, что я хочу сделать, это вывести вывод, который имеет общее среднее значение для каждого месяца для каждого ключа, как показано ниже:
Key January February March.... etc
A 4.36 ... ...
B 3.26 ... ...
то есть. общее среднее значение для января для ключа A = (2 + 1) + (0,1 + 3) + (2 + 5)/3
Когда я сделал этот анализ на одном наборе данных за тридцать лет (т.е. только один ключ), я успешно использовал следующий код для этого:
runoff_tot_average <- rowsum(DF$Runoff, format(DF$Date, '%m')) / 30
Где DF - это кадр данных для одного набора данных за 30 лет.
Могу ли я получить предложения по изменению моего кода выше, чтобы работать с большим набором данных со многими "ключами" или предложить совершенно новое решение?
Спасибо,
J
ИЗМЕНИТЬ
В приведенном ниже примере приведен пример данных выше:
Key <- c("A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B")
Date <- as.Date(c("1980-01-01", "1980-01-02", "1981-01-01", "1981-01-02", "1982-01-01", "1982-01-02", "1980-01-01", "1980-01-02", "1981-01-01", "1981-01-02", "1982-01-01", "1982-01-02"))
Runoff <- c(2, 1, 0.1, 3, 2, 5, 1.5, 0.5, 0.3, 2, 1.5, 4)
DT <- data.table(Key, Date, Runoff)
Ответы
Ответ 1
Только так я мог подумать, что это было в два шага. Вероятно, это не самый лучший способ, но здесь идет
DT[, c("YM", "Month") := list(substr(Date, 1, 7), substr(Date, 6, 7))]
DT[, Runoff2 := sum(Runoff), by = c("Key", "YM")]
DT[, mean(Runoff2), by = c("Key", "Month")]
## Key Month V1
## 1: A 01 4.366667
## 2: B 01 3.266667
Просто чтобы показать другой (очень похожий) способ:
DT[, c("year", "month") := list(year(Date), month(Date))]
DT[, Runoff2 := sum(Runoff), by=list(Key, year, month)]
DT[, mean(Runoff2), by=list(Key, month)]
Обратите внимание, что вам не нужно создавать новые столбцы, так как by
также поддерживает выражения. То есть вы можете напрямую использовать их в by
следующим образом:
DT[, Runoff2 := sum(Runoff), by=list(Key, year = year(Date), month = month(Date))]
Но поскольку вам требуется агрегировать более одного раза, лучше (для скорости) хранить их как дополнительные столбцы, как показано здесь @David.
Ответ 2
Если вы не ищете сложные функции и просто хотите получить среднее значение, тогда должно быть достаточно следующего:
DT[, sum(Runoff) / length(unique(year(Date))), list(Key, month(Date))]
# Key month V1
#1: A 1 4.366667
#2: B 1 3.266667
Ответ 3
Поскольку вы сказали в своем вопросе, что вы были бы открыты для совершенно нового решения, вы можете попробовать следующее с dplyr
:
df$Date <- as.Date(df$Date, format="%Y-%m-%d")
df$Year.Month <- format(df$Date, '%Y-%m')
df$Month <- format(df$Date, '%m')
require(dplyr)
df %>%
group_by(Key, Year.Month, Month) %>%
summarize(Runoff = sum(Runoff)) %>%
ungroup() %>%
group_by(Key, Month) %>%
summarize(mean(Runoff))
ИЗМЕНИТЬ № 1 после комментария от @Henrik:
То же самое можно сделать:
df %>%
group_by(Key, Month, Year.Month) %>%
summarize(Runoff = sum(Runoff)) %>%
summarize(mean(Runoff))
ИЗМЕНИТЬ № 2:
Это еще один способ сделать это (вторая группировка более явна именно так)
благодаря @Henrik за его комментарии
df %>%
group_by(Key, Month, Year.Month) %>%
summarize(Runoff = sum(Runoff)) %>%
group_by(Key, Month, add = FALSE) %>% #now grouping by Key and Month, but not Year.Month
summarize(mean(Runoff))
Он производит следующий результат:
#Source: local data frame [2 x 3]
#Groups: Key
#
# Key Month mean(Runoff)
#1 A 01 4.366667
#2 B 01 3.266667
Затем вы можете изменить выход, чтобы он соответствовал желаемому выходу, например, reshape2
. Предположим, что вы сохранили вывод вышеуказанной операции в файле data.frame df2
, тогда вы могли бы сделать:
require(reshape2)
df2 <- dcast(df2, Key ~ Month, sum, value.var = "mean(Runoff)")