Использование dplyr для суммирования и сохранения одинакового имени переменной
Я обнаружил, что data.table и dplyr имеют разные результаты при попытке сделать то же самое. Я хотел бы использовать синтаксис dplyr, но рассчитать его так, как это делает data.table. Вариант использования: я хочу добавить промежуточные итоги в таблицу. Для этого мне нужно выполнить агрегацию для каждой переменной, но затем сохранить те же имена переменных (в преобразованной версии). Data.table позволяет мне выполнять некоторую агрегацию для переменной и сохранять то же имя. Затем выполните еще одну агрегацию с той же переменной. Он будет продолжать использовать нетрансформированную версию. Dplyr, однако, будет использовать преобразованную версию.
В итоговой документации сказано:
# Note that with data frames, newly created summaries immediately
# overwrite existing variables
mtcars %>%
group_by(cyl) %>%
summarise(disp = mean(disp), sd = sd(disp))
Это в основном проблема, с которой я сталкиваюсь, но мне интересно, есть ли хороший обходной путь. Одна вещь, которую я обнаружил, состояла в том, чтобы просто назвать преобразованную переменную как-нибудь еще, а затем переименовать ее в конце, но это не очень приятно для меня. Если есть хороший способ сделать промежуточные итоги, это было бы хорошо знать. Я осмотрел этот сайт и не увидел обсуждаемой ситуации. Любая помощь будет принята с благодарностью!
Здесь я привел простой пример, один раз с результатами data.table и один раз с dplyr. Я хочу взять эту простую таблицу и добавить итоговую строку, которая является средневзвешенным значением интересующего столбца (Итого).
library(data.table)
library(dplyr)
dt <- data.table(Group = LETTERS[1:5],
Count = c(1000, 1500, 1200, 2000, 5000),
Total = c(50, 300, 600, 400, 1000))
dt[, Count_Dist := Count/sum(Count)]
dt[, .(Count_Dist = sum(Count_Dist), Weighted_Total = sum(Count_Dist*Total))]
dt <- rbind(dt[, .(Group, Count_Dist, Total)],
dt[, .(Group = "All", Count_Dist = sum(Count_Dist), Total = sum(Count_Dist*Total))])
setnames(dt, "Total", "Weighted_Avg_Total")
dt
df <- data.frame(Group = LETTERS[1:5],
Count = c(1000, 1500, 1200, 2000, 5000),
Total = c(50, 300, 600, 400, 1000))
df %>%
mutate(Count_Dist = Count/sum(Count)) %>%
summarize(Count_Dist = sum(Count_Dist),
Weighted_Total = sum(Count_Dist*Total))
df %>%
mutate(Count_Dist = Count/sum(Count)) %>%
select(Group, Count_Dist, Total) %>%
rbind(df %>%
mutate(Count_Dist = Count/sum(Count)) %>%
summarize(Group = "All",
Count_Dist = sum(Count_Dist),
Total = sum(Count_Dist*Total))) %>%
rename(Weighted_Avg_Total = Total)
Еще раз спасибо за любую помощь!
2 ответа
Возможное решение - пропустить mutate
шаги и использование transmute
для первого mutate
/select
-шаг и непосредственно рассчитать нужные переменные из исходных переменных без создания промежуточной переменной для второй mutate
-ступенно:
df %>%
transmute(Group, Count_Dist = Count/sum(Count), Weighted_Avg_Total = Total) %>%
bind_rows(df %>%
summarize(Group = "All",
Count_Dist = sum(Count/sum(Count)),
Weighted_Avg_Total = sum((Count/sum(Count))*Total)))
который дает:
Group Count_Dist Weighted_Avg_Total 1 A 0.09345794 50.0000 2 B 0.14018692 300.0000 3 C 0.11214953 600.0000 4 D 0.18691589 400.0000 5 E 0.46728972 1000.0000 6 All 1.00000000 656.0748
Другое возможное решение - изменить порядок, в котором новые переменные вычисляются в dplyr
а затем использовать select
чтобы вернуть порядок столбцов в то, что вы изначально хотели:
df %>%
mutate(Count_Dist = Count/sum(Count)) %>%
select(Group, Count_Dist, Weighted_Avg_Total = Total) %>%
bind_rows(df %>%
mutate(Count_Dist = Count/sum(Count)) %>%
summarize(Group = "All",
Weighted_Avg_Total = sum(Count_Dist*Total),
Count_Dist = sum(Count_Dist)) %>%
select(Group, Count_Dist, Weighted_Avg_Total))
Если вы хотите включить Count
-колонка, вы могли бы сделать (на основе моего комментария снизу):
df %>%
transmute(Group = Group, Count_Dist = Count/sum(Count), Weighted_Avg_Total = Total, Count) %>%
bind_rows(df %>%
summarize(Group = "All",
Count_Dist = sum(Count/sum(Count)),
Weighted_Avg_Total = sum((Count/sum(Count))*Total),
Count = sum(Count)))
Одной из альтернатив может быть использование mutate
дважды, чтобы рассчитать даже Weighted_Total
и использовать sum
из этого столбца в summarize
,
df %>%
mutate(Count_Dist = Count/sum(Count)) %>%
mutate(Weighted_Total = Count_Dist*Total) %>%
summarize(Count_Dist = sum(Count_Dist),
Weighted_Total = sum(Weighted_Total))
Result:
Count_Dist Weighted_Total
1 1 656.074766
А также:
df %>%
mutate(Count_Dist = Count/sum(Count)) %>%
select(Group, Count_Dist, Total) %>%
rbind(df %>%
mutate(Count_Dist = Count/sum(Count)) %>%
mutate(Weighted_Total = Count_Dist*Total) %>%
summarize(Group = "All",
Count_Dist = sum(Count_Dist),
Total = sum(Weighted_Total))) %>%
rename(Weighted_Avg_Total = Total)
Result:
Group Count_Dist Weighted_Avg_Total
1 A 0.0934579439 50.000000
2 B 0.1401869159 300.000000
3 C 0.1121495327 600.000000
4 D 0.1869158879 400.000000
5 E 0.4672897196 1000.000000
6 All 1.0000000000 656.074766