Dividir cadena de texto en un dato.columnas de la tabla
Tengo un script que lee los datos de un archivo CSV en un data.table
y 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 nuevas columnas PX
y PY
en el carácter"_".
A pesar de que esto funciona bien, me preguntaba si hay una mejor (más eficiente) manera 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.
ACTUALIZACIÓN:
Siguiendo la sugerencia de @Frank, creé un caso de prueba más grande y usé los comandos sugeridos, pero el stringr::str_split_fixed
toma 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
Así que el método str_split_fixed
tarda unas 20 veces más.
5 answers
Actualización: Desde la versión 1.9.6 (en CRAN a partir de Sep ' 15), 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 una envoltura para transpose(strsplit())
, donde la función transpose()
, también implementada recientemente, transpone una lista. Por favor, ver ?tstrsplit()
y ?transpose()
para ejemplos.
Vea la historia para las respuestas antiguas.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-16 14:16:17
I añadir respuesta para alguien que no use data.table
v1.9.5 y también quiere una línea de solución.
dt[, c('PX','PY') := do.call(Map, c(f = c, strsplit(PREFIX, '-'))) ]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-01 07:48:26
Usando 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-16 20:07:09
Con tidyr la solución es:
separate(df,col = "PREFIX",into = c("PX", "PY"), sep = "_")
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-30 13:12:32
¿Sobre qué ??? fread (text = dt PREF PREFIX)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-04 16:40:20