Разделить текстовую строку в данных.столбец таблицы
у меня есть скрипт, который считывает данные из csv файла в data.table а затем разбивает текст в одном столбце на несколько новых столбцов. В настоящее время я использую lapply и strsplit функции для этого. Вот пример:
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
в примере выше столбца PREFIX разбивается на две новые колонки PX и PY на "_" символ.
хотя это работает просто отлично, мне было интересно, есть ли лучший (более эффективный) способ сделать это используя data.table. Мои реальные наборы данных имеют > =10M+ строк, поэтому эффективность времени/памяти становится действительно важной.
обновление:
следуя предложению @ Frank Я создал более крупный тестовый случай и использовал предложенные команды, но stringr::str_split_fixed занимает намного больше времени, чем оригинальный метод.
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
так str_split_fixed метод занимает около 20 раз больше времени.
5 ответов:
обновление: из версии 1.9.6 (на CRAN по состоянию на 15 сентября), мы можем использовать функцию
tstrsplit()чтобы получить результаты напрямую (и гораздо более эффективным способом):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()в основном это обертка дляtranspose(strsplit()), гдеtranspose()функция, также недавно реализованная, транспонирует список. Пожалуйста, смотрите?tstrsplit()и?transpose()для примера.смотрите историю для старых ответов.
Я добавляю ответ для тех, кто не использует
data.tableВ1.9.5 а также хотите однолинейное решение.dt[, c('PX','PY') := do.call(Map, c(f = c, strsplit(PREFIX, '-'))) ]
используя
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
Comments