向R函数传递参数失败:变量与列范围传递报错
R函数封装:变量范围传递错误的解决方法
问题背景
需要将一段处理缺失值的R代码封装为函数,传入参数包括:数据框名、ResponseId变量名、一组连续变量范围(如PMS_1:PMS_45)。但函数调用时提示PMS_1不存在,参数传递方式有误。
可运行的原始代码
set.seed(1024) premice_1 <- subset(emu_raw, select=c(ResponseId, PMS_1:PMS_45)) premice_2 <- mice(premice_1, maxit=0, pri=F) pred <- premice_2$pred pred[,c("ResponseId")] <- 0 meth <- premice_2$meth meth[c("ResponseId")] <- "" postmice_a <- mice(premice_1, m=1, maxit=10, printFlag=TRUE, pred=pred, meth=meth, seed=4201) postmice_b <- mice::complete(postmice_a, "long", include=FALSE) postmice_b$.imp <- NULL postmice_b$.id <- NULL emu_raw <- merge(emu_raw, postmice_b)
出错的函数及调用
调用方式:missing_values(emu_raw, ResponseId, PMS_1:PMS_45),错误提示object 'PMS_1' not found。
出错函数:
missing_values <- function(df, ResponseId, measure_range) { set.seed(1024) premice_1 <- subset(df, select=c(ResponseId, measure_range)) premice_2 <- mice(premice_1, maxit=0, pri=F) pred <- premice_2$pred pred[,c("ResponseId")] <- 0 meth <- premice_2$meth meth[c("ResponseId")] <- "" postmice_a <- mice(premice_1, m=1, maxit=10, printFlag=TRUE, pred=pred, meth=meth, seed=4201) postmice_b <- mice::complete(postmice_a, "long", include=FALSE) postmice_b$.imp <- NULL postmice_b$.id <-NULL return(postmice_b) }
尝试用方括号替代subset()后仍报错:
missing_values <- function(df, ResponseId, measure_range) { set.seed(1024) premice_1 <- df[,c(ResponseId, measure_range)] premice_2 <- mice(premice_1, maxit=0, pri=F) pred <- premice_2$pred pred[,c(ResponseId)] <- 0 meth <- premice_2$meth meth[c("ResponseId")] <- "" postmice_a <- mice(premice_1, m=1, maxit=10, printFlag=TRUE, pred=pred, meth=meth, seed=4201) postmice_b <- mice::complete(postmice_a, "long", include=FALSE) postmice_b$.imp <- NULL postmice_b$.id <- NULL return(postmice_b) }
错误原因
直接在函数调用中传入PMS_1:PMS_45时,R会尝试在全局环境中查找名为PMS_1的对象,而非将其解析为数据框内的列名范围。同时,ResponseId的传递也未处理非标准求值的问题,导致列选择逻辑失效。
解决方案
提供两种可行的修正方式,按需选择:
方案一:使用非标准求值(推荐,保持调用直观性)
借助rlang包的非标准求值工具,让R在数据框的环境中解析变量名和范围:
library(mice) library(rlang) missing_values <- function(df, ResponseId, measure_range) { set.seed(1024) # 用{{}}注入变量,解析数据框内的列名和范围 premice_1 <- df |> dplyr::select({{ ResponseId }}, {{ measure_range }}) premice_2 <- mice(premice_1, maxit=0, pri=F) pred <- premice_2$pred # 将ResponseId转为字符串,处理pred和meth矩阵 resp_id_str <- as_name(enquo(ResponseId)) pred[, resp_id_str] <- 0 meth <- premice_2$meth meth[resp_id_str] <- "" postmice_a <- mice(premice_1, m=1, maxit=10, printFlag=TRUE, pred=pred, meth=meth, seed=4201) postmice_b <- mice::complete(postmice_a, "long", include=FALSE) postmice_b$.imp <- NULL postmice_b$.id <- NULL return(postmice_b) }
调用方式(无需引号,和原始代码写法一致):
# 调用函数 imputed_data <- missing_values(emu_raw, ResponseId, PMS_1:PMS_45) # 合并回原数据框 emu_raw <- merge(emu_raw, imputed_data)
方案二:使用字符串传递列名范围
若不想依赖rlang,可直接生成列名字符串向量传递:
library(mice) missing_values <- function(df, ResponseId, measure_range) { set.seed(1024) # 合并列名字符串 cols <- c(ResponseId, measure_range) premice_1 <- df[, cols, drop = FALSE] premice_2 <- mice(premice_1, maxit=0, pri=F) pred <- premice_2$pred pred[, ResponseId] <- 0 meth <- premice_2$meth meth[ResponseId] <- "" postmice_a <- mice(premice_1, m=1, maxit=10, printFlag=TRUE, pred=pred, meth=meth, seed=4201) postmice_b <- mice::complete(postmice_a, "long", include=FALSE) postmice_b$.imp <- NULL postmice_b$.id <- NULL return(postmice_b) }
调用方式:
# 生成列名字符串向量 measure_cols <- paste0("PMS_", 1:45) # 调用函数 imputed_data <- missing_values(emu_raw, "ResponseId", measure_cols) # 合并回原数据框 emu_raw <- merge(emu_raw, imputed_data)
内容的提问来源于stack exchange,提问作者JRDubbleu
相关产品推荐
相关产品推荐

