dplyr summarize: Equivalent of".drop=FALSE " pour garder les groupes de longueur zéro en sortie
Lorsqu'on utilise la fonction summarise
avec la fonction plyr
's ddply
, les catégories vides sont supprimées par défaut. Vous pouvez modifier ce comportement en ajoutant .drop = FALSE
. Cependant, cela ne fonctionne pas lorsque vous utilisez summarise
avec dplyr
. Est-il une autre façon de garder vide catégories dans le résultat?
voici un exemple avec de fausses données.
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
Pas exactement ce que j'espérais. Existe-t-il une méthode dplyr
pour atteindre le même résultat que .drop=FALSE
dans plyr
?
3 réponses
la question est toujours ouverte, mais en attendant, surtout depuis que vos données sont déjà prises en compte, vous pouvez utiliser complete
de "tidyr" pour obtenir ce que vous pourriez être à la recherche de:
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
si vous voulez que la valeur de remplacement soit zéro, vous devez spécifier que avec 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 solution:
première marque groupée DF
by_b <- tbl_df(df) %>% group_by(b)
nous résumons ensuite les niveaux qui se produisent en comptant avec n()
res <- by_b %>% summarise( count_a = n() )
ensuite nous fusionnons nos résultats dans une base de données qui contient tous les niveaux de facteurs:
expanded_res <- left_join(expand.grid(b = levels(df$b)),res)
enfin, dans ce cas, puisque nous regardons les comptes, les valeurs NA
sont changées à 0.
final_counts <- expanded_res[is.na(expanded_res)] <- 0
cela peut aussi être mis en œuvre fonctionnellement, voir les réponses: Ajouter des lignes de données regroupées avec dplyr?
Une bidouille:
j'ai pensé que je posterais un terrible hack qui fonctionne dans ce cas pour intérêt. Je doute sérieusement que vous devriez réellement faire cela mais il montre comment group_by()
génère les atrributes comme si df$b
était un vecteur de caractère pas un facteur avec des niveaux. Aussi, Je ne prétendez pas comprendre cela correctement -- mais j'espère que cela m'aidera à apprendre -- c'est la seule raison pour laquelle je l'affiche!
by_b <- tbl_df(df) %>% group_by(b)
définit une valeur" hors limites " qui ne peut pas exister dans l'ensemble de données.
oob_val <- nrow(by_b)+1
modifier les attributs pour" trick " summarise()
:
attr(by_b, "indices")[[3]] <- rep(NA,oob_val)
attr(by_b, "group_sizes")[3] <- 0
attr(by_b, "labels")[3,] <- 3
faire le résumé:
res <- by_b %>% summarise(count_a = n())
index et remplacer toutes les occurences de oob_val
res[res == oob_val] <- 0
qui donne la destination:
> res
Source: local data frame [3 x 2]
b count_a
1 1 6
2 2 6
3 3 0
ce n'est pas exactement ce qui a été demandé dans la question, mais au moins pour cet exemple simple, vous pourriez obtenir le même résultat en utilisant xtabs, par exemple:
utilisant dplyr:
df %.%
xtabs(formula = ~ b) %.%
as.data.frame()
ou moins:
as.data.frame(xtabs( ~ b, df))
résultat (égal dans les deux cas):
b Freq
1 1 6
2 2 6
3 3 0