J'ai un script qui lit les données d'un fichier CSV dans un data.table
et divise ensuite le texte d'une colonne en plusieurs nouvelles colonnes. J'utilise actuellement les fonctions lapply
et strsplit
pour le 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 A B
# 2: A_C 2 A C
# 3: A_D 3 A D
# 4: B_A 4 B A
# 5: B_C 5 B C
# 6: B_D 6 B D
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 existait un moyen plus efficace (plus efficace) d'utiliser data.table
. Mes véritables ensembles de données ont> = 10 millions de lignes +, l'efficacité en termes de temps/mémoire devient donc vraiment importante.
Suivant la suggestion de @ Frank, j'ai créé un scénario de test plus volumineux et utilisé les commandes suggérées, mais le stringr::str_split_fixed
prend beaucoup plus de temps que la méthode d'origine.
library("data.table")
library("stringr")
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 à compter du 15 septembre), 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 A B
# 2: A_C 2 A C
# 3: A_D 3 A D
# 4: B_A 4 B A
# 5: B_C 5 B C
# 6: B_D 6 B D
tstrsplit()
est essentiellement un wrapper pour transpose(strsplit())
, où la fonction transpose()
, également récemment mise en œuvre, transpose une liste. S'il vous plaît voir ?tstrsplit()
et ?transpose()
pour des exemples.
Voir l'historique pour les anciennes réponses.
J'ajoute answer pour quelqu'un qui n'utilise pas data.table
v1.9.5 et qui veut aussi une solution sur une ligne.
dt[, c('PX','PY') := do.call(Map, c(f = c, strsplit(PREFIX, '-'))) ]
Utilisation du package splitstackshape
:
library(splitstackshape)
cSplit(df, splitCols = "PREFIX", sep = "_", direction = "wide", drop = FALSE)
# PREFIX VALUE PREFIX_1 PREFIX_2
# 1: A_B 1 A B
# 2: A_C 2 A C
# 3: A_D 3 A D
# 4: B_A 4 B A
# 5: B_C 5 B C
# 6: B_D 6 B D
Avec tidyr, la solution est la suivante:
separate(df,col = "PREFIX",into = c("PX", "PY"), sep = "_")