我在R中有一个相当大的字符串集:
set.seed(42)
strings <- sapply(1:250000, function(x) sample(2:20, 1, prob=c(
0.001, 0.006, 0.021, 0.043, 0.075, 0.101, 0.127,
0.138, 0.132, 0.111, 0.087, 0.064, 0.042, 0.025, 0.014, 0.008,
0.004, 0.002, 0.001)))
strings <- lapply(strings, function(x) sample(letters, x, replace=TRUE))
strings <- sapply(strings, paste, collapse='')
我想从这些字符串中的子串列表中创建一个表示每个元素是否存在的列表。我的出发点当然是some code from stackoverflow:
#0.1 seconds
substrings <- sample(strings, 10)
system.time(matches <- lapply(substrings, grepl, strings, fixed=TRUE))
然而,对于更大的子串集合,这种方法有点幼稚,因为它存储了所有匹配和所有不匹配:
#13 seconds
substrings <- sample(strings, 1000)
system.time(matches <- lapply(substrings, grepl, strings, fixed=TRUE))
我们可以通过仅存储匹配来减小输出对象的大小:
#13 seconds
substrings <- sample(strings, 1000)
system.time(matches <- lapply(substrings, function(x) which(grepl(x, strings, fixed=TRUE))))
但对于大量的子串,这仍然很慢:
#316 seconds
substrings <- sample(strings, 25000)
system.time(matches <- lapply(substrings, function(x) which(grepl(x, strings, fixed=TRUE))))
时间越来越线性,这很好,但我觉得必须有一种更快的方法来完成这项任务,可能是通过避免lapply
循环。
如何加快这种多对多字符串匹配功能?
/ edit:一个简单的加速是并行化:
#Takes about 99 seconds
require('doParallel')
cl <- makeForkCluster(nnodes=8)
registerDoParallel(cl)
system.time(matches <- foreach(i=1:length(substrings)) %dopar% {
which(grepl(substrings[i], strings, fixed=TRUE))
})
stopCluster(cl)
但是,我认为一旦找到快速串行算法,大多数解决这个问题的方法都很容易并行化。