如何在dplyr的filter中使用自定义函数且无需传入.data参数
解决方案
你描述的需求完全可以实现,核心是让自定义辅助函数能够访问filter()执行时的数据屏蔽上下文,这里提供两种不同版本适配的实现方式:
方案1:适配dplyr 1.1.0及以上(推荐)
使用dplyr新增的pick()函数直接在过滤上下文内读取目标列,无需手动传入数据集:
library(tidyverse) sepal_config <- function(length, width, species) { current_cols <- pick(Sepal.Length, Sepal.Width, Species) current_cols$Sepal.Length > length & current_cols$Sepal.Width < width & current_cols$Species == species } # 调用时不需要额外传.data参数 iris %>% filter( sepal_config(length = 4, width = 3, species = "versicolor") | sepal_config(length = 3, width = 3, species = "virginica") )
运行后即可返回预期的55行结果。
方案2:兼容dplyr 1.0.0~1.0.10旧版本
如果你使用的dplyr版本低于1.1.0,可以用cur_data()函数替代pick()获取当前上下文的完整数据集:
sepal_config <- function(length, width, species) { current_data <- cur_data() current_data$Sepal.Length > length & current_data$Sepal.Width < width & current_data$Species == species }
调用方式和方案1完全一致,运行效果相同。
原理解释
之前报错的原因是:自定义函数默认会在自身的函数执行环境中查找Sepal.Length等对象,而filter()的数据屏蔽能力仅对直接写在filter()参数内的表达式生效,不会自动穿透到自定义函数的内部环境。
而pick()、cur_data()都是dplyr原生提供的上下文感知函数,会自动从父级的filter()执行环境中获取当前处理的数据集,不需要手动传递参数,完美适配自定义过滤条件的需求。
内容的提问来源于stack exchange,提问作者Akhil Nair
相关产品推荐
相关产品推荐

