【问题标题】:Split text string in a data.table columns在 data.table 列中拆分文本字符串
【发布时间】:2013-08-11 20:24:03
【问题描述】:

我有一个脚本,它将 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 倍的时间。

【问题讨论】:

  • 我认为先在 data.table 之外进行操作可能会更好。如果您使用stringr 包,这是命令:str_split_fixed(PREFIX,"_",2)。我没有回答,因为我还没有测试加速......或者,一步:dt[,c("PX","PY"):=data.table(str_split_fixed(PREFIX,"_",2))]

标签: r data.table


【解决方案1】:

更新:从版本 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()

查看历史以获取旧答案。

【讨论】:

  • 谢谢阿伦。我没有想到先创建列表,然后是索引,然后是“a_spl”中描述的列的方法。我一直认为在一行中完成所有事情是最好的方法。只是出于好奇,为什么索引方式工作得这么快?
  • @Arun,与这个问题相关,你会在我在这里写的函数中看到哪些陷阱:gist.github.com/mrdwab/6873058 基本上,我已经使用了fread,但要这样做,我必须使用tempfile(这似乎是一个瓶颈),因为fread 似乎没有与text 参数等效。使用此示例数据进行测试,其性能介于您的 a_spla_sub 方法之间。
  • 我想知道如何猜测 := 的 LHS 上的列数并根据出现的 grep tstrsplit 动态创建 new 列的名称
  • 有没有一种有效的方法可以使用这种方法一次性删除原始 PREFIX 列?我的意思是,与链接或单独操作相比,这可能更快或使用更少的内存。
【解决方案2】:

我为不使用 data.tablev1.9.5 并且还想要单行解决方案的人添加答案。

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      我们可以试试:

      library(data.table)  
      cbind(dt, fread(text = dt$PREFIX, sep = "_", header = FALSE))
          #    PREFIX VALUE V1 V2
          # 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
      

      【讨论】:

        【解决方案5】:

        使用 tidyr 的解决方案是:

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

        【讨论】:

        • 该问题专门针对 data.table 解决方案。在这个领域工作的人已经选择了 data.table 解决方案而不是 tidyr 解决方案,这是有充分理由考虑到他们所面临的挑战的。
        • 其他用户也提供了其他库的解决方案,我刚刚给出了一个有效的替代方案,简单快捷。
        猜你喜欢
        • 1970-01-01
        • 2016-08-07
        • 1970-01-01
        • 1970-01-01
        • 2017-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-14
        相关资源
        最近更新 更多