gsub 速度与图案长度

Posted

技术标签:

【中文标题】gsub 速度与图案长度【英文标题】:gsub speed vs pattern length 【发布时间】:2015-02-16 12:21:57 【问题描述】:

我最近一直在广泛使用gsub,我注意到短模式比长模式运行得更快,这并不奇怪。这是一个完全可重现的代码:

library(microbenchmark)
set.seed(12345)
n = 0
rpt = seq(20, 1461, 20)
msecFF = numeric(length(rpt))
msecFT = numeric(length(rpt))
inp = rep("aaaaaaaaaa",15000)

for (i in rpt) 
  n = n + 1
  print(n)
  patt = paste(rep("a", rpt[n]), collapse = "")
  #time = microbenchmark(func(count[1:10000,12], patt, "b"), times = 10)
  timeFF = microbenchmark(gsub(patt, "b", inp, fixed=F), times = 10)
  msecFF[n] = mean(timeFF$time)/1000000.

  timeFT = microbenchmark(gsub(patt, "b", inp, fixed=T), times = 10)
  msecFT[n] = mean(timeFT$time)/1000000.


library(ggplot2)
library(grid)
library(gridExtra)

axis(1,at=seq(0,1000,200),labels=T)

p1 = qplot(rpt, msecFT, xlab="pattern length, characters", ylab="time, msec",main="fixed = TRUE" )
p2 = qplot(rpt, msecFF, xlab="pattern length, characters", ylab="time, msec",main="fixed = FALSE")
grid.arrange(p1, p2, nrow = 2)

如您所见,我正在寻找一个包含a 复制rpt[n] 次的模式。正如预期的那样,斜率为正。但是,我注意到fixed=T 有 300 个字符,fixed=F 有 600 个字符,然后斜率似乎与以前大致相同(见下图)。 我想,这是由于内存、对象大小等原因。我还注意到pattern 允许的最长符号是 1463 个符号,对象大小为 1552 字节。

谁能更好地解释一下这个问题以及为什么在 300 和 600 个字符处?

补充:值得一提的是,我的大多数模式都是 5-10 个字符长,这为我的真实数据(不是上面示例中的模型 inp)提供了以下时间。

gsub, fixed = TRUE: ~50 msec per one pattern
gsub, fixed = FALSE: ~190 msec per one pattern
stringi, fixed = FALSE: ~55 msec per one pattern
gsub, fixed = FALSE, perl = TRUE: ~95 msec per one pattern

(我有 4k 模式,所以我的模块的总时间大约是 200 秒,这恰好是 0.05 x 4000 与 gsub 和固定 = TRUE。这是我的数据和模式最快的方法)

【问题讨论】:

根本不是您问题的答案,但有趣的是看到stringi等效于stringiF <- microbenchmark(stri_replace_all_fixed(str = inp, pattern = patt, replacement = "b"), times = 10); mean_stringiF[n] <- mean(stringiF$time)/1000000; qplot(rpt, mean_stringiF),显示没有类似的图案长度增加,至少没有超过这里测试的范围。 如果我在gsubfixed=FALSE 中使用perl=TRUE,我也看不到斜率(fixed = TRUE 无关紧要)。但是,我确实需要使用 fixed = TRUE,因为它在我的应用程序中要快得多 我知道为什么stri_replace 函数的执行时间会在 5 处跳跃 :) 因为对于大于或等于 5 的模式,使用了 KMP 算法。对于短于 5 的模式,简单的搜索就完成了。 如果您的域从 n=2 而不是 n=1 开始,您的绘图会更清晰。更清洁是指感兴趣的区域将拥有图表上的大部分空间。 有什么问题? 【参考方案1】:

扭结可能与保持该长度模式所需的位有关。

还有另一种解决方案可以更好地扩展,使用重复运算符 来指定要查找的重复次数。为了找到超过 255 个(最大 8 位整数),您必须指定 perl = TRUE

patt2 <- paste0('a',rpt[n],'')
timeRF <- microbenchmark(gsub(patt2, "b", inp, perl = T), times = 10)

每次搜索的速度约为 2.1 毫秒,而模式长度没有任何损失。对于小图案长度,这比 fixed = FALSE 快约 8 倍,对于大图案长度,快约 60 倍。

【讨论】:

感谢您的想法。不幸的是,我所有的模式都是独一无二的,通常只是没有重复的常规单词。对于我的应用程序,由于可能伴随目标的其他字符(例如“大写字母”等),fixed=FALSE 提供了最正确(尽管比 fixed=TRUE 慢)的解决方案 这是一个活生生的例子。 a = "appless, appless. apples- 。我需要将“apples”更改为“apple”,保持所有标点符号不变。我有另一个线程,为什么以及我需要做什么:***.com/questions/27367914/…

以上是关于gsub 速度与图案长度的主要内容,如果未能解决你的问题,请参考以下文章

打印各种图案~

由围绕矩形形状顺时针方向移动的数字组成的图案(长度和宽度每次减小)[关闭]

Springboot 系列动态Banner与图片转字符图案的手动实现

c++打印数字图案?

CAD2014学习笔记-图层图案图块

scratch如何让画笔绘制的图案移动?