使用dplyr的select_if结合多条件(含字符串匹配)选列遇问题
问题原因
你遇到的报错核心是上下文不匹配:
select_if()的谓词函数(~is.numeric(.) & ...)是针对列的数值内容做判断的,属于「列值处理上下文」;- 而
ends_with()这类tidyselect辅助函数,是专门在「列名选择上下文」(比如直接写在select()括号里)用来匹配列名的,它们无法在列值处理的环境中生效。
简单说,select_if()本身是选择函数,但它的参数是用来检查每一列值的特征,不是直接匹配列名的,所以不能直接在里面用ends_with()。
解决方案
下面给几种实用的解决方法,按推荐程度排序:
方法1:用select(where())结合matches()(dplyr现代写法)
dplyr 1.0.0之后推荐用where()替代select_if(),它可以在select()的列名选择上下文里,同时结合列值判断和列名匹配:
iris %>% select(where(is.numeric) & matches("Length$")) %>% names()
where(is.numeric)筛选出数值类型的列;matches("Length$")用正则匹配列名以Length结尾的列;- 两者用
&组合,就能得到同时满足两个条件的列。
方法2:在select_if()里手动判断列名
如果一定要用select_if(),可以用cur_column()获取当前处理的列名,再用字符串匹配函数判断:
library(stringr) iris %>% select_if(~is.numeric(.) & str_detect(cur_column(), "Length$")) %>% names()
cur_column()是dplyr提供的工具,能在谓词函数里拿到当前列的名称,这样就可以用普通字符串函数(比如str_detect)来匹配列名,避开tidyselect的上下文限制。
方法3:先筛选列名再选择
用基础R的方式先找出符合条件的列名,再传入select():
library(stringr) target_cols <- names(iris)[sapply(iris, is.numeric) & str_detect(names(iris), "Length$")] iris %>% select(all_of(target_cols)) %>% names()
这种方法逻辑直白,适合习惯基础R语法的场景。
内容的提问来源于stack exchange,提问作者llewmills
相关产品推荐
相关产品推荐

