R语言dplyr自定义函数统计变量缺失值结果错误如何解决
R自定义函数按参考列非缺失值统计目标列缺失值问题
需求与初始测试
需要构建自定义函数,实现基于指定参考变量的非缺失值子集,统计目标变量缺失值数量的功能,初始测试数据集构造代码如下:
library(dplyr) var1=c(1:10,rep(NA,5)) var2=c(rep(NA,10), 21:25) var3=as.factor(c(rep(NA,3), rep("V",8), rep("U",4))) var4<-c(rep(NA,3), 1:9,rep(NA,3)) data <- data.frame(var1,var2,var3,var4)
直接运行管道代码可以得到正确结果,逻辑为:先筛选参考变量非缺失的行,再统计目标变量的缺失值计数:
# 筛选var3非缺失行,统计var2缺失值 data %>% filter(!is.na(var3)) %>% summarise(Missing=sum(is.na(var2))) # 筛选var2非缺失行,统计var4缺失值 data %>% filter(!is.na(var2)) %>% summarise(Missing=sum(is.na(var4)))
遇到的问题
将上述逻辑封装为自定义函数后运行结果不符合预期,初始错误封装代码如下:
count_missing <- function(data,a,b) { data %>% filter(!is.na(a)) %>% summarise(Missing=sum(is.na(b))) }
测试调用count_missing(data,var2,var4)时,预期返回Missing值为3,但实际返回值为6。最初误判为summarise语句未正确接收管道传入的筛选后数据。
问题原因
该问题和管道传值无关,本质是dplyr非标准计算的作用域问题:直接在函数内使用参数名a/b时,filter和summarise不会将参数识别为传入的数据框列名,会跳转至全局环境搜索同名对象,最终实际在原始全量数据上完成缺失值统计,因此返回全量var4的缺失值总数6,而非筛选var2非缺失行后的正确结果3。
修复方案
可根据参数传递习惯选择以下两种方案:
- 方案1:传入裸列名时,使用dplyr专门为自定义函数设计的双大括号
{{}}(拥抱运算符)包裹列参数,告知函数在传入数据的列中解析参数,修复后代码如下:
count_missing <- function(data,a,b) { data %>% filter(!is.na({{a}})) %>% summarise(Missing=sum(is.na({{b}}))) } # 测试调用 count_missing(data,var2,var4) # 输出 Missing=3,符合预期
- 方案2:习惯传入字符串形式列名时,使用
.data代词指代传入的数据框,按索引取对应列即可,修复后代码如下:
count_missing <- function(data,a,b) { data %>% filter(!is.na(.data[[a]])) %>% summarise(Missing=sum(is.na(.data[[b]]))) } # 测试调用(传字符串列名) count_missing(data,"var2","var4") # 输出 Missing=3,符合预期
内容的提问来源于stack exchange,提问作者Vu Tran
相关产品推荐
相关产品推荐

