Tengo una secuencia de comandos que lee datos de un archivo CSV en data.tableay luego divide el texto en una columna en varias columnas nuevas. Actualmente estoy usando las funciones lapplyy strsplitpara 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 PREFIXse divide en dos columnas nuevas PXy PYen 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_fixedlleva 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_fixedmétodo tarda unas 20 veces más.
fuente

stringrpaquete, 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 Dtstrsplit()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 quefreadtenga un equivalente a untextargumento. Al probar con estos datos de muestra, su rendimiento está entre sus enfoquesa_splya_sub.Agrego una respuesta para alguien que no usa
data.tablev1.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
splitstackshapepaquete: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 Dfuente
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 Dfuente
Con tidyr la solución es:
separate(df,col = "PREFIX",into = c("PX", "PY"), sep = "_")fuente