Considérons le bloc de données suivant:
data %>% group_by(col1, col2) %>% summarize(stat = sum(val2) - sum(val1)) # A tibble: 5 x 3 # Groups: col1 [?] col1 col2 stat <fct> <fct> <dbl> 1 A A 58.1 2 B A -16.4 3 B B 17.0 4 C A -12.9 5 C C -41.9
Le tableau de contingence est le suivant:
cont_tab <- table(data$col1, data$col2, dnn = c("col1", "col2")) cont_tab col2 col1 A B C A 4 0 0 B 1 3 0 C 1 0 3
Comme vous pouvez le voir, certaines paires n'ont pas ne se produisent pas: (A, B), (A, C), (B, C), (C, B). Le but final de mon analyse est de lister toutes les paires (dans ce cas 9) et d'afficher une statistique pour chacune d'elles. En utilisant la fonction dplyr :: group_by ()
, j'ai atteint une limitation. À savoir, le dplyr :: group_by ()
ne considère que les paires existantes (paires qui se sont produites au moins une fois):
set.seed(123) data <- data.frame(col1 = factor(rep(c("A", "B", "C"), 4)), col2 = factor(c(rep(c("A", "B", "C"), 3), c("A", "A", "A"))), val1 = 1:12, val2 = rnorm(12, 10, 15))
Le résultat que j'ai en tête a 9 lignes (dont 4 ont stat
égal à 0). Est-ce faisable dans dplyr
?
EDIT: Désolé d'être trop vague au début. Le vrai problème est plus complexe que de compter le nombre de fois qu'une paire particulière se produit. J'ai ajouté les nouvelles données afin de rendre le vrai problème plus visible.
5 Réponses :
Ceci est faisable même sans dplyr
as.data.frame(table(data$col1, data$col2, dnn = c("col1", "col2"))) # col1 col2 Freq #1 A A 4 #2 B A 1 #3 C A 1 #4 A B 0 #5 B B 3 #6 C B 0 #7 A C 0 #8 B C 0 #9 C C 3
Il est beaucoup plus facile d'ajouter spread
depuis tidyr
pour obtenir le même résultat qu'avec table
data %>% group_by(col1, col2) %>% summarize(stat = sum(val2) - sum(val1)) %>% spread(col2, stat, fill = 0) %>% gather(col2, stat, -1) # A tibble: 9 x 3 # Groups: col1 [3] # col1 col2 stat # <fct> <chr> <dbl> #1 A A 7.76 #2 B A -20.8 #3 C A 6.97 #4 A B 0 #5 B B 28.8 #6 C B 0 #7 A C 0 #8 B C 0 #9 C C 9.56
REMARQUE: l'étape group_by / summary
est remplacée par count
ici
Comme @divibisan l'a suggéré, si l'OP voulait un format long, ajoutez rassembler à la fin
data %>% group_by(col1, col2) %>% summarize(stat = n()) %>% spread(col2, stat, fill = 0) %>% gather(col2, stat, A:C) # A tibble: 9 x 3 # Groups: col1 [3] # col1 col2 stat # <fct> <chr> <dbl> #1 A A 4 #2 B A 1 #3 C A 1 #4 A B 0 #5 B B 3 #6 C B 0 #7 A C 0 #8 B C 0 #9 C C 3
Avec les données mises à jour dans le post de OP
library(dplyr) library(tidyr) count(data, col1, col2) %>% spread(col2, n, fill = 0) # A tibble: 3 x 4 # Groups: col1 [3] # col1 A B C # <fct> <dbl> <dbl> <dbl> #1 A 4 0 0 #2 B 1 3 0 #3 C 1 0 3
Il s'agit simplement de répliquer la table avec laquelle le demandeur a commencé. Ils veulent les décomptes au format long sous forme de trame de données 9x3
Les spread ()
et rassembler ()
sont vraiment utiles. Je me demande s'il est possible de ne pas coder en dur A: C
dans la dernière ligne?
@ balkon16 Vous pouvez le changer en -1
c'est-à-dire sauf la première colonne. Mise à jour du code
Vous pouvez utiliser tidyr::complete
data %>% count(col1, col2) %>% complete(col1, col2, fill = list(n = 0))
Vous pouvez également utiliser count
pour la première partie. Le code ci-dessous donne le même résultat que le code ci-dessus
library(tidyverse) data %>% group_by(col1, col2) %>% summarize(stat = n()) %>% # additions below ungroup %>% complete(col1, col2, fill = list(stat = 0)) # # A tibble: 9 x 3 # col1 col2 stat # <chr> <chr> <dbl> # 1 A A 4 # 2 A B 0 # 3 A C 0 # 4 B A 1 # 5 B B 3 # 6 B C 0 # 7 C A 1 # 8 C B 0 # 9 C C 3
C'est une belle option
Également une possibilité tidyverse
en utilisant tidyr::complete()
:
data %>% count(col1, col2) %>% right_join(crossing(col1 = unique(data$col1), col2 = unique(data$col2)), by = c("col1" = "col1", "col2" = "col2")) %>% replace_na(list(n = 0))
Ou en utilisant tidyr :: expand ( )
:
data %>% count(col1, col2) %>% right_join(data %>% expand(col1, col2), by = c("col1" = "col1", "col2" = "col2")) %>% replace_na(list(n = 0))
Ou en utilisant tidyr::crossing()
:
data %>% group_by_all() %>% add_count() %>% complete(col1, col2, fill = list(n = 0)) %>% distinct() col1 col2 n <fct> <fct> <dbl> 1 A A 4 2 A B 0 3 A C 0 4 B A 1 5 B B 3 6 B C 0 7 C A 1 8 C B 0 9 C C 3
Voici une petite solution de contournement, j'espère que cela fonctionne pour vous. Fusionnez votre tableau avec le tableau de toutes les combinaisons et remplacez les NA par 0.
data %>% group_by(col1, col2) %>% summarize(stat = n()) %>% merge(unique(expand.grid(data)), by=c("col1","col2"), all=T) %>% replace_na(list(stat=0))
Vous pouvez ajouter
spread
à partir detidyr
%>% spread (col2, stat, fill = 0)
Le groupe par étape peut se faire avec une seule lignecount (data, col1, col2)%>% spread (col2, n, fill = 0)