在data.table列中分割文本string

我有一个脚本,它将CSV文件中的数据读入到data.table ,然后将一列中的文本分成几个新列。 我目前使用lapplystrsplit函数来做到这一点。 这是一个例子:

 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 AB # 2: A_C 2 AC # 3: A_D 3 AD # 4: B_A 4 BA # 5: B_C 5 BC # 6: B_D 6 BD 

在上面的例子中, PREFIX列在“_”字符上被分成两个新的列PXPY

即使这工作得很好,我想知道是否有一个更好(更有效率)的方法来做到这一点使用data.table 。 我的真实数据集有> = 10M +行,所以时间/内存效率变得非常重要。


更新:

在Frank的build议之后,我创build了一个更大的testing用例,并使用了build议的命令,但是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倍的时间。

更新:从版本1.9.6(在2015年9月的CRAN上),我们可以使用函数tstrsplit()直接得到结果(并且以更高效的方式):

 require(data.table) ## v1.9.6+ dt[, c("PX", "PY") := tstrsplit(PREFIX, "_", fixed=TRUE)] # PREFIX VALUE PX PY # 1: A_B 1 AB # 2: A_C 2 AC # 3: A_D 3 AD # 4: B_A 4 BA # 5: B_C 5 BC # 6: B_D 6 BD 

tstrsplit()基本上是一个transpose(strsplit())的包装,最近也实现了transpose()函数转置一个列表。 例如,请参阅?tstrsplit()?transpose()

查看旧的答案的历史。

我为没有使用data.table人添加了答案,也希望有一个单行的解决scheme。

 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 AB # 2: A_C 2 AC # 3: A_D 3 AD # 4: B_A 4 BA # 5: B_C 5 BC # 6: B_D 6 BD 

用tidyr解决scheme是:

 separate(df,col = "PREFIX",into = c("PX", "PY"), sep = "_")