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

R语言janitor包tabyl生成的adorn_ns表格如何按Total列降序排序

问题:janitor包tabyl生成交叉表后adorn_ns追加数值无法正确排序

问题背景

调用janitor包的tabyl函数生成交叉表后,无法对adorn_ns()追加的数值正确排序。需求是按「Total」列的频数降序排序后,传入knitr::kable()用于报表输出。
直接对tabyl对象调用arrange排序后,adorn_ns()会将N值填充到原始位置而非排序后的位置,该问题的成因是tabyl排序时其core属性未同步变更。手动设置因子顺序调整行序的方案效率太低,不适用于类别多、需要复用表格生成逻辑的场景。

示例代码与现象

基础生成代码(未排序)

library(dplyr)
library(janitor)

# 示例数据
var1 <- c("aaa", "bbb", "ccc", "ccc", "ddd", "ddd", "ddd", "ddd", "aaa", "ddd", "ddd", "bbb", "bbb", "ddd")
sex <- c("f", "f", "m", "f", "m", "m", "f", "f", "m", "m", "f", "m", "f", "f")
df <- data.frame(var1,sex)

# 生成含频数、占比、合计的交叉表
tabyl(df, var1, sex) %>%
  adorn_totals(where = c("col", "row")) %>%
  adorn_percentages("col") %>%
  adorn_pct_formatting(digits = 0) %>%
  adorn_ns(position = "front")

输出结果符合预期:

var1fmTotal
aaa1 (12%)1 (17%)2 (14%)
bbb2 (25%)1 (17%)3 (21%)
ccc1 (12%)1 (17%)2 (14%)
ddd4 (50%)3 (50%)7 (50%)
Total8 (100%)6 (100%)14 (100%)

预期效果(按Total降序排序)

var1fmTotal
ddd4 (50%)3 (50%)7 (50%)
bbb2 (25%)1 (17%)3 (21%)
aaa1 (12%)1 (17%)2 (14%)
ccc1 (12%)1 (17%)2 (14%)
Total8 (100%)6 (100%)14 (100%)

错误尝试与现象

直接在流程中加arrange排序,会出现N值错位、百分比计算错误的问题:

df %>% tabyl(var1,sex) %>%
  adorn_totals(where = "col") %>%
  arrange(desc(Total)) %>%
  adorn_totals(where = "row") %>%
  adorn_percentages("col") %>%
  adorn_pct_formatting(digits = 0) %>%
  adorn_ns(position = "front") 

错误输出:

var1fmTotal
ddd1 (50%)1 (50%)2 (50%)
bbb2 (25%)1 (17%)3 (21%)
aaa1 (12%)1 (17%)2 (14%)
ccc4 (12%)3 (17%)7 (14%)
Total8 (100%)6 (100%)14 (100%)

解决方案

方案1:提前按频数重设因子顺序(推荐,复用性高)

无需手动指定因子水平,通过forcats::fct_infreq自动将分类变量调整为按出现频数降序的因子,tabyl会默认按因子顺序生成表格,从根源避免排序错位问题。

library(dplyr)
library(janitor)
library(forcats)

# 示例数据
var1 <- c("aaa", "bbb", "ccc", "ccc", "ddd", "ddd", "ddd", "ddd", "aaa", "ddd", "ddd", "bbb", "bbb", "ddd")
sex <- c("f", "f", "m", "f", "m", "m", "f", "f", "m", "m", "f", "m", "f", "f")
df <- data.frame(var1,sex)

# 自动将var1转换为按频数降序的因子
df$var1 <- fct_infreq(df$var1)

# 原有生成流程无需调整
tabyl(df, var1, sex) %>%
  adorn_totals(where = c("col", "row")) %>%
  adorn_percentages("col") %>%
  adorn_pct_formatting(digits = 0) %>%
  adorn_ns(position = "front")

方案2:排序后手动传入自定义N值

如果不想改动原始数据的因子结构,可以在排序后提取对应顺序的频数矩阵,传入adorn_ns的ns参数,覆盖默认读取的未排序core属性值。

library(dplyr)
library(janitor)

# 示例数据
var1 <- c("aaa", "bbb", "ccc", "ccc", "ddd", "ddd", "ddd", "ddd", "aaa", "ddd", "ddd", "bbb", "bbb", "ddd")
sex <- c("f", "f", "m", "f", "m", "m", "f", "f", "m", "m", "f", "m", "f", "f")
df <- data.frame(var1,sex)

# 1. 生成原始核心频数表并按Total排序
core_tab <- tabyl(df, var1, sex) %>%
  adorn_totals(where = "col")
sorted_core <- arrange(core_tab, desc(Total))

# 2. 提取排序后的频数作为自定义N值
custom_ns <- sorted_core[, -1]

# 3. 后续加工时传入自定义N值
sorted_core %>%
  adorn_totals(where = "row") %>%
  adorn_percentages("col") %>%
  adorn_pct_formatting(digits = 0) %>%
  adorn_ns(position = "front", ns = custom_ns)

两种方案都可以得到预期的排序结果,封装为函数后即可复用到不同变量的交叉表生成场景。


内容的提问来源于stack exchange,提问作者Saskia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 15:06:03