Группировать по двум факторам с помощью dplyr

Я немного борюсь со структурой dplyr в R. Я хотел бы последовательно сгруппировать по двум разным уровням факторов, чтобы получить сумму другой переменной.

Вот воспроизводимый пример

df <- data.frame(c("A", "A", "A", "B", "C", "C","C"),
                 c("1", "1", "3", "2", "3", "2","2"),
                 c(12, 45, 78, 32, 5, 7, 8))

colnames(df) <- c("factor1","factor2","values")

И вот моя попытка до сих пор

test <- df %>%
  group_by(factor1, factor2) %>%
  summarise(sum(values))

# A tibble: 5 x 3
# Groups:   factor1 [3]
factor1 factor2 `sum(values)`
<fct>   <fct>           <dbl>
1 A       1                  57
2 A       3                  78
3 B       2                  32
4 C       2                  15
5 C       3                   5

Но это не то, что я ищу. Я хотел бы иметь одну строку для каждого фактора 1 с результатами, похожими на это (и 0 также учитывался)

        1   2   3 
A       57  0   78           
B       0   32  0             
C       0   15  5    

какие-либо предложения?


person ePoQ    schedule 28.05.2021    source источник


Ответы (4)


Вам нужно изменить форму или повернуть данные. Поскольку вы уже используете dplyr, вы можете использовать tidyr::pivot_wider. (В качестве альтернативы reshape2::dcast будет работать аналогично, хотя, честно говоря, я считаю, что pivot_wider более многофункционален.)

library(dplyr)
test <- df %>%
  group_by(factor1, factor2) %>%
  summarise(z = sum(values))
tidyr::pivot_wider(test, factor1, names_from = "factor2", values_from = "z",
                   values_fill = 0)
# # A tibble: 3 x 4
# # Groups:   factor1 [3]
#   factor1   `1`   `3`   `2`
#   <chr>   <dbl> <dbl> <dbl>
# 1 A          57    78     0
# 2 B           0     0    32
# 3 C           0     5    15
person r2evans    schedule 28.05.2021
comment
Спасибо, это работает хорошо, за исключением замены NA на 0. «Ошибка в values_fill[[value]]: нижний индекс выходит за пределы» - person ePoQ; 28.05.2021
comment
Я не знаю, с этими данными этого не происходит. Если вы можете найти, какие столбцы/значения вызывают его, обновите свои данные, и я посмотрю. - person r2evans; 28.05.2021
comment
Мой пакет тайдыра не был обновлен. Проблема решена спасибо. - person ePoQ; 31.05.2021

Использование pivot_Wider -

tidyr::pivot_wider(df, names_from = factor2, values_from = values, 
                    values_fn  =sum, values_fill = 0)

#  factor1   `1`   `3`   `2`
#  <chr>   <dbl> <dbl> <dbl>
#1 A          57    78     0
#2 B           0     0    32
#3 C           0     5    15

Or in data.table -

library(data.table)
dcast(setDT(df),factor1~factor2, value.var = 'values', fun.aggregate = sum)
person Ronak Shah    schedule 28.05.2021
comment
Используя воспроизводимый пример и первый метод, я получил «Ошибка в values_fn[[value]]: объект типа «встроенный» не является подмножеством». Второй работает отлично спасибо - person ePoQ; 28.05.2021
comment
@ePoQ Используя данные, которыми вы поделились в вопросе, я не получаю никаких ошибок. Вы пытались перезапустить R? - person Ronak Shah; 28.05.2021
comment
Мой пакет тайдыра не был обновлен. Проблема решена спасибо. - person ePoQ; 31.05.2021

Мы можем использовать xtabs из base R

xtabs(values ~ factor1 + factor2 , df)
#       factor2
#factor1  1  2  3
#      A 57  0 78
#      B  0 32  0
#      C  0 15  5
person akrun    schedule 28.05.2021

Я думаю, что решение @akrun's xtabs пока является самым кратким решением. Вот еще один базовый вариант R с aggregate + reshape

reshape(
  aggregate(values ~ ., df, sum),
  direction = "wide",
  idvar = "factor1",
  timevar = "factor2",
)

дает

  factor1 values.1 values.2 values.3
1       A       57       NA       78
2       B       NA       32       NA
3       C       NA       15        5

Вариант data.table

> dcast(setDT(df), factor1 ~ factor2, sum)
Using 'values' as value column. Use 'value.var' to override
   factor1  1  2  3
1:       A 57  0 78
2:       B  0 32  0
3:       C  0 15  5
person ThomasIsCoding    schedule 28.05.2021
comment
@akrun Ха-ха, тогда лучше не быть первым :P - person ThomasIsCoding; 28.05.2021