使用data.table在R中实现多模式与多字符串匹配的问题
解决data.table中逐行匹配正则表达式并聚合匹配结果的问题
问题场景
有两个data.table对象dat1和dat2,需要用正则表达式\b[pattern]\b(单词边界匹配),将dat1中的每个pattern分别在dat2的description和memo列中匹配,把对应的id2值拼接后存入dat1,期望输出格式如下:
id1 pattern description_match memo_match 1: 1 apple 1174,1231 <NA> 2: 1 applejack <NA> <NA> 3: 2 bananas, sweet <NA> 1174
尝试的代码如下,运行报错提示grepl只能使用第一个pattern:
dat1[, description_match := dat2[grepl(paste0("\b", dat1$pattern, "\b"), dat2$description), .(id2 = paste(id2, collapse = ","))]] dat1[, memo_match := dat2[grepl(paste0("\b", dat1$pattern, "\b"), dat2$memo), .(id2 = paste(id2, collapse = ","))]]
错误原因
- 向量不匹配:
grepl的pattern参数若传入长度大于1的向量,只会用第一个元素匹配所有dat2行,无法实现dat1每行pattern对应匹配dat2的逻辑。 - 转义字符错误:R字符串中的
\b需要双重转义为\\b,否则会被解析为退格符,而非正则表达式的单词边界。
解决方法
利用data.table的分组逐行处理特性,实现每个pattern的独立匹配:
方法1:data.table分组处理(推荐)
# 处理description列 dat1[, description_match := { pat <- paste0("\\b", pattern, "\\b") matched_ids <- dat2[grepl(pat, description), paste(id2, collapse = ",")] if (length(matched_ids) == 0) NA_character_ else matched_ids }, by = .(id1, pattern)] # 处理memo列 dat1[, memo_match := { pat <- paste0("\\b", pattern, "\\b") matched_ids <- dat2[grepl(pat, memo), paste(id2, collapse = ",")] if (length(matched_ids) == 0) NA_character_ else matched_ids }, by = .(id1, pattern)]
方法2:sapply逐行遍历
dat1$description_match <- sapply(dat1$pattern, function(p) { pat <- paste0("\\b", p, "\\b") ids <- dat2[grepl(pat, description), id2] if (length(ids) == 0) NA else paste(ids, collapse = ",") }) dat1$memo_match <- sapply(dat1$pattern, function(p) { pat <- paste0("\\b", p, "\\b") ids <- dat2[grepl(pat, memo), id2] if (length(ids) == 0) NA else paste(ids, collapse = ",") })
关键说明
- 正则转义:必须用
\\b表示正则中的单词边界,R字符串单个\会被当作转义符,因此需要双重转义。 - 逐行匹配:通过
by = .(id1, pattern)让data.table对dat1每一行单独执行匹配逻辑,确保每个pattern都被正确使用。 - 空匹配处理:无匹配结果时手动返回
NA,保证输出格式符合预期。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

