You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用filter_at时starts_with报错:需在选择函数内使用的问题排查

解决filter_at里用starts_with()报错的问题

这个坑我之前也踩过,确实是你用的dplyr(0.8.4)和tidyselect(1.0.0)版本组合导致的兼容问题。tidyselect 1.0.0开始对选择器的使用场景做了严格限制,starts_with()这类选择器被限定只能在选择型函数(比如select())里用,而旧版的filter_at的vars()参数并不属于这个场景,所以就触发了报错。

给你几个靠谱的解决办法,按需选择就行:

办法1:用matches()替换starts_with()

matches()支持正则表达式匹配列名,完全能实现starts_with("all")的效果,而且在filter_at里可以正常工作:

filter_at(df, vars(matches("^all")), any_vars(. == "Y"))

这里^all是正则表达式的写法,意思就是匹配以"all"开头的列名,和starts_with("all")的逻辑完全一致。

办法2:先获取目标列名再传入vars()

先通过select()把符合条件的列名提取出来,再用one_of()将列名传给filter_at:

# 先获取以all开头的列名
target_cols <- names(select(df, starts_with("all")))
# 执行过滤逻辑
filter_at(df, vars(one_of(target_cols)), any_vars(. == "Y"))

one_of()可以接受列名字符向量,在vars()中是合法用法,完美绕开选择器的场景限制。

办法3:升级dplyr到新版本(推荐)

如果允许升级包的话,建议把dplyr升级到1.0.0及以上版本。新版dplyr中,虽然filter_at这类“范围动词”被标记为软弃用,但引入了更灵活的across()和if_any()函数,写法更直观:

# 使用across的写法(dplyr 1.0.0+可用)
df %>% filter(across(starts_with("all"), ~ .x == "Y", .fns = any))
# 更简洁的if_any写法(dplyr 1.0.5+可用)
df %>% filter(if_any(starts_with("all"), ~ .x == "Y"))

if_any()专门用来实现“任意一列满足条件则保留该行”的逻辑,代码可读性比旧版filter_at高很多。

用你的测试数据验证效果

拿你提供的数据集运行办法1的代码,能得到正确结果:

id <- c("john","paul","george","ringo","mick","dozy","beaky","tich")
allow_a <- c("Y","N","Y","Y","","","Y","")
allow_b <- c("N","","N","","N","N","N","Y")
generic_a <- c("N","","","Y","Y","Y","N","")
generic_b <- c("N","","","N","Y","N","","Y")
df <- data.frame(id, allow_a, allow_b, generic_a, generic_b)

library(dplyr)
filter_at(df, vars(matches("^all")), any_vars(. == "Y"))

输出结果:

id allow_a allow_b generic_a generic_b
1   john       Y       N         N         N
2 george       Y       N                 N
3  ringo       Y                   Y         N
4  beaky       Y       N         N         

内容的提问来源于stack exchange,提问作者TimL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:32:39