2017-10-05 4 views
0

J'ai une trame de données composée de plusieurs lignes, et je voudrais diviser chaque ligne en deux composants basés sur des éléments d'un vecteur (exécutez essentiellement strsplit avec un vecteur comme le « modèle ») dans l'affaire R.Chaîne fractionnement d'une trame de données avec un vecteur comme motif dans R

la trame de données (une seule colonne) ressemble à quelque chose comme ceci:

 [,1]     
[1,] "apple please fuji" 
[2,] "pear help name"  
[3,] "banana me mango" 

Alors que mon vecteur de modèle pourrait ressembler à ceci: v <- c("please", "help", "me").

Si possible, je voudrais que ma fin sortie être:

df$name    df$part1 df$split df$part2 
"apple please fuji" "apple" "please" "fuji" 
"pear help name" "pear"  "help" "name" 
"banana me mango" "banana" "me"  "mango" 

Je vous serais reconnaissant toute aide à l'entre-deux pas d'être en mesure de composants isoler la base d'un vecteur, mais si est un moyen encore plus facile de le mettre dans un dataframe, ce serait génial! Merci beaucoup!

+0

Si la première rangée était ' "pomme rouge vous plaît fuji"', aurait pour conséquence être 'c ("pomme rouge", "PLEASE", "fuji") '? – zx8754

+0

@ zx8754, oui, c'est ce que j'espère! Je voudrais juste isoler trois catégories (indépendamment du nombre de mots): avant la chaîne de division, la chaîne de division, et après la chaîne de division. Merci! – maria

Répondre

2

Voici deux méthodes dans la base R.

Démarrer avec un vecteur de caractères:

text <- c("apple please fuji", "pear help name", "banana me mango") 

En outre, les noms de variables souhaitées (pour plus de commodité)

varNames <- c("name", "part1", "split", "part2") 

utilisant regexec et regmatches

Comme alternative, vous pouvez également utiliser des expressions régulières avec le regmatches/regexec combinaison pour construire cet ensemble de données.

D'abord, créez une expression régulière à partir de v avec paste.

myRegex <- paste0("^(.*) +(", paste(v, collapse="|"), ") +(.*)$") 
myRegex 
[1] "^(.*)(please|help|me)(.*)$" 

setNames(do.call(rbind.data.frame, regmatches(text, regexec(myRegex, text))), varNames) 

cela renvoie le même que ci-dessus

   name part1 split part2 
1 apple please fuji apple please fuji 
2 pear help name pear help name 
3 banana me mango banana  me mango 

utilisant strsplit et do.call

d'abord, diviser chaque élément par v

tmp <- do.call(strsplit, list(text, split=v)) 
tmp 
[[1]] 
[1] "apple " " fuji" 

[[2]] 
[1] "pear " " name" 

[[3]] 
[1] "banana " " mango" 

Maintenant, rbind.data.frame ceux-ci, qui supprime la deuxième colonne, et renvoie un data.frame cbind les variables de division et de nom, puis ajouter des noms avec setNames.

setNames(cbind(text, do.call(rbind.data.frame, tmp), v)[c(1, 2, 4, 2)], varNames) 

ce retour

   name part1 split part2 
1 apple please fuji apple please apple 
2 pear help name pear help pear 
3 banana me mango banana  me banana 

1

Cette solution suppose que le nombre d'éléments dans v est égal au nombre de lignes dans la trame de données. Vous pouvez utiliser separate à partir du package tidyr pour créer part1 et part2.

library(tidyverse) 
df <- tibble(name = c("apple please fuji", "pear help name", "banana me mango")) 
v <- c("please", "help", "me") 

df %>% 
    separate(name, c("part1", "part2"), v, remove = FALSE) %>% 
    add_column(split = v, .before = "part2") 
#> # A tibble: 3 x 4 
#>    name part1 split part2 
#>    <chr> <chr> <chr> <chr> 
#> 1 apple please fuji apple please fuji 
#> 2 pear help name pear help name 
#> 3 banana me mango banana  me mango 

Si vous voulez essayer de diviser chaque ligne en utilisant tout élément dans v vous pourriez essayer de coller v en un seul premier motif avant de se séparer. Je pense que quelque chose comme ça devrait fonctionner.

library(tidyverse) 
library(stringr) 
p <- paste0("\\b(?:", paste(v, collapse = "|"), ")\\b") 
df %>% 
    separate(name, c("part1", "part2"), p, remove = FALSE) %>% 
    mutate(split = str_extract(name, p)) %>% 
    select(name, part1, split, part2) 
#> # A tibble: 3 x 4 
#>    name part1 split part2 
#>    <chr> <chr> <chr> <chr> 
#> 1 apple please fuji apple please fuji 
#> 2 pear help name pear help name 
#> 3 banana me mango banana  me mango 
0
# Creating creating the df 
name <- c("apple please fuji","pear help name","banana me mango") 

# as.data.frame 
df <- as.data.frame(name, stringsAsFactors = F) 
# Initialize empty data frame. 
df_n <- data.frame() 
# Loop through the original rows of the df. 
for(i in 1:nrow(df)){ 
    for(j in 1:nrow(df)){ 
    o <- strsplit(df$name, " ")[[i]][j] 
    } 
} 
# rename and assign new df (df_n) changes to original df. 
df$part1 <- df_n$V1 
df$part2 <- df_n$V2 
df$part3 <- df_n$V3 

print(df) 
+0

Merci pour ça! Les boucles sont assez lentes, et la taille de mes données est assez grande, donc malheureusement, cela ne fonctionnera pas pour moi. Avez-vous des idées sur la façon de vectoriser cela, peut-être en utilisant appliquer? Je vous remercie! – maria