dplyr резюмируют: эквивалент ".drop=FALSE " для сохранения групп с нулевой длиной на выходе
при использовании summarise
С plyr
' s 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
?
3 ответа:
вопрос все еще открыт, но в то же время, тем более, что ваши данные уже учтены, вы можете использовать
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()
генерирует atrributes, как если бы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