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

编写自定义函数错误排查:函数中数据框列名使用问题

问题分析:自定义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")
}

错误原因拆解

  1. %to%用法误区:%to%是expss专属的列范围选择符,它仅接受列名符号或字符串形式的列名范围,不能直接传入列值(如example$q1),也无法在函数内直接识别未绑定到数据框的参数符号(如a %to% b)。
  2. 非标准评估适配问题:
    • 第一个函数中,a %to% b无法被mrset和cross_cpct解析为目标数据框的列范围,因为函数参数在非标准评估环境下未与数据框关联。
    • 第二个函数中,df[[a]] %to% df[[b]]属于错误用法:%to%不能作用于列向量,只能用于标识列名的范围。
  3. 分组变量传递错误: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 00:05:17