在大型数据集上优化sapply-grepl

时间:2019-05-07 07:54:00

标签: r regex grepl

我有一个大数据集(df)〜250.000个观察值,其中包括一列cleanText(其中包含以任何数字,标点,大写字母等形式清除的文本),并且有公司名称列表。我想检查df $ cleanText中与公司名称列表中的公司是否匹配的每个观察值,并计算它找到并存储的匹配数量。我的代码有效,但是,它大约需要20个小时才能执行,而且我觉得它可能要快得多。

到目前为止,我还无法弄清楚什么可行。

# Start for loop for each row in df
for(i in 1:nrow(df)){

# store matches in companyNameMatch, make sure the paste0 includes \\b to match whole strings
companyNameMatch <- sapply(list_Companies, function(x) grepl(paste0(x, "\\b"), as.character(df$cleanText[i])))

# Calculate the number of matches and store it
df$companyNameMatch[i] <- as.numeric(length(which(companyNameMatch != 0)))
}

我希望代码应该能够在几个小时左右的时间内运行。

示例

cleanText <- c("keeping a cool head takes practice nike",
               "playing soccer on these adidas",
               "just having a laugh",
               "nike and adidas perform better than crocs")

list_Companies <- c("nike", "adidas", "crocs", "puma")

对于df $ cleanText中的每一行,sapply函数应检查是否与list_Companies中的一行匹配。在这种情况下,结果看起来是这样的:

df$companyNameMatch[1] = 1
df$companyNameMatch[2] = 1
df$companyNameMatch[3] = 0
df$companyNameMatch[4] = 3

2 个答案:

答案 0 :(得分:2)

您可以将sapplyrowSums一起使用

df$companyNameMatch <- rowSums(sapply(list_Companies, function(x) grepl(x, cleanText)))

使用microbenchmark软件包,我们可以明显地提高速度:

Unit: microseconds
     expr      min       lq      mean   median       uq        max neval cld
  rowSums   65.382   78.496   132.345   93.511   119.55   1462.727   100  a 
 for_loop 6206.326 6920.394 11170.353 7340.814 10058.53 170440.373   100   b

答案 1 :(得分:1)

使用base R,我们可以遍历'listCompanies,使用greplReduce逻辑向量的list成为一个

Reduce(`+`, lapply(list_Companies, grepl, cleanText))
#[1] 1 1 0 3

tidyverse的类似选项

library(tidyverse)
map(list_Companies, str_detect, string = cleanText) %>% 
           reduce(`+`)