2017-09-07 5 views
1

Supposons que chaque ligne d'une colonne (chaîne_fil) comporte un nombre variable de chaînes séparées par une virgule. Par exemple:dataframe dans R: recherche de plusieurs chaînes dans une cellule séparées par une virgule

letter_strings 

abc, def, ghi, jkl 
mno, pqr 
stu, vw, xyz 

Je voudrais rechercher chaque chaîne dans une trame de données:

letter_strings code 

abc YES 
def NO 
ghi MAYBE 
jkl SURE 
mno PERHAPS 
pqr ALWAYS 
stu NEVER 
vw NOGO 
xyz ABSENT 

et obtenir les lignes correspondantes suivantes, dans une colonne supplémentaire

YES, NO, MAYBE, SURE 
PERHAPS, ALWAYS 
NEVER, NOGO, ABSENT 

Est-ce possible R, je ne sais pas vraiment comment faire face à ce problème ...

Merci d'avance!

W

+3

S'il vous plaît fournir un 'dput' de vos données dans le corps de votre question. Il sera utile de déterminer la structure réelle des données avec lesquelles vous travaillez. Si elle est grande, alors 'dput (head (dat, 10))' ou 'devrait suffire. – lmo

Répondre

0

S'il n'y a pas trop de chaînes de lettres, vous pouvez le faire avec gsub dans une boucle.

Temp = letter_strings 
for(i in 1:nrow(df)) { 
    Temp = gsub(df$letter_strings[i], df$code[i], Temp) } 
Temp 
[1] "YES, NO, MAYBE, SURE" "PERHAPS, ALWAYS"  "NEVER, NOGO, ABSENT" 
3

1) gusbfn

gsubfn est comme gsub sauf qu'il regarde les matchs à l'expression régulière (ici défini comme "\\w+", soit une séquence de caractères de mots) dans les noms de la recherche liste, lookup, en remplaçant les noms de la chaîne cible par leurs valeurs dans lookup.

library(gsubfn) 

lookup <- with(DF2, as.list(setNames(code, letter_strings))) 
transform(DF1, codes = gsubfn("\\w+", lookup, letter_strings)) 

donnant:

 letter_strings    codes 
1 abc, def, ghi, jkl YES, NO, MAYBE, SURE 
2   mno, pqr  PERHAPS, ALWAYS 
3  stu, vw, xyz NEVER, NOGO, ABSENT 

2) dplyr/tidyr Convertir DF1 à la forme longue, joignez-vous avec DF2 puis remodeler revenir à la forme originale:

library(dplyr) 
library(tidyr) 

DF1 %>% 
    mutate(id = 1:n()) %>% 
    separate_rows(letter_strings) %>% 
    left_join(DF2) %>% 
    group_by(id) %>% 
    summarise(letter_string = toString(letter_strings), codes = toString(code)) %>% 
    ungroup %>% 
    select(-id) 

donnant:

Joining, by = "letter_strings" 
# A tibble: 3 x 2 
     letter_string    codes 
       <chr>    <chr> 
1 abc, def, ghi, jkl YES, NO, MAYBE, SURE 
2   mno, pqr  PERHAPS, ALWAYS 
3  stu, vw, xyz NEVER, NOGO, ABSENT 

3) StrSplit/fusion/ agrégat Utilisation strsplit pour diviser les chaînes en DF1 et stack que dans la forme longue st. Puis merge cela avec DF2 et aggregate de nouveau à la forme originale. Aucun paquet n'est utilisé.

s <- strsplit(DF1$letter_strings, ", ") 
st <- stack(setNames(s, seq_along(s))) 
m <- merge(st, DF2, by = 1, all.x = TRUE, all.y = FALSE) 
aggregate(. ~ ind, m, toString)[-1] 

donnant:

   values     code 
1 abc, def, ghi, jkl YES, NO, MAYBE, SURE 
2   mno, pqr  PERHAPS, ALWAYS 
3  stu, vw, xyz NEVER, NOGO, ABSENT 

3a) magrittr Cela pourrait être exprimé à l'aide magrittr:

library(magrittr) 

DF1 %>% 
    "$"("letter_strings") %>% 
    strsplit(", ") %>% 
    setNames(seq_along(.)) %>% 
    stack %>% 
    merge(DF2, by = 1, all.x = TRUE, all.y = FALSE) %>% 
    aggregate(. ~ ind, ., toString) %>% 
    "["(-1) 


s <- stack(setNames(strsplit(DF1$letter_strings, ", "), 1:nrow(DF1))) 
m <- merge(s, DF2, by = 1, all.x = TRUE, all.y = FALSE) 
aggregate(. ~ ind, m, toString)[-1] 

4) data.table Notez que dans un commentaire ci-dessous que @ Uwe a fourni une version data.table de l'approche de (2) et (3) qui consiste à convertir en forme longue, rejoindre et convertir arrière.

Note: entrées sous forme reproductible:

Lines1 <- " 
letter_strings 
abc, def, ghi, jkl 
mno, pqr 
stu, vw, xyz" 
DF1 <- read.table(text = Lines1, header = TRUE, as.is = TRUE, sep = ";") 

Lines2 <- " 
letter_strings code 
abc YES 
def NO 
ghi MAYBE 
jkl SURE 
mno PERHAPS 
pqr ALWAYS 
stu NEVER 
vw NOGO 
xyz ABSENT" 
DF2 <- read.table(text = Lines2, header = TRUE, as.is = TRUE) 
+0

Merci! Votre solution est parfaite pour ce dont j'ai besoin! –

+0

Si vous voulez ajouter une version 'data.table' de * reshape à long, rejoignez, reshape à wide *:' library (data.table); setDT (DF1); setDT (DF2); DF2 [DF1 [, rn: = .I] [, strsplit (chaîne_fichiers, ",", fixed = TRUE), par = rn], on =. (Chaîne_fichiers = V1)] [, lapply (.SD, toString), par = rn] [, - "rn"] ' – Uwe