如何在R语言中使用grepl按行检查字符串是否存在
问题场景
现有如下R数据集:
library(dplyr) mydata <- data.frame(id = c(1, 2, 3, 4, 5), fruit = c("orange", "jackfruit", "", "N/A", ""), fruit2 = c("orange", "guava", "", "", ""), fruit3 = c("orange", "N/A", "orang", "", ""))
需要按每个id(每行对应一个id)检查指定字符串是否存在于该行的fruit/fruit2/fruit3列中,例如判断"orange"是否存在于id=1、2中,"jackfruit"是否存在于id=2中。
尝试以下代码时出现警告:
mydata %>% group_by(id) %>% grepl("orange")
警告信息:
In grep(., "orange") : argument 'pattern' has length > 1 and only the first element will be used
错误原因
group_by(id)多余:每个id对应单独一行,无需分组,直接按行处理即可。- 参数顺序错误:
grepl的正确语法是grepl(pattern, x),你把数据框传给了第一个参数(pattern位置),导致R错误解析参数触发警告。 - 未结合dplyr行处理动词(如
mutate/summarize)直接调用grepl,不符合dplyr管道的使用逻辑。
正确实现方法
方法1:使用rowwise() + any(grepl())
适合需要自定义列范围或做额外数据清洗的场景:
# 检查每行是否包含"orange" mydata %>% rowwise() %>% mutate(has_orange = any(grepl("orange", c(fruit, fruit2, fruit3)))) %>% ungroup() # 检查每行是否包含"jackfruit" mydata %>% rowwise() %>% mutate(has_jackfruit = any(grepl("jackfruit", c(fruit, fruit2, fruit3)))) %>% ungroup()
说明:
rowwise()让R逐行处理数据c(fruit, fruit2, fruit3)将当前行的三个水果列合并为向量grepl()检查每个元素是否匹配目标字符串,any()判断该行是否有至少一个匹配项
如果需要排除空字符串、"N/A"这类无效值,可以先清洗数据:
# 先将无效值替换为NA mydata_clean <- mydata %>% mutate(across(starts_with("fruit"), ~ ifelse(.x %in% c("", "N/A"), NA, .x))) # 再检查,添加na.rm=TRUE忽略NA mydata_clean %>% rowwise() %>% mutate(has_orange = any(grepl("orange", c(fruit, fruit2, fruit3)), na.rm = TRUE)) %>% ungroup()
方法2:使用if_any()(dplyr 1.0.0及以上版本)
这是更简洁的dplyr原生写法,无需手动合并列:
# 检查每行是否包含"orange" mydata %>% mutate(has_orange = if_any(starts_with("fruit"), ~ grepl("orange", .x))) # 检查每行是否包含"jackfruit" mydata %>% mutate(has_jackfruit = if_any(starts_with("fruit"), ~ grepl("jackfruit", .x)))
说明:
starts_with("fruit")自动匹配所有以fruit开头的列if_any()会对每行的指定列逐一应用grepl判断,只要有一列匹配就返回TRUE
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

