dplyr суммировать: Эквивалент «.drop = FALSE» для сохранения групп с нулевой длиной в выходе
При использовании summarise
с plyr
ddply
пустые категории по умолчанию отбрасываются. Вы можете изменить это поведение, добавив .drop = FALSE
. Однако это не работает при использовании summarise
с dplyr
. Есть ли другой способ сохранить пустые категории в результате?
Вот пример с поддельными данными.
library(dplyr) df = data.frame(a=rep(1:3,4), b=rep(1:2,6)) # Now add an extra level to df$b that has no corresponding value in df$a df$b = factor(df$b, levels=1:3) # Summarise with plyr, keeping categories with a count of zero plyr::ddply(df, "b", summarise, count_a=length(a), .drop=FALSE) b count_a 1 1 6 2 2 6 3 3 0 # Now try it with dplyr df %.% group_by(b) %.% summarise(count_a=length(a), .drop=FALSE) b count_a .drop 1 1 6 FALSE 2 2 6 FALSE
Не совсем то, на что я надеялся. Есть ли метод dplyr
для достижения того же результата, что и .drop=FALSE
в plyr
?
- Эквивалентно команде unix unix в консоли R
- Локальная долгота Координаты с кодом состояния в R
- Есть ли функция R, которая применяет функцию к каждой паре столбцов?
- dplyr :: mutate добавить несколько значений
- R: объединить два нерегулярных временных ряда
- R dplyr: переименование переменных с использованием строковых функций
- Сохранение файла grid.arrange () в файл
- dplyr мутировать вычисления rowSums или пользовательские функции
- Как добавить количество наблюдений на группу и использовать групповое значение в блоке ggplot2?
- Как сохранить сюжет как изображение на диске?
- Есть ли встроенная функция для поиска режима?
- Отображение знака больше или равно
- Сравните два data.frames, чтобы найти строки в data.frame 1, которых нет в data.frame 2
Проблема по-прежнему открыта, но тем временем, тем более, что ваши данные уже учтены, вы можете использовать complete
от «tidyr», чтобы получить то, что вы можете искать:
library(tidyr) df %>% group_by(b) %>% summarise(count_a=length(a)) %>% complete(b) # Source: local data frame [3 x 2] # # b count_a # (fctr) (int) # 1 1 6 # 2 2 6 # 3 3 NA
Если вы хотите, чтобы значение замены было равно нулю, вам нужно указать, что при fill
:
df %>% group_by(b) %>% summarise(count_a=length(a)) %>% complete(b, fill = list(count_a = 0)) # Source: local data frame [3 x 2] # # b count_a # (fctr) (dbl) # 1 1 6 # 2 2 6 # 3 3 0
Решение dplyr:
Сначала сгруппируйте df
by_b <- tbl_df(df) %>% group_by(b)
то мы суммируем те уровни, которые происходят путем подсчета с n()
res <- by_b %>% summarise( count_a = n() )
то мы объединяем наши результаты в кадр данных, который содержит все уровни факторов:
expanded_res <- left_join(expand.grid(b = levels(df$b)),res)
наконец, в этом случае, поскольку мы смотрим на подсчеты, значения NA
меняются на 0.
final_counts <- expanded_res[is.na(expanded_res)] <- 0
Это также можно реализовать функционально, см. Ответы: Добавить строки в сгруппированные данные с помощью dplyr?
Взлом:
Я думал, что я опубликую ужасный хак, который работает в этом случае ради интереса. Я серьезно сомневаюсь, что вы действительно должны это делать, но это показывает, как group_by()
генерирует атрибуты, как если бы df$b
был символьным вектором, а не фактором с уровнями. Кроме того, я не претендую на это правильно, но я надеюсь, что это поможет мне учиться - это единственная причина, по которой я отправляю его!
by_b <- tbl_df(df) %>% group_by(b)
определите значение «вне пределов», которое не может существовать в наборе данных.
oob_val <- nrow(by_b)+1
изменить атрибуты на «трюк» summarise()
:
attr(by_b, "indices")[[3]] <- rep(NA,oob_val) attr(by_b, "group_sizes")[3] <- 0 attr(by_b, "labels")[3,] <- 3
сделать резюме:
res <- by_b %>% summarise(count_a = n())
индексировать и заменять все вхождения oob_val
res[res == oob_val] <- 0
который дает предполагаемое:
> res Source: local data frame [3 x 2] b count_a 1 1 6 2 2 6 3 3 0
это не совсем то, что было задано в вопросе, но, по крайней мере, для этого простого примера, вы можете получить тот же результат, используя xtabs, например:
используя dplyr:
df %.% xtabs(formula = ~ b) %.% as.data.frame()
или короче:
as.data.frame(xtabs( ~ b, df))
результат (равный в обоих случаях):
b Freq 1 1 6 2 2 6 3 3 0