【问题标题】:R - data.table fast lookup with regexR - 使用正则表达式快速查找 data.table
【发布时间】:2020-08-11 08:25:57
【问题描述】:

具有两列(3-grams 及其计数)的 data.table,在 ngrams 列上设置了一个键。 3-gram 是由空格分隔的三个单词的单个字符向量。

set.seed(20182)

create.ngrams <- function(){
        w1 <- paste(sample(letters[1:5], 3, T), collapse = '')
        w2 <- paste(sample(letters[1:5], 3, T), collapse = '')
        w3 <- paste(sample(letters, 5, T), collapse = '')

        ngram <- paste(c(w1, w2, w3), collapse = " ")
        return(ngram)
}

dt <- data.table(ngrams = replicate(100000, create.ngrams()), N = sample.int(100, 100000, replace=T))

dt[ngrams %like% '^ada cab \\.*']

我需要得出的是,给定一个 2-gram,在以 2-gram 为词干的 3-gram 表中出现了多少个唯一的 3-gram?到目前为止的方法是过滤 3-gram 表并使用正则表达式和 data.table %like% 函数获取行数。不幸的是,documentation 声明 like 没有使用表键。

注意:当前实现不使用排序键。

这大大减慢了过滤速度:

dt[ngrams %like% '^ada cab \\.*']

          ngrams  N
1: ada cab jsfzb 33
2: ada cab rbkqz 43
3: ada cab oyohg 10
4: ada cab dahtd 87
5: ada cab qgmfb  8
6: ada cab ylyfl 13
7: ada cab izeje 83
8: ada cab fukov 12

microbenchmark(dt[ngrams %like% '^ada cab \\.*']))

Unit: milliseconds
                                expr     min      lq     mean  median       uq     max neval
 dt[ngrams %like% "^ada cab \\\\.*"] 22.4061 23.9792 25.89883 25.0981 26.88145 34.7454   100

在我正在使用的实际表 (nrow = 46856038) 上,性能太慢而无法完成我的任务:

Unit: seconds
                              expr      min       lq     mean   median       uq      max neval
 t[ngrams %like% "^on the \\\\.*"] 10.48471 10.57198 11.27199 10.77015 10.94827 17.42804   100

我可以做些什么来提高性能?我尝试与dplyr 一起工作,但收益似乎并不显着。

【问题讨论】:

  • 冒险猜测。你有什么样的记忆?您是否可以将 3-gram 拆分为 3 列,然后键入这 3 列并在第 1&2 或 2&3 列中搜索 2-gram?
  • 使用你的set.seed 我得到了不同的起始条件。这里还有别的吗? (R-3.5.3,win10)(此外,您在第一个和第二个代码块中都有一些错误的右括号。)
  • @r2evans win10 和 R 版本 3.6.1,但不知道这些可能会影响种子启动条件。​​
  • 我不知道他们会这样做,但是随着最近发布的 R-4.0,我想如果您使用的是该版本,这可能会有所不同。 *耸耸肩*

标签: r filter data.table regexp-like


【解决方案1】:

您可以使用fixed= 模式吗?如果你在所有ngrams 前面加上一个空格,它会给你一个虚拟的“单词边界”,让你做一个更快的模式:

dt[, ngrams1 := paste0(" ", ngrams)]
dt
#                ngrams  N        ngrams1
#      1: dcd aee vxfba 99  dcd aee vxfba
#      2: cad bec alsmv 92  cad bec alsmv
#      3: ebe edd zbogd 90  ebe edd zbogd
#      4: aac ace miexa 26  aac ace miexa
#      5: aea cda ppyii 67  aea cda ppyii
#     ---                                
#  99996: cca bbc xaezc 58  cca bbc xaezc
#  99997: ebc cae ktacb 95  ebc cae ktacb
#  99998: bed abe dpjmc 92  bed abe dpjmc
#  99999: dde cdb frkfz 79  dde cdb frkfz
# 100000: bed bce ydawa 52  bed bce ydawa

dt[ngrams %like% '^ada cab \\.*']
#           ngrams  N        ngrams1
# 1: ada cab qbbiw 22  ada cab qbbiw
# 2: ada cab kpejz 16  ada cab kpejz
# 3: ada cab lighh  4  ada cab lighh
# 4: ada cab rxpmc 64  ada cab rxpmc

dt[grepl(' ada cab ', ngrams1, fixed = TRUE),]
#           ngrams  N        ngrams1
# 1: ada cab qbbiw 22  ada cab qbbiw
# 2: ada cab kpejz 16  ada cab kpejz
# 3: ada cab lighh  4  ada cab lighh
# 4: ada cab rxpmc 64  ada cab rxpmc

在基准测试中,固定模式的速度要快 3-4 倍:

microbenchmark::microbenchmark(
  a = dt[ngrams %like% '^ada cab \\.*'],
  b = dt[grepl('^ada cab', ngrams),],
  c = dt[ngrams1 %flike% ' ada cab ', ],
  d = dt[grepl(' ada cab ', ngrams1, fixed = TRUE),]
)
# Unit: milliseconds
#  expr       min        lq      mean    median        uq       max neval
#     a 20.299101 21.364401 22.088702 21.832000 22.444351 25.403801   100
#     b 20.605501 21.648101 22.656212 22.382001 23.384151 26.330201   100
#     c  4.337301  4.872151  5.265142  5.125251  5.500951  9.646201   100
#     d  4.301901  4.860501  5.221697  5.102000  5.465402  7.339400   100

如果模式偏离 3-3-5(例如,如果您有更多 3,这可能会意外匹配而不是前几个 3)。

【讨论】:

  • ConnerM.,这能解决你的问题吗?
猜你喜欢
  • 2013-06-23
  • 2013-05-31
  • 2017-07-29
  • 2021-11-01
  • 1970-01-01
  • 2011-05-16
  • 2016-01-15
  • 2011-12-24
  • 1970-01-01
相关资源
最近更新 更多