2
votes

Diviser la colonne de chaîne en plusieurs à l'aide de tidyverse

J'ai une colonne de chaîne avec des virgules. Je souhaite convertir cette colonne unique en plusieurs colonnes étiquetées, avec des valeurs remplies de manière appropriée. La trame de données de sortie aurait 3 colonnes (A, B et C). La ligne 1 comprendrait les colonnes A et B remplies par «Oui» et C par «Non». La ligne 2 aurait les 3 colonnes remplies avec "Oui", etc.

A    B    C
Yes  Yes  No
Yes  Yes  Yes
Yes  No   No
Yes  No   Yes

Sortie requise

df1 <- data.frame(X= c("A, B", "A, B, C", "A", "A, C"))

df1
        X
1    A, B
2 A, B, C
3       A
4    A, C

N'importe quel indice, s'il vous plaît.


6 Réponses :


4
votes

Quelque chose comme ceci:

library(tidyverse)

df1 %>%
  mutate(id = row_number()) %>% 
  separate_rows(X) %>% 
  group_by(id) %>% 
  mutate(Y = "yes") %>% 
  spread(X, Y, fill = "no")

# A tibble: 4 x 4
# Groups:   id [4]
     id A     B     C    
  <int> <chr> <chr> <chr>
1     1 yes   yes   no   
2     2 yes   yes   yes  
3     3 yes   no    no   
4     4 yes   no    yes  


0 commentaires

2
votes

Une approche légèrement différente qui ne repose pas sur le regroupement. La conversion finale en "Oui /" Non "est également effectuée par colonne, plutôt que de s'appuyer sur une conversion de données longues en données larges. Pour un très grand ensemble de données, cela peut être un peu plus efficace.

df2 <- df1 %>% 
  mutate(row_num = 1:n()) %>% 
  separate_rows(X) %>% 
  spread(X, 1) %>% 
  select(-row_num) %>% 
  mutate_all(~ifelse(!is.na(.), 'Yes', 'No'))

    A   B   C
1 Yes Yes  No
2 Yes Yes Yes
3 Yes  No  No
4 Yes  No Yes


0 commentaires

1
votes

Utilisation de splitstackshape

library(splitstackshape)
newdf=cSplit_e(df1, "X", sep = ", ",type = "character")
newdf[newdf==1]='Yes'
newdf[is.na(newdf)]='No'

newdf
        X X_A X_B X_C
1    A, B Yes Yes  No
2 A, B, C Yes Yes Yes
3       A Yes  No  No
4    A, C Yes  No Yes


0 commentaires

1
votes

Voici une autre solution en base

lets <- strsplit(as.character(.subset2(df1,1L)), ', ')
lets_unique <- unique(unlist(lets))
vapply(seq_along(lets_unique),function(k)grepl(lets_unique[k],lets),logical(length(lets)))
#      [,1]  [,2]  [,3]
# [1,] TRUE  TRUE FALSE
# [2,] TRUE  TRUE  TRUE
# [3,] TRUE FALSE FALSE
# [4,] TRUE FALSE  TRUE


0 commentaires

3
votes

Voici une option utilisant base R avec table . Nous divisons la colonne 'X' par , en une liste de vecteurs s, la convertissons en deux colonnes data.frame avec stack , obtenez la fréquence avec table et convertissez-la en

table(stack(setNames(strsplit(as.character(df1$X), ", +"), 
                    seq_len(nrow(df1))))[2:1]) > 0
 #   values
#ind    A     B     C
#  1 TRUE  TRUE FALSE
#  2 TRUE  TRUE  TRUE
#  3 TRUE FALSE FALSE
#  4 TRUE FALSE  TRUE

logique


0 commentaires

3
votes

Via stringi

stringi::stri_split_fixed(df1$X, ", ", simplify = TRUE) != ""
#      [,1]  [,2]  [,3]
# [1,] TRUE  TRUE FALSE
# [2,] TRUE  TRUE  TRUE
# [3,] TRUE FALSE FALSE
# [4,] TRUE  TRUE FALSE

TRUE / FALSE est essentiellement oui / non mais si vous avez besoin de la matrice de caractères, vous pouvez toujours faire ifelse (., "yes", "no") et conserver la structure de la matrice.


0 commentaires