我正在尝试gregexpr搜索" ABCD"的位置。用大字符串和" ABBD,ACCD,AAAD"在同一个字符串中。我想输出" ABCD"搜索结果和" ABBD,ACCD,AAAD"搜索结果在数据表的两个单独的列中。
我目前的方法是单独使用gregexpr,将每个导出为1列txt文件,将每个作为矩阵导入,对每个1列矩阵进行排序,使数字逐行上升,列绑定两个矩阵,并转换得到的两个矩阵列矩阵成数据表。
这种方法在处理非常大的字符串时似乎非常低效,并且需要很长时间才能完成。有没有办法优化程序?谢谢你的帮助!
# dummy string that is relatively short for this demo
x <- "ABCDACCDABBDABCDAAADACCDABBDABCD"
# SEARCH for 'ABCD' location
out1 <- gregexpr(pattern = "ABCD", x)
cat(paste(c(out1[[1]]), sep = "\n", collapse = "\n"), file = "~/out_1.txt")
# SEARCH for 'A??D' location
outB <- gregexpr(pattern = "ABBD", x)
outC <- gregexpr(pattern = "ACCD", x)
outA <- gregexpr(pattern = "AAAD", x)
cat(paste(c(outA[[1]], outB[[1]], outC[[1]]), collapse = "\n"), file = "~/out_2.txt")
# Function that BINDS Matrices by column
cbind.fill <- function(...){
nm <- list(...)
nm <- lapply(nm, as.matrix)
n <- max(sapply(nm, nrow))
do.call(cbind, lapply(nm, function (x) rbind(x, matrix(, n-nrow(x), ncol(x)))))
}
# Load as Tables --> Sort by numbers increasing --> Matrices
mat1 <- as.matrix(read.table("~/out_1.txt"))
mat2.t <- (read.table("~/out_2.txt"))
mat2 <- as.matrix(mat2.t[order(mat2.t$V1),])
# Combine two matrices to create 2 column matrix
comb_mat <- cbind.fill(mat1, mat2)
write.table(comb_mat, file = "~/comb_mat.txt", row.names = FALSE, col.names = FALSE)
答案 0 :(得分:6)
fixed=T
的{{1}}参数,这可能会产生性能优势。来自https://stat.ethz.ch/R-manual/R-devel/library/base/html/grep.html:如果要进行大量正则表达式匹配(包括非常长的字符串),则需要考虑使用的选项。通常PCRE将比默认的正则表达式引擎更快,并且仍然更快固定= TRUE(特别是当每个模式只匹配几次时)。
gregexpr()
立即对第二列进行排序,而不是存储中间变量,然后使用sort()
对其进行索引。order()
函数可以正常工作,但NA-padding的任务可以通过越界索引轻松完成,对于该索引,R自然会返回越界索引的NA。因此:
cbind.fill()
然后,您可以根据x <- 'ABCDACCDABBDABCDAAADACCDABBDABCD';
out1 <- c(gregexpr('ABCD',x,fixed=T)[[1]]);
out2 <- sort(c(gregexpr('AAAD',x,fixed=T)[[1]],gregexpr('ABBD',x,fixed=T)[[1]],gregexpr('ACCD',x,fixed=T)[[1]]));
outmax <- max(length(out1),length(out2));
comb_mat <- cbind(out1[1:outmax],out2[1:outmax]);
comb_mat;
## [,1] [,2]
## [1,] 1 5
## [2,] 13 9
## [3,] 29 17
## [4,] NA 21
## [5,] NA 25
电话将comb_mat
写入文件。
编辑:正如您(现在我)发现的那样,write.table()
对大字符串执行效果差得惊人,而您的237MB字符串肯定是一个大字符串。从Fast partial string matching in R开始,我们可以使用gregexpr()
包来加快效果。以下是如何使用stringi::stri_locate_all()
来完成您的要求的演示。一些说明:
stringi
,您可以看到我使用x
加载它,因为data.table::fread()
占用时间过长。read.table()
。因此:
1:outmax
答案 1 :(得分:4)
您可以使用前瞻来简化它,因此您只有一个带有两个捕获组件的正则表达式。
library('data.table');
library('stringi');
x <- fread('x',header=F)$V1;
## Read 1 rows and 1 (of 1) columns from 0.221 GB file in 00:00:03
system.time({ out1 <- stri_locate_all(x,regex='ABCD')[[1]][,'start']; });
## user system elapsed
## 3.687 0.359 4.044
system.time({ out2 <- stri_locate_all(x,regex='AAAD|ABBD|ACCD')[[1]][,'start']; });
## user system elapsed
## 4.938 0.454 5.404
length(out1);
## [1] 22218750
length(out2);
## [1] 37031250
length(out1) <- length(out2) <- max(length(out1),length(out2));
comb_mat <- cbind(out1,out2);
head(comb_mat);
## out1 out2
## [1,] 1 5
## [2,] 13 9
## [3,] 29 17
## [4,] 33 21
## [5,] 45 25
## [6,] 61 37
tail(comb_mat);
## out1 out2
## [37031245,] NA 236999961
## [37031246,] NA 236999973
## [37031247,] NA 236999977
## [37031248,] NA 236999985
## [37031249,] NA 236999989
## [37031250,] NA 236999993
nrow(comb_mat);
## [1] 37031250
在这个矩阵ms <- gregexpr("A(?=(BCD)|(BBD|CCD|AAD))", x, perl=T)
res <- attr(ms[[1]], "capture.start")
res[res>0] <- res[res>0]-1
中,第一列是ABCD的起始位置,其他三个中的第二列。如果您愿意,可以用NA替换零。
res
答案 2 :(得分:4)
使用 stringi 包的另一种方法:
library(stringi)
x <- 'ABCDACCDABBDABCDAAADACCDABBDABCD'
m <- stri_locate_all_regex(x, c('ABCD', 'AAAD|ABBD|ACCD'))
l <- list(m[[1]][,'start'], m[[2]][,'start'])
do.call(cbind, lapply(l, `[`, seq_len(max(sapply(l, length)))))
# [,1] [,2]
# [1,] 1 5
# [2,] 13 9
# [3,] 29 17
# [4,] NA 21
# [5,] NA 25
或者您可以尝试使用 zoo 包:
m <- coredata(do.call(cbind, lapply(l, zoo)))
colnames(m) <- NULL
# [,1] [,2]
# [1,] 1 5
# [2,] 13 9
# [3,] 29 17
# [4,] NA 21
# [5,] NA 25