2
votes

Compter le nombre de chaque groupe de facteurs par un autre facteur

Je sais que la réponse à cette question sera simple, mais j'ai effectué de nombreuses recherches dans les forums et je n'ai pas pu trouver de solution.

J'ai une colonne appelée Data_source qui est un facteur par lequel je souhaite regrouper mes variables.

J'ai une série de variables symptom * dont je veux les décomptes selon Data_source .

Pour une raison quelconque, je n'arrive pas à comprendre comment faire cela. Les fonctions normales de group_by ne semblent pas fonctionner correctement.

Voici le dataframe en question

> df %>% na.omit() %>% group_by(Data_source) %>% count("symptoms_decLOC")
# A tibble: 2 x 3
# Groups:   Data_source [2]
  Data_source `"symptoms_decLOC"`     n
  <chr>       <chr>               <int>
1 1           symptoms_decLOC         5
2 2           symptoms_decLOC         2

Notez que Sex et les variables des symptômes sont tous des facteurs qui incluent les NA. J'ai essayé ce qui suit

df %>% na.omit() %>% group_by(Data_source) %>% count("symptoms_decLOC")

Ce qui ne fonctionne pas et n'est pas optimal car je devrais le répéter pour chaque colonne. L'idéal serait d'utiliser quelque chose de similaire à lapply (df, count) mais cela ne me donne pas de description pour chaque groupe.

EDIT

En réponse à la question ci-dessous, j'ai ajouté le résultat attendu. J'ai édité ceci dans Excel, en codant par couleur le group_by pour plus de clarté.

entrez la description de l'image ici

Remarquez comment je je reçois une ventilation pour chaque réponse possible. Lorsque je l'exécute en utilisant dplyr , voici la sortie.

 df <- wrapr::build_frame(
   "Data_source"  , "Sex"   , "symptoms_decLOC", "symptoms_nausea_vomitting" |
     "1"          , "Female", NA_character_    , NA_character_               |
     "1"          , "Female", NA_character_    , NA_character_               |
     "1"          , "Female", "No"             , NA_character_               |
     "1"          , "Female", "Yes"            , "No"                        |
     "1"          , "Female", "Yes"            , "No"                        |
     "1"          , "Female", "Yes"            , "No"                        |
     "1"          , "Male"  , "Yes"            , "No"                        |
     "1"          , "Female", "Yes"            , "No"                        |
     "2"          , "Female", NA_character_    , NA_character_               |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Female", "Yes"            , "No"                        |
     "2"          , "Female", "Yes"            , "No"                        |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Female", NA_character_    , NA_character_               |
     "2"          , "Female", NA_character_    , NA_character_               |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Female", NA_character_    , NA_character_               )


2 commentaires

quelle est votre sortie souhaitée?


Merci pour votre commentaire. J'aurais dû mettre cela dans la question initiale. J'ai fait un EDIT pour clarifier davantage ce que je recherche


4 Réponses :


0
votes

Je ne comprends pas tout à fait ce que vous demandez, mais je suppose que vous voulez compter le nombre de valeurs non-NA dans chacune de vos colonnes symptom_ * .

Ceci est une solution data.table :

# load library

library(data.table)

# Suppose the table is called "dt". Convert it to a data.table:

setDT(dt)

# convert the wide table to a long one, filter the values that
# aren't NA and count both, by Data_source and by variable
# (variable is the created column with the symptom_* names)

melt(dt, id.vars = 1:2)[!is.na(value), 
                        .N, 
                         by = .(Data_source, variable)]

Ce que fait chaque partie du code:

melt ( dt, id.vars = 1: 2) convertit dt de large en long et conserve les colonnes 1 et 2 (Data_source et sex ) comme fixes.

! is.na (valeur) filtre les valeurs (qui étaient auparavant sous chaque en-tête symptom_ * ) qui ne sont pas NA code >.

.N compte les lignes.

by =. (Data_source, variable) est le regroupement que nous utilisons compter. variable est le nom de la colonne où le symptom_ * a atterri lors de la refonte.


1 commentaires

Lorsque j'exécute cela, j'obtiens la variable Data_source suivante N 1: 1 symptômes_decLOC 6 2: 2 symptômes_decLOC 2 3: 1 symptômes_nausea_vomitting 5 4: 2 symptômes_nausea_vomitting 2 Cela ne me donne pas de statistiques pour chaque réponse individuelle.



1
votes

Cela prend la plupart du temps: je n'ai pas encore trouvé comment inclure des groupes à zéro comptage ... soi-disant en ajoutant . drop = FALSE s'occupe de ça , mais cela ne fonctionne pas pour moi (en utilisant dplyr v. 0.8.0.9001 ).

  Data_source var                       val        n
  <chr>       <chr>                     <chr>  <int>
1 1           Sex                       Female     7
2 1           Sex                       Male       1
3 1           symptoms_decLOC           No         1
4 1           symptoms_decLOC           Yes        5
5 1           symptoms_nausea_vomitting No         5
6 2           Sex                       Female     6
7 2           Sex                       Male       6
8 2           symptoms_decLOC           Yes        2
9 2           symptoms_nausea_vomitting No         2

Résultats:

library(dplyr)
library(tidyr)
(df
    %>% tidyr::gather(var,val,-Data_source)
    %>% count(Data_source,var,val, .drop=FALSE)
    %>% na.omit()
)


5 commentaires

En utilisant cette syntaxe, je n'obtiens pas le même résultat que vous. J'obtiens Erreur de décompte (., Data_source, var, val, .drop = FALSE): arguments non utilisés (val, .drop = FALSE)


quels sont les résultats de find ("count") (et packageVersion ("dplyr") `)?


Voici un lien vers la sortie > find ("count") [1] "package: plyr" "package: dplyr"> packageVersion ("dplyr") [1] '0.8.0.1'


D'accord, puisque les deux packages sont en cours de chargement si je change votre code en dplyr :: count , j'obtiens le résultat attendu! Merci


Vous avez probablement reçu un avertissement indiquant que certaines fonctions étaient masquées lorsque vous avez chargé plyr après dplyr ...



1
votes

Utilisation de la réponse de @Ben Bolker pour obtenir le décompte de chaque groupe, utilisation de spread et collecte pour inclure des groupes de comptage nul.

dplyr

library(data.table)
dt <- data.table(df)

# Melt data by Data source
dt_melt <- melt(dt, id.vars = "Data_source", value.factor = FALSE, variable.factor = FALSE)

# Add counter, if NA then 0 else 1
dt_melt[, counter := 0]
dt_melt[!is.na(value), counter := 1]

# Sum number of occurrences
dt_count <- dt_melt[,list(counter = sum(counter)), by = c("Data_source", "variable", "value")]

# Split into two dt
dt2a <- dt_count[variable == "Sex", ]
dt2b <- dt_count[variable != "Sex" ,]

# only on symptoms variables
# Convert into factor variable
dt2b$value <- factor(dt2b$value, levels = c("Yes", "No"))
dt2b_dcast <- dcast(data = dt2b, formula = Data_source + variable ~ value, value.var = "counter", fill = 0, drop = FALSE)
dt2b_melt <- melt(dt2b_dcast, id.vars = c("Data_source", "variable"), variable.name = "value", value.name = "counter") 

# combine
combined_d <- rbind(dt2a, dt2b_melt)
combined_d[order(Data_source, variable), ]

library(dplyr)
library(tidyr)

# Count number of occurences by Data_source 
df2 <- 
  df %>% 
  gather(variable, value, -Data_source) %>% 
  count(Data_source, variable, value, name = "counter") %>%
  na.omit() 

# For variable = "Sex", leave as is
# For everything else, in this case symptom* convert into factor to include zero count group
# Then spread with dataframe will NAs filled with 0, re-convert back to long to bind rows
bind_rows(df2 %>%
            filter(variable == "Sex"), 

          df2 %>%
            filter(variable != "Sex") %>%
            mutate(value = factor(value, levels = c("Yes", "No"))) %>%
            spread(key = value, value = counter, fill = 0) %>%
            gather(value, counter, -Data_source, -variable))  %>%

  arrange(Data_source, variable)


1 commentaires

Ya je suis toujours incapable de faire fonctionner la méthode dplyr. Data.table fonctionne mais il ajoute une énorme quantité de code.



0
votes

Décidément, le plus dur est de conserver des combinaisons qui n'existent pas dans les données ... Voici une solution en deux étapes:

1. Préparez une base de données sans décompte

Vous pouvez faire ce que vous voulez, mais j'ai choisi de calculer deux blocs car les modalités sont différentes pour la variable Sex . Pas besoin de lier ces morceaux ici.

# A tibble: 12 x 4
# Groups:   Data_source, name [6]
   Data_source name                      value  count
   <chr>       <chr>                     <chr>  <int>
 1 1           Sex                       Female     7
 2 1           Sex                       Male       1
 3 1           symptoms_decLOC           Yes        5
 4 1           symptoms_decLOC           No         1
 5 1           symptoms_nausea_vomitting Yes        0
 6 1           symptoms_nausea_vomitting No         5
 7 2           Sex                       Female     6
 8 2           Sex                       Male       6
 9 2           symptoms_decLOC           Yes        2
10 2           symptoms_decLOC           No         0
11 2           symptoms_nausea_vomitting Yes        0
12 2           symptoms_nausea_vomitting No         2

2. Terminer le travail demandé

library(dplyr)
library(tidyr)

df %>% 
  pivot_longer(cols = c("Sex", "symptoms_decLOC", "symptoms_nausea_vomitting"))%>%
  group_by(Data_source, name, value) %>%
  summarise(count = n()) %>%
  right_join(bind_rows(chunk1, chunk2), by = c("Data_source", "name", "value")) %>%
  arrange(Data_source, name) %>%
  mutate(count = zoo::na.fill(count, 0))

Et voilÃ

chunk1 <- expand.grid(
  Data_source = c("1", "2"),
  name = c("symptoms_decLOC", "symptoms_nausea_vomitting"),
  value = c("Yes", "No"),
  stringsAsFactors = FALSE
)

chunk2 <- expand.grid(
  Data_source = c("1", "2"),
  name = "Sex",
  value = c("Female", "Male"),
  stringsAsFactors = FALSE
)

Ce n'est pas si court, mais il utilise des fonctions simples. Le processus est similaire à celui que l'on peut faire dans Excel, c'est-à-dire préparer la structure puis compléter les comptages.

J'espère que cela pourrait aider ;-)


0 commentaires