2015-12-17 4 views
1

J'ai la trame de donnéesdiviser une colonne de chaîne dans plusieurs colonnes

df=data.frame(x=rnorm(8),y=runif(8),longstring=c("foo_100_Case1","foo_125_Case1","bar_100_Case1","bar_125_Case1","foo_100_Case2","foo_125_Case2","bar_100_Case2","bar_125_Case2"),stringsAsFactors = F) 

J'ai besoin de diviser la dernière colonne en trois colonnes, avec delimiter « _ ». Je fais ce qui suit:

a=matrix(unlist(strsplit(df$longstring,"_",fixed=T)),8,3,byrow = T) 
df$type=a[,1] 
df$point=a[,2] 
df$case=a[,3] 

Mais je me demande s'il y a un moyen plus facile: la combinaison de strsplit et unlist est particulièrement délicate, et il ne fait pas le code très lisible.

+1

La fonction 'separate' dans le package ** tidyr ** a été spécialement écrit pour cela. – joran

Répondre

4

Vous pouvez essayer,

cbind(df[-3], data.frame(do.call('rbind', strsplit(df$longstring,'_')))) 

# x    y X1 X2 X3 
#1 -0.5522704 0.9998266 foo 100 Case1 
#2 1.1907351 0.8979460 foo 125 Case1 
#3 0.6005691 0.4301610 bar 100 Case1 
#4 -1.0698081 0.9626781 bar 125 Case1 
#5 -0.8526932 0.9634738 foo 100 Case2 
#6 0.0100209 0.2968137 foo 125 Case2 
#7 -1.5051358 0.7012956 bar 100 Case2 
#8 1.0892584 0.4655736 bar 125 Case2 

La fonction do.call vous permet d'appeler toutes les fonctions de R et au lieu d'envoyer l'argument un par un, vous pouvez utiliser une liste pour tenir les arguments. Plus d'info ?do.call. Le do.call renvoie uniquement les colonnes X1, X2 et X3 et pour obtenir votre cadre de données d'origine j'utilise cbind pour lier les colonnes d'origine. Le strsplit comme vous le savez déjà scinde la chaîne sur _.


Ou comme @joran mentionné, vous pouvez utiliser separate du package tidyr comme

library(tidyr) 
separate(df, longstring, c("X1", "X2", "X3"), sep="_") 

# x    y X1 X2 X3 
#1 -0.5522704 0.9998266 foo 100 Case1 
#2 1.1907351 0.8979460 foo 125 Case1 
#3 0.6005691 0.4301610 bar 100 Case1 
#4 -1.0698081 0.9626781 bar 125 Case1 
#5 -0.8526932 0.9634738 foo 100 Case2 
#6 0.0100209 0.2968137 foo 125 Case2 
#7 -1.5051358 0.7012956 bar 100 Case2 
#8 1.0892584 0.4655736 bar 125 Case2 
+0

Certainement plus lisible que le mien, et j'aime bien que vous jetiez 'df $ longstring'. Pouvez-vous s'il vous plaît expliquer votre code, cependant? Qu'est-ce que 'do.call'? Pourquoi avez-vous besoin de 'cbind' et' rbind'? Pourquoi dans votre code avez-vous besoin de 'as.character', alors que dans le mien je peux directement écrire' strsplit (df $ longstring ...) '? – DeltaIV

+1

Ok, j'aime mieux la syntaxe 'tidyr'. Habituellement, je n'aime pas installer des paquets pour faire des choses qui peuvent être faites dans la base R, mais j'aime vraiment le fait que 'tidyr' me permet de séparer et de renommer les colonnes en une seule fois. Et la syntaxe est beaucoup plus lisible! – DeltaIV

+0

@DeltaIV vous avez raison, 'tidyr' est plus lisible et aussi il n'y a pas besoin de' as.character' dans 'strsplit', donc mis à jour –

6

Voici quelques options pour essayer:

Mon paquet "splitstackshape" est conçu pour cette genre de choses ...

library(splitstackshape) 
cSplit(df, "longstring", "_") 
#    x   y longstring_1 longstring_2 longstring_3 
# 1: -1.41524742 0.2123978   foo   100  Case1 
# 2: -1.09240237 0.3899935   foo   125  Case1 
# 3: 0.39675025 0.2162463   bar   100  Case1 
# 4: -1.14996728 0.7608128   bar   125  Case1 
# 5: -0.07657172 0.6878348   foo   100  Case2 
# 6: 0.29549599 0.2216566   foo   125  Case2 
# 7: 1.78622612 0.1496666   bar   100  Case2 
# 8: -0.11749579 0.9255409   bar   125  Case2 

Le paquet « data.table » nous apporte la fonction tstrsplit rapide ...

library(data.table) 
as.data.table(df)[ 
    , paste0("V", 1:3) := tstrsplit(longstring, "_")][ 
    , longstring := NULL][] 

Si vous avez le temps et que vous voulez attendre read.table faire son travail ...

cbind(df[1:2], read.table(text = df$longstring, sep = "_")) 

Si yo u besoin de quelque chose d'autre qui est rapide ...

library(iotools) 
cbind(df[1:2], mstrsplit(df$longstring, sep = "_"))