如何在crosstab或频数表中纳入可能不存在的列?
动态生成含可选列的交叉频数表解决方案
问题背景
需要编写代码,根据数据中实际存在的列动态生成1/2/3维交叉频数表,目标列固定为A、B、C,但无法预知哪些列会缺失(可能缺A、缺B、同时缺A和B,甚至三列全缺)。此前尝试过dat %>% intersect(names(.), c("A", "B","C"))或dat %>% select(any_of(c("A", "B", "C")))与tabyl/count结合,但未成功;用map(tabyl)只能得到单列频数;写大量if else语句又过于繁琐,寻求高效可行方案。
示例数据
dat <- structure(list(A = c("2", "7", "1", "1", "1"), C = c(NA, NA, NA, NA, NA)), row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame"))
解决方案
1. 生成count格式结果
核心逻辑是先筛选出数据中实际存在的目标列,再通过动态分组实现计数:
# 定义目标列集合 target_cols <- c("A", "B", "C") # 提取数据中存在的目标列 existing_cols <- intersect(target_cols, names(dat)) # 动态生成频数表 if (length(existing_cols) > 0) { dat %>% count(across(all_of(existing_cols)), .drop = FALSE) } else { message("所有目标列均缺失") }
示例数据运行输出:
# A tibble: 3 × 3 A C n <chr> <lgl> <int> 1 1 NA 3 2 2 NA 1 3 7 NA 1
2. 生成tabyl格式结果
利用rlang包的符号转换与参数展开,适配tabyl的多维度调用:
library(janitor) library(rlang) target_cols <- c("A", "B", "C") existing_cols <- intersect(target_cols, names(dat)) # 根据存在列数动态调用tabyl if (length(existing_cols) > 0) { case_when( length(existing_cols) == 1 ~ dat %>% tabyl(!!sym(existing_cols)), length(existing_cols) == 2 ~ dat %>% tabyl(!!!syms(existing_cols)), length(existing_cols) == 3 ~ dat %>% tabyl(!!!syms(existing_cols)) ) } else { message("所有目标列均缺失") }
示例数据运行输出:
A NA 1 3 2 1 7 1
关键说明
intersect(target_cols, names(dat))精准过滤存在的目标列,避免列缺失报错across(all_of(existing_cols))配合count实现动态分组,.drop = FALSE保留所有组合(包括NA)rlang::syms将列名转为符号,!!!实现参数动态展开,完美适配tabyl的1/2/3维调用场景
内容的提问来源于stack exchange,提问作者FloriaT
相关产品推荐
相关产品推荐

