Fréquences / proportions relatives avec dplyr

Supposons que je veuille calculer la proportion de différentes valeurs dans chaque groupe. Par exemple, en utilisant les données mtcars , comment calculer la fréquence relative du nombre d’ engrenages par heure (automatique / manuel) en une seule fois avec dplyr ?

 library(dplyr) data(mtcars) mtcars % group_by(am, gear) %>% summarise(n = n()) # am gear n # 0 3 15 # 0 4 4 # 1 4 8 # 1 5 5 

Ce que j’aimerais réaliser:

 am gear n rel.freq 0 3 15 0.7894737 0 4 4 0.2105263 1 4 8 0.6153846 1 5 5 0.3846154 

Essaye ça:

 mtcars %>% group_by(am, gear) %>% summarise (n = n()) %>% mutate(freq = n / sum(n)) # am gear n freq # 1 0 3 15 0.7894737 # 2 0 4 4 0.2105263 # 3 1 4 8 0.6153846 # 4 1 5 5 0.3846154 

De la vignette dplyr :

Lorsque vous regroupez par plusieurs variables, chaque résumé détache un niveau du regroupement. Cela facilite le déploiement progressif d’un jeu de données.

Ainsi, après le summarise , la variable de regroupement «gear» est décollée et les données sont ensuite regroupées «seulement» par «am» (il suffit de le vérifier avec des groups sur les données résultantes), sur lesquelles nous effectuons ensuite le calcul.

Le résultat du «peeling» dépend bien sûr de l’ordre des variables de regroupement dans l’appel group_by . Nous avons eu de la chance cette fois-ci de retirer la variable souhaitée. Vous souhaiterez peut-être faire un group_by(am) pour rendre votre code plus explicite.

Pour l’arrondi et la prettification, veuillez vous référer à la belle réponse de @Tyler Rinker.

Vous pouvez utiliser la fonction count() , qui a cependant un comportement différent selon la version de dplyr :

  • dplyr 0.7.1: retourne une table non groupée : vous devez regrouper à nouveau par am

  • dplyr <0.7.1: retourne une table groupée , donc pas besoin de regrouper à nouveau, bien que vous puissiez ungroup() pour des manipulations ultérieures

dplyr 0.7.1

 mtcars %>% count(am, gear) %>% group_by(am) %>% mutate(freq = n / sum(n)) 

dplyr <0.7.1

 mtcars %>% count(am, gear) %>% mutate(freq = n / sum(n)) 

Cela se traduit par une table groupée , si vous souhaitez l’utiliser pour une parsing plus approfondie, il peut être utile de supprimer l’atsortingbut groupé avec ungroup() .

@ Henrik’s est meilleur pour la facilité d’utilisation car cela rendra les caractères de colonne non plus numériques mais correspondra à ce que vous demandiez …

 mtcars %>% group_by (am, gear) %>% summarise (n=n()) %>% mutate(rel.freq = paste0(round(100 * n/sum(n), 0), "%")) ## am gear n rel.freq ## 1 0 3 15 79% ## 2 0 4 4 21% ## 3 1 4 8 62% ## 4 1 5 5 38% 

EDIT Parce que Spacedman l’a demandé 🙂

 as.rel_freq <- function(x, rel_freq_col = "rel.freq", ...) { class(x) <- c("rel_freq", class(x)) attributes(x)[["rel_freq_col"]] <- rel_freq_col x } print.rel_freq <- function(x, ...) { freq_col <- attributes(x)[["rel_freq_col"]] x[[freq_col]] <- paste0(round(100 * x[[freq_col]], 0), "%") class(x) <- class(x)[!class(x)%in% "rel_freq"] print(x) } mtcars %>% group_by (am, gear) %>% summarise (n=n()) %>% mutate(rel.freq = n/sum(n)) %>% as.rel_freq() ## Source: local data frame [4 x 4] ## Groups: am ## ## am gear n rel.freq ## 1 0 3 15 79% ## 2 0 4 4 21% ## 3 1 4 8 62% ## 4 1 5 5 38% 

Voici une fonction générale mettant en œuvre la solution d’Henrik sur dplyr 0.7.1.

 freq_table <- function(x, group_var, prop_var) { group_var <- enquo(group_var) prop_var <- enquo(prop_var) x %>% group_by(!!group_var, !!prop_var) %>% summarise(n = n()) %>% mutate(freq = n /sum(n)) %>% ungroup } 

Cette réponse est basée sur la réponse de Matifou.

D’abord, je l’ai modifié pour m’assurer que la colonne freq ne soit pas renvoyée comme colonne de notation scientifique en utilisant l’option scipen.

Ensuite, je multiplie la réponse par 100 pour obtenir un pourcentage plutôt que décimal pour que la colonne freq soit plus facile à lire en pourcentage.

 getOption("scipen") options("scipen"=10) mtcars %>% count(am, gear) %>% mutate(freq = (n / sum(n)) * 100)