Tengo una secuencia de comandos que lee datos de un archivo CSV en data.table
ay luego divide el texto en una columna en varias columnas nuevas. Actualmente estoy usando las funciones lapply
y strsplit
para hacer esto. He aquí un ejemplo:
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
En el ejemplo anterior, la columna PREFIX
se divide en dos columnas nuevas PX
y PY
en el carácter "_".
Aunque esto funciona bien, me preguntaba si hay una forma mejor (más eficiente) de hacer esto usando data.table
. Mis conjuntos de datos reales tienen> = 10M + filas, por lo que la eficiencia de tiempo / memoria se vuelve realmente importante.
ACTUALIZAR:
Siguiendo la sugerencia de @ Frank, creé un caso de prueba más grande y usé los comandos sugeridos, pero stringr::str_split_fixed
lleva mucho más tiempo que el método original.
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
Por tanto, el str_split_fixed
método tarda unas 20 veces más.
fuente
stringr
paquete, este es el comando:str_split_fixed(PREFIX,"_",2)
. No respondo porque no he probado la aceleración ... O, en un solo paso:dt[,c("PX","PY"):=data.table(str_split_fixed(PREFIX,"_",2))]
Respuestas:
Actualización: desde la versión 1.9.6 (en CRAN a partir de septiembre de 2015), podemos usar la función
tstrsplit()
para obtener los resultados directamente (y de una manera mucho más eficiente):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()
básicamente es un contenedor paratranspose(strsplit())
, donde latranspose()
función, también implementada recientemente, transpone una lista. Consulte?tstrsplit()
y?transpose()
para ver ejemplos.Consulte el historial para obtener respuestas antiguas.
fuente
fread
, pero para hacerlo, Tuve que usar untempfile
(que parecería ser un cuello de botella) ya que no parece quefread
tenga un equivalente a untext
argumento. Al probar con estos datos de muestra, su rendimiento está entre sus enfoquesa_spl
ya_sub
.Agrego una respuesta para alguien que no usa
data.table
v1.9.5 y también quiere una solución de una línea.dt[, c('PX','PY') := do.call(Map, c(f = c, strsplit(PREFIX, '-'))) ]
fuente
Usando el
splitstackshape
paquete: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
fuente
Podemos intentarlo:
cbind(dt, fread(text = dt$PREFIX, sep = "_", header = FALSE)) # PREFIX VALUE V1 V2 # 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
fuente
Con tidyr la solución es:
separate(df,col = "PREFIX",into = c("PX", "PY"), sep = "_")
fuente