Fractionner une chaîne de texte dans une colonne data.table

J’ai un script qui lit les données d’un fichier CSV dans un fichier data.table , puis divise le texte en une colonne en plusieurs nouvelles colonnes. J’utilise actuellement les fonctions lapply et strsplit pour ce faire. Voici un exemple:

 library("data.table") df = data.table(PREFIX = c("A_B","A_C","A_D","B_A","B_C","B_D"), VALUE = 1:6) dt = as.data.table(df) # split PREFIX into new columns dt$PX = as.character(lapply(strsplit(as.character(dt$PREFIX), split="_"), "[", 1)) dt$PY = as.character(lapply(strsplit(as.character(dt$PREFIX), split="_"), "[", 2)) dt # PREFIX VALUE PX PY # 1: A_B 1 AB # 2: A_C 2 AC # 3: A_D 3 AD # 4: B_A 4 BA # 5: B_C 5 BC # 6: B_D 6 BD 

Dans l’exemple ci-dessus, la colonne PREFIX est divisée en deux nouvelles colonnes PX et PY sur le caractère “_”.

Même si cela fonctionne très bien, je me demandais s’il y avait une meilleure façon (plus efficace) de le faire en utilisant data.table . Mes jeux de données réels ont> = 10 millions de lignes, donc l’efficacité du temps / de la mémoire devient très importante.


METTRE À JOUR:

Suivant la suggestion de @Frank, j’ai créé un cas de test plus grand et utilisé les commandes suggérées, mais ssortingngr::str_split_fixed prend beaucoup plus de temps que la méthode d’origine.

 library("data.table") library("ssortingngr") system.time ({ df = data.table(PREFIX = rep(c("A_B","A_C","A_D","B_A","B_C","B_D"), 1000000), VALUE = rep(1:6, 1000000)) dt = data.table(df) }) # user system elapsed # 0.682 0.075 0.758 system.time({ dt[, c("PX","PY") := data.table(str_split_fixed(PREFIX,"_",2))] }) # user system elapsed # 738.283 3.103 741.674 rm(dt) system.time ( { df = data.table(PREFIX = rep(c("A_B","A_C","A_D","B_A","B_C","B_D"), 1000000), VALUE = rep(1:6, 1000000) ) dt = as.data.table(df) }) # user system elapsed # 0.123 0.000 0.123 # split PREFIX into new columns system.time ({ dt$PX = as.character(lapply(strsplit(as.character(dt$PREFIX), split="_"), "[", 1)) dt$PY = as.character(lapply(strsplit(as.character(dt$PREFIX), split="_"), "[", 2)) }) # user system elapsed # 33.185 0.000 33.191 

Donc, la méthode str_split_fixed prend environ 20 fois plus de temps.

Mise à jour: À partir de la version 1.9.6 (sur CRAN à partir de septembre 2015), nous pouvons utiliser la fonction tstrsplit() pour obtenir les résultats directement (et de manière beaucoup plus efficace):

 require(data.table) ## v1.9.6+ dt[, c("PX", "PY") := tstrsplit(PREFIX, "_", fixed=TRUE)] # PREFIX VALUE PX PY # 1: A_B 1 AB # 2: A_C 2 AC # 3: A_D 3 AD # 4: B_A 4 BA # 5: B_C 5 BC # 6: B_D 6 BD 

tstrsplit() est essentiellement un wrapper pour transpose(strsplit()) , où la fonction transpose() , également implémentée récemment, transpose une liste. S’il vous plaît voir ?tstrsplit() et ?transpose() pour des exemples.

Voir l’histoire pour les anciennes réponses.

J’ajoute une réponse pour quelqu’un qui n’utilise pas data.table v1.9.5 et qui souhaite une solution à une ligne.

 dt[, c('PX','PY') := do.call(Map, c(f = c, strsplit(PREFIX, '-'))) ] 

Utilisation splitstackshape package splitstackshape :

 library(splitstackshape) cSplit(df, splitCols = "PREFIX", sep = "_", direction = "wide", drop = FALSE) # PREFIX VALUE PREFIX_1 PREFIX_2 # 1: A_B 1 AB # 2: A_C 2 AC # 3: A_D 3 AD # 4: B_A 4 BA # 5: B_C 5 BC # 6: B_D 6 BD 

Avec tidyr la solution est:

 separate(df,col = "PREFIX",into = c("PX", "PY"), sep = "_")