快速分割字符串并在data.table中转换为长格式

RIn*_*atM 7 substring r data-manipulation data.table

我做了以下事情

library(data.table)
library(stringr)        
dt <- data.table(string_column = paste(sample(c(letters, " "), 500000, replace = TRUE)
                                     , sample(c(letters, " "), 500000, replace = TRUE)
                                     , sample(1:500000)
                                 , sep = " "), key = "string_column") 

split_res <- dt[, list(name = unlist(str_split(string_column, '\\s+'))), by = string_column]
Run Code Online (Sandbox Code Playgroud)

对于真实数据,它需要大约.1小时处理dt(10M行)并创建split_res(18M行)出于好奇 - 有没有办法加快进程?也许unlist + str_split这不是正确的方法吗?

A5C*_*2T1 11

如果您只是使用str_split()"stringr"并且只是使用,那么您将获得大幅加速strsplit().

fun1 <- function() dt[, list(name = unlist(str_split(string_column, '\\s+'))), by = string_column]
fun2 <- function() dt[, list(name = unlist(strsplit(string_column, '\\s+'))), by = string_column]

system.time(fun1())
#    user  system elapsed 
#  172.41    0.05  172.82 

system.time(fun2())
#    user  system elapsed 
#   11.22    0.01   11.23 
Run Code Online (Sandbox Code Playgroud)

这是否会使您的处理时间从一小时缩短到4分钟,我不确定.但至少你不必记得在你的函数名称中加入那些令人讨厌的下划线:-)


如果你可以拆分固定的搜索模式,你可以使用fixed = TRUE参数,这将为你提供另一个显着的速度提升.


另一件需要考虑的事情是手动完成这个过程:

x <- strsplit(dt$string_column, "\\s+")
DT <- dt[rep(sequence(nrow(dt)), vapply(x, length, 1L))]
DT[, name := unlist(x, use.names = FALSE)]
DT
Run Code Online (Sandbox Code Playgroud)

使用您的示例数据:

fun4 <- function() {
  x <- strsplit(dt$string_column, "\\s+")
  DT <- dt[rep(sequence(nrow(dt)), vapply(x, length, 1L))]
  DT[, name := unlist(x, use.names = FALSE)]
  DT
}
#    user  system elapsed 
#    1.79    0.01    1.82
Run Code Online (Sandbox Code Playgroud)

但是,答案与我所得到的不一样fun2(),但那是因为你在"string_column"中有重复的值.如果添加"id"列并执行相同操作,则会得到相同的结果.