编写自定义函数错误排查:函数中数据框列名使用问题
问题分析:自定义expss多响应频率表函数的错误排查
问题背景
我需要明确自己编写的函数存在哪些错误。目前正在用expss包对多响应变量生成频率表,要在多列重复执行代码,所以想写自定义函数简化流程,但遇到了问题。
示例数据
example <- data.frame(org = c("A", "B", "C", "D", "E", "F", "G"), q1 = c("apple", "apple", NA, "apple", "apple", "apple", NA), q2 = c(NA, NA, NA, "banana", "banana", "banana", NA), q3 = c("orange", NA, "orange", "orange", NA, "orange", NA), region = c("1", "1", "2", "3", "3", "2", "2"))
原可运行代码
library(dplyr) library(expss) # 生成全州频率表 pct_tot <- as.data.frame(cross_cpct(example, mrset(q1 %to% q3))) # 生成按region分组的频率表并与全州表合并 pct_all <- as.data.frame(cross_cpct(example, mrset(q1 %to% q3), region)) %>% left_join(pct_tot, by = "row_labels")
错误的函数实现与调用
第一个错误函数
mr_freq_1 <- function(df, a, b, region) { # 生成百分比表 # 全州表 pct_tot <- as.data.frame(cross_cpct(df, mrset(a %to% b))) # 按region分组的表并与全州表合并 pct_all <- as.data.frame(cross_cpct(df, mrset(a %to% b), region)) %>% left_join(pct_tot, by = "row_labels") }
尝试三种调用方式均报错:
mr_freq_1(example, example$q1, example$q3, example$region) mr_freq_1(example, q1, q3, region) mr_freq_1(example, "q1", "q3", "region")
第二个错误函数
mr_freq_2 <- function(df, a, b, region) { # 生成百分比表 # 全州表 pct_tot <- as.data.frame(cross_cpct(df, mrset(df[[a]] %to% df[[b]]))) # 按region分组的表并与全州表合并 pct_all <- as.data.frame(cross_cpct(df, mrset(df[[a]] %to% df[[b]]), df[[region]])) %>% left_join(pct_tot, by = "row_labels") }
错误原因拆解
%to%用法误区:%to%是expss专属的列范围选择符,它仅接受列名符号或字符串形式的列名范围,不能直接传入列值(如example$q1),也无法在函数内直接识别未绑定到数据框的参数符号(如a %to% b)。- 非标准评估适配问题:
- 第一个函数中,
a %to% b无法被mrset和cross_cpct解析为目标数据框的列范围,因为函数参数在非标准评估环境下未与数据框关联。 - 第二个函数中,
df[[a]] %to% df[[b]]属于错误用法:%to%不能作用于列向量,只能用于标识列名的范围。
- 第一个函数中,
- 分组变量传递错误:
cross_cpct的分组参数需要数据框内的列引用(符号或字符串),直接传入未绑定的region或列向量df[[region]]都不符合函数要求。
正确的函数实现
针对非标准评估的问题,我们可以通过构造表达式结合强制求值(!!)来解决,以下提供两种兼容不同调用方式的版本:
版本1:接受字符串列名
mr_freq_correct <- function(df, start_col, end_col, group_col) { library(dplyr) library(expss) library(rlang) # 构造多响应变量范围表达式 col_range_expr <- parse_expr(paste0("mrset(", start_col, " %to% ", end_col, ")")) # 生成全州频率表 pct_tot <- as.data.frame(cross_cpct(df, !!col_range_expr)) # 生成分组频率表并合并 pct_all <- as.data.frame(cross_cpct(df, !!col_range_expr, !!sym(group_col))) %>% left_join(pct_tot, by = "row_labels") return(pct_all) }
调用示例:
result <- mr_freq_correct(example, "q1", "q3", "region") print(result)
版本2:接受符号列名(更贴近原生代码写法)
mr_freq_correct_sym <- function(df, start_col, end_col, group_col) { library(dplyr) library(expss) library(rlang) # 将符号参数转为字符串 start_col_str <- as_name(enquo(start_col)) end_col_str <- as_name(enquo(end_col)) group_col_str <- as_name(enquo(group_col)) # 构造多响应变量范围表达式 col_range_expr <- parse_expr(paste0("mrset(", start_col_str, " %to% ", end_col_str, ")")) # 生成全州频率表 pct_tot <- as.data.frame(cross_cpct(df, !!col_range_expr)) # 生成分组频率表并合并 pct_all <- as.data.frame(cross_cpct(df, !!col_range_expr, !!sym(group_col_str))) %>% left_join(pct_tot, by = "row_labels") return(pct_all) }
调用示例:
result <- mr_freq_correct_sym(example, q1, q3, region) print(result)
内容的提问来源于stack exchange,提问作者KLenny
相关产品推荐
相关产品推荐

