如何加速 R 中的正则表达式搜索?
How to speed up regex search in R?
我有密码
matrix<-outer(df$text, df1$regexp, str_count)
df 超过 1000 个文本,每个约 1500 个符号
和带有 500 个正则表达式否定表达式的 df1,例如
(?<!(no|not|n`t|n’t|neither|never|no one|nobody|none|nor|nothing|nowhere|hardly|barely|scarcely|unlikely|seldom|rarely))[ ][aA][bB][aA][nN][dD][oO][nN]
所以我的代码运行宁了一个多小时
如何加速我的代码?
示例:
library(stringr)
df<-data.frame(names=c("text1","text2"), text=c("one two three four five","six seven eight nine ten"))
regex<-data.frame(names=c("1","2"), regexp=c("(?<!(no|not))[ ][oO][nN][eE]","(?<!(no|not))[ ][fF][iI][vV][eE]"))
matrix<-outer(df$text, as.character(regex$regexp), str_count)
我已经尝试 运行 代码与
并行
library(stringr)
library(parallel)
no_cores <- detectCores() - 1
df<-data.frame(names=c("text1","text2"), text=c("one two three four five","six seven eight nine ten"))
regex<-data.frame(names=c("1","2"), regexp=c("(?<!(no|not))[ ][oO][nN][eE]","(?<!(no|not))[ ][fF][iI][vV][eE]"))
cl <- makeCluster(no_cores)
matrix<-parSapply(cl,regex$regexp, str_count, string=df$text)
stopCluster(cl)
现在在我的 4 核 PC 上编码速度提高了大约 40%
我已经像 Wiktor 推荐的那样更改了所有正则表达式,并且使用代码 运行 比使用旧正则表达式
的并行代码快大约 25%
(?<!n(?:[`’]t|e(?:ither|ver)|o(?:t| one|body|ne|r|thing|where){0,1})|hardly|barely|scarcely|unlikely|seldom|rarely)[ ][aA][bB][aA][nN][dD][oO][nN]
预先正确创建数据(字符而不是因子)
df <- data.frame(names=c("text1","text2"),
text=c("one two three four five",
"six seven eight nine ten"),
stringsAsFactors=FALSE)
regex <- data.frame(names=c("1","2"),
regexp=c("(?<!(no|not))[ ][oO][nN][eE]",
"(?<!(no|not))[ ][fF][iI][vV][eE]"),
stringsAsFactors=FALSE)
R函数一般都是'vectorized',也就是说每个正则表达式都可以作用于字符串的向量
str_count(pattern=regex$regex[1], string=df$text)
或
sapply(regex$regex, str_count, string=df$text)
例如,
> sapply(regex$regex, str_count, string=df$text)
(?<!(no|not))[ ][oO][nN][eE] (?<!(no|not))[ ][fF][iI][vV][eE]
[1,] 0 1
[2,] 0 0
这可能会在两个维度上线性扩展,但随着 length(df$text)
的增加,速度要快得多(与使用 outer()
相比)。
stringr 中使用的正则表达式风格是 ICU(因此,无法测试它是否在 regex101.com 有效)并且这种风格不需要完全固定宽度的后视。在一些简单的情况下,它确实支持限制量词以及常规 *
和 +
(尽管后两者与其说是功能,不如说是错误,可能会在以后修复)。
因此,您的正则表达式运行缓慢,因为多个交替分支以相同的子字符串开头。这会造成过多的回溯。您需要确保每个分支不能在同一个位置匹配。
使用
(?<!n(?:[`’]t|e(?:ither|ver)|o(?:t| one|body|ne|r|thing|where){0,1})|hardly|barely|scarcely|unlikely|seldom|rarely)[ ][aA][bB][aA][nN][dD][oO][nN]
我有密码
matrix<-outer(df$text, df1$regexp, str_count)
df 超过 1000 个文本,每个约 1500 个符号 和带有 500 个正则表达式否定表达式的 df1,例如
(?<!(no|not|n`t|n’t|neither|never|no one|nobody|none|nor|nothing|nowhere|hardly|barely|scarcely|unlikely|seldom|rarely))[ ][aA][bB][aA][nN][dD][oO][nN]
所以我的代码运行宁了一个多小时
如何加速我的代码?
示例:
library(stringr)
df<-data.frame(names=c("text1","text2"), text=c("one two three four five","six seven eight nine ten"))
regex<-data.frame(names=c("1","2"), regexp=c("(?<!(no|not))[ ][oO][nN][eE]","(?<!(no|not))[ ][fF][iI][vV][eE]"))
matrix<-outer(df$text, as.character(regex$regexp), str_count)
我已经尝试 运行 代码与
并行library(stringr)
library(parallel)
no_cores <- detectCores() - 1
df<-data.frame(names=c("text1","text2"), text=c("one two three four five","six seven eight nine ten"))
regex<-data.frame(names=c("1","2"), regexp=c("(?<!(no|not))[ ][oO][nN][eE]","(?<!(no|not))[ ][fF][iI][vV][eE]"))
cl <- makeCluster(no_cores)
matrix<-parSapply(cl,regex$regexp, str_count, string=df$text)
stopCluster(cl)
现在在我的 4 核 PC 上编码速度提高了大约 40%
我已经像 Wiktor 推荐的那样更改了所有正则表达式,并且使用代码 运行 比使用旧正则表达式
的并行代码快大约 25%(?<!n(?:[`’]t|e(?:ither|ver)|o(?:t| one|body|ne|r|thing|where){0,1})|hardly|barely|scarcely|unlikely|seldom|rarely)[ ][aA][bB][aA][nN][dD][oO][nN]
预先正确创建数据(字符而不是因子)
df <- data.frame(names=c("text1","text2"),
text=c("one two three four five",
"six seven eight nine ten"),
stringsAsFactors=FALSE)
regex <- data.frame(names=c("1","2"),
regexp=c("(?<!(no|not))[ ][oO][nN][eE]",
"(?<!(no|not))[ ][fF][iI][vV][eE]"),
stringsAsFactors=FALSE)
R函数一般都是'vectorized',也就是说每个正则表达式都可以作用于字符串的向量
str_count(pattern=regex$regex[1], string=df$text)
或
sapply(regex$regex, str_count, string=df$text)
例如,
> sapply(regex$regex, str_count, string=df$text)
(?<!(no|not))[ ][oO][nN][eE] (?<!(no|not))[ ][fF][iI][vV][eE]
[1,] 0 1
[2,] 0 0
这可能会在两个维度上线性扩展,但随着 length(df$text)
的增加,速度要快得多(与使用 outer()
相比)。
stringr 中使用的正则表达式风格是 ICU(因此,无法测试它是否在 regex101.com 有效)并且这种风格不需要完全固定宽度的后视。在一些简单的情况下,它确实支持限制量词以及常规 *
和 +
(尽管后两者与其说是功能,不如说是错误,可能会在以后修复)。
因此,您的正则表达式运行缓慢,因为多个交替分支以相同的子字符串开头。这会造成过多的回溯。您需要确保每个分支不能在同一个位置匹配。
使用
(?<!n(?:[`’]t|e(?:ither|ver)|o(?:t| one|body|ne|r|thing|where){0,1})|hardly|barely|scarcely|unlikely|seldom|rarely)[ ][aA][bB][aA][nN][dD][oO][nN]