R语言中统计另一数据框列字符串匹配次数的最高效方法
R语言高效统计评论中汽车品牌提及次数方案
首先你原有方案的问题有两个:一是for循环逐一遍历品牌全量扫描评论列,时间复杂度为O(品牌数*评论数),数据量大时耗时会成倍增长;二是默认区分大小写匹配,会漏统计大小写不一致的提及内容,比如示例中的小写tesla无法匹配TESLA。
以下是按效率从高到低给出的可直接运行的方案:
最优方案:单次扫描提取所有品牌后统计
该方案仅需扫描一次评论列即可提取所有匹配的品牌,时间复杂度为O(评论数),数据量越大效率优势越明显,最终结果直接追加到df2中无需额外合并:
library(tidyverse) # 小样本测试数据集 df1 <- tibble(body = c("The Tesla Roadster has a range of 620 miles", "ferrari needs to make an electric car", "How much does a tesla cost?", "When is the new Mercedes releasing?", "Can't wait to get my hands on the new Tesla")) df2 <- tibble(names = c("FORD", "TESLA", "MERCEDES", "FERRARI", "JAGUAR", "HYUNDAI")) # 预处理:统一评论为大写,避免大小写不匹配漏统计 df1$body <- str_to_upper(df1$body) # 拼接品牌正则匹配组 brand_pattern <- paste(df2$names, collapse = "|") # 提取所有评论中出现的品牌,统计频次 brand_counts <- str_extract_all(df1$body, brand_pattern, simplify = FALSE) %>% unlist() %>% table() %>% as.data.frame(stringsAsFactors = FALSE) %>% setNames(c("names", "mention_count")) # 左连到df2,未提及的品牌计数填充为0 df2 <- df2 %>% left_join(brand_counts, by = "names") %>% mutate(mention_count = replace_na(mention_count, 0))
运行后df2的输出结果符合预期:
| names | mention_count |
|---|---|
| FORD | 0 |
| TESLA | 3 |
| MERCEDES | 1 |
| FERRARI | 1 |
| JAGUAR | 0 |
| HYUNDAI | 0 |
次优方案:固定字符串匹配优化循环
如果品牌名存在特殊正则元字符(比如+、.、*),用固定字符串匹配比正则匹配速度高3-5倍,且避免元字符导致的匹配错误:
library(stringi) library(tidyverse) df1$body <- stri_trans_toupper(df1$body) # 用stringi的固定匹配函数,直接生成计数列追加到df2 df2$mention_count <- sapply(df2$names, function(x) sum(stri_detect_fixed(df1$body, pattern = x)))
优化说明
- 优先做一次全量大小写统一预处理,不要在每次匹配时单独处理大小写,可节省大量重复计算开销
- 无模糊匹配需求时一定用固定字符串匹配,不要用正则匹配,速度提升非常明显
- 评论数远大于品牌数时,优先用单次全量提取统计的方案,避免逐一遍历品牌扫描全量评论
内容的提问来源于stack exchange,提问作者catic_
相关产品推荐
相关产品推荐

