首页 文章

在data.table列中拆分文本字符串

提问于
浏览
62

我有一个脚本,将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  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 列被分成"_"字符上的两个新列 PXPY .

虽然这很好用,但我想知道是否有更好(更有效)的方法来使用 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

    Update: 从版本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  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() .

    查看旧答案的历史记录 .

  • 12

    我为那些不使用 data.table v1.9.5 并且想要一行解决方案的人添加答案 .

    dt[, c('PX','PY') := do.call(Map, c(f = c, strsplit(PREFIX, '-'))) ]
    
  • 0

    使用 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
    
  • 79

    有了tidyr,解决方案是:

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

    关于什么 ??? fread(text = dt $ PREFIX)

相关问题