grepl与str_detect的区别及dplyr模糊筛选数据框的正确方法
模糊筛选数据框行的正确写法
先构建示例数据框:
library(dplyr) df <- data.frame( col1 = sample(c('M017', 'M018', 'M019', 'M20', 'Other'), 20, replace = TRUE), col2 = sample(c('m017', 'm018', 'm019', 'm20', 'Other'), 20, replace = TRUE), col3 = sample(c('AM017', 'BM018', 'CM019', 'DM20', 'Other'), 20, replace = TRUE), stringsAsFactors = FALSE )
需求
- 筛选出任意列中包含'M017'、'M018'模式的行
- 排除任意列中包含'M019'、'M20'模式的行
精确匹配实现
精确匹配的代码如下:
df_filtered <- df %>% filter_all(any_vars(. %in% c('M017', 'M018'))) %>% filter_all(all_vars(!(. %in% c('M019', 'M20'))))
模糊筛选写法分析
你尝试的三种模糊筛选写法都是正确的,只是用到了dplyr不同版本的语法和不同字符串匹配工具:
写法1:if_any + grepl
df_filtered <- df %>% filter(if_any(everything(), ~ grepl('M017|M018', ., ignore.case = TRUE))) %>% filter(!if_any(everything(), ~ grepl('M019|M20', ., ignore.case = TRUE)))
if_any是dplyr 1.0.0+引入的新语法,替代旧版filter_all(any_vars(...)),逻辑更直观;grepl是base R内置的字符串匹配函数,返回逻辑值,ignore.case=TRUE实现忽略大小写匹配。
写法2:旧版filter_all + grepl
df_filtered <- df %>% filter_all(any_vars(grepl('M017|M018', ., ignore.case = TRUE))) %>% filter_all(all_vars(!grepl('M019|M20', ., ignore.case = TRUE)))
filter_all是dplyr旧版本的语法,any_vars表示任意列满足条件即可保留,all_vars要求所有列满足条件才保留;- 逻辑上和写法1完全等价,适合dplyr 1.0.0之前的版本使用。
写法3:if_any + str_detect
df %>% filter(if_any(everything(), ~ str_detect(., regex('M017|M018', ignore_case = TRUE)))) %>% filter(!if_any(everything(), ~ str_detect(., regex('M019|M20', ignore_case = TRUE))))
str_detect是tidyverse生态下stringr包的函数,和grepl功能一致,都是检测字符串是否包含目标模式;regex('xxx', ignore_case=TRUE)用来定义忽略大小写的正则规则,效果和grepl的ignore.case=TRUE完全相同。
补充说明
grepl(base R)和str_detect(stringr)核心功能一致,主要差异是参数顺序:grepl(模式, 字符串)vsstr_detect(字符串, 模式);- 若使用tidyverse工具链,推荐
str_detect+if_any的组合,语法风格更统一;习惯base R的话,grepl也完全够用。
内容的提问来源于stack exchange,提问作者farrow90
相关产品推荐
相关产品推荐

