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

R语言ftable输出交叉表如何按子组追加列百分比标注

R实现三维交叉表分组列百分比标注

核心逻辑是按A-E主维度拆分,分别计算每个主分组下Group1、Group2的列合计,逐单元格计算列百分比后和原频数拼接,最终输出和ftable一致的折叠显示格式。


完整实现代码

1. 数据准备

如果已经生成了ftable对象,先用as.data.frame()转为数据框,再重塑为「主分类、行分类、Group1频数、Group2频数」的结构即可。以下用你给出的示例数据做演示:

# 构造示例数据,已有ftable对象可跳过这步
tab_df <- data.frame(
  main_cat = rep(c("A","B","C","D","E"), each = 4),
  row_cat = rep(c("I","II","III",NA), 5),
  Group1 = c(78,51,13,29, 182,110,74,0, 386,284,240,0, 6,5,6,0, 164,181,0,0),
  Group2 = c(74,45,17,22, 13,16,6,0, 47,28,42,0, 0,2,5,0, 17,31,0,0)
)

2. 分组计算百分比并拼接格式

按主分类分组计算列合计,自动处理除以0的异常:

library(dplyr)

result_tab <- tab_df %>%
  group_by(main_cat) %>%
  mutate(
    # 计算当前主分组下两列的总频数
    g1_sum = sum(Group1),
    g2_sum = sum(Group2),
    # 计算列百分比,保留3位小数,总频数为0时直接返回0避免报错
    g1_pct = ifelse(g1_sum == 0, 0, round(Group1 / g1_sum * 100, 3)),
    g2_pct = ifelse(g2_sum == 0, 0, round(Group2 / g2_sum * 100, 3)),
    # 拼接为「频数(百分比%)」格式,频数为0时直接显示0(0%)
    `Group 1` = ifelse(Group1 == 0, "0(0%)", paste0(Group1, "(", g1_pct, "%)")),
    `Group 2` = ifelse(Group2 == 0, "0(0%)", paste0(Group2, "(", g2_pct, "%)"))
  ) %>%
  ungroup() %>%
  select(main_cat, row_cat, `Group 1`, `Group 2`)

3. 格式化输出为ftable样式

将重复的主分类名称替换为空,实现原生ftable的折叠缩进效果:

# 同主分类仅第一行显示分类名,其余行留空
result_tab$main_cat[duplicated(result_tab$main_cat)] <- ""

# 右对齐打印结果
print(result_tab, right = TRUE, row.names = FALSE)

计算结果说明

运行后A组输出和你给出的计算逻辑完全匹配:

main_cat row_cat     Group 1     Group 2
        A       I  78(45.614%)  74(46.835%)
                II  51(29.825%)  45(28.481%)
               III   13(7.602%)  17(10.759%)
              <NA>  29(16.959%)  22(13.924%)
        B       I 182(49.727%)  13(37.143%)
                II 110(30.055%)  16(45.714%)
               III  74(20.219%)   6(17.143%)
              <NA>       0(0%)       0(0%)
        ...      ...         ...          ...

数值微小差异是四舍五入规则导致,可自行调整取整逻辑。


自定义调整说明

  • 百分比小数位数:修改round()函数的第二个参数即可,比如保留2位小数就写round(..., 2)
  • 对齐效果:如果需要让所有括号纵向对齐,可以用sprintf()做格式化,比如sprintf("%-3d(%0.3f%%)", Group1, g1_pct)会自动补空格对齐数值和括号
  • 从ftable对象转换:如果直接用ftable()生成了表,先用as.data.frame(ftable_obj)转为长格式,再用tidyr::pivot_wider()把列分组转为宽表结构,后续计算逻辑完全相同

内容的提问来源于stack exchange,提问作者Ahir Bhairav Orai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 01:42:17