如何在gtsummary的tbl_svysummary/tbl_summary中使百分比凑整至100%
问题描述
我已掌握针对向量和表格的百分比凑整至100%的通用方案,但尚未找到在gtsummary包的tbl_svysummary()或tbl_summary()函数中的实现方法。我拥有一个包含分类变量和数值变量的加权dataframe(示例代码如下),需要获取比例和均值,但希望分类变量的各比例总和恰好为100%(而非99%或101%),且百分比保留0位或2位小数,请问是否有可行方法?
示例代码:
library(dplyr) library(gtsummary) set.seed(123) numerical_var <- rnorm(200, mean = 50, sd = 10) categories <- c("Category_A", "Category_B", "Category_C", "Category_D") categorical_var1 <- sample(categories, 200, replace = TRUE) categorical_var2 <- sample(categories, 200, replace = TRUE) categorical_var3 <- sample(categories, 200, replace = TRUE) weight_var <- runif(200, min = 0.003, max = 40) # Create the data frame df<- data.frame( num = numerical_var, cat1 = categorical_var1, cat2 = categorical_var2, cat3 = categorical_var3, wgt = weight_var ) # Create design object svy_design <- survey::svydesign( ~1, data = df, weights = ~wgt ) # Get frequencies svy_table <- svy_design %>% tbl_svysummary( by = cat1, statistic = all_categorical() ~ "{p}%" ) %>% add_p( group = cat1 ) svy_table %>% gtsummary::as_tibble() %>% writexl::write_xlsx( ., "test.xlsx" )
可行解决方案
方法1:自定义统计函数实现凑整
先实现一个能保证百分比总和为100%的凑整函数,再在tbl_svysummary()中指定使用该函数计算分类变量的百分比:
# 定义百分比凑整函数:保证总和为100% round_pct <- function(x, digits = 0) { pct <- x / sum(x) * 100 rounded <- round(pct, digits) diff <- 100 - sum(rounded) if (diff != 0) { # 将差值调整到与原始百分比偏差最大的项上 idx <- which.max(abs(pct - rounded)) rounded[idx] <- rounded[idx] + diff } paste0(rounded, "%") } # 在tbl_svysummary中使用自定义统计量 svy_table <- svy_design %>% tbl_svysummary( by = cat1, statistic = list( all_categorical() ~ "{round_pct(stat)}", all_continuous() ~ "{mean} ({sd})" ), digits = all_categorical() ~ 0 # 这里设置小数位数,需2位则改为2 ) %>% add_p(group = cat1)
方法2:表格生成后进行后处理
若不想修改统计计算流程,可在生成表格后转为tibble,再对百分比列进行调整:
# 导出原始表格为tibble svy_tbl <- svy_table %>% gtsummary::as_tibble() # 定义调整百分比总和的函数 adjust_pct_sum <- function(pct_col, digits = 0) { # 提取百分比中的数字部分 pct_num <- as.numeric(sub("%", "", pct_col)) # 计算与100%的差值 diff <- 100 - sum(pct_num) if (diff != 0) { # 选择偏差最大的项进行调整 idx <- which.max(abs(pct_num - round(pct_num, digits))) pct_num[idx] <- pct_num[idx] + diff } # 重新格式化为百分比字符串 paste0(round(pct_num, digits), "%") } # 对所有统计列(以stat_开头)进行调整 adjusted_tbl <- svy_tbl %>% mutate(across(starts_with("stat_"), ~adjust_pct_sum(., digits = 0))) # 导出调整后的表格 adjusted_tbl %>% writexl::write_xlsx("test_adjusted.xlsx")
关键说明
- 若需保留2位小数,只需将两个方法中的
digits参数改为2即可。 - 加权数据场景下,gtsummary会自动使用加权频数计算比例,无需额外处理加权逻辑。
- 调整逻辑采用“偏差最大项优先调整”的规则,是百分比凑整的通用做法,能最大程度保留原始比例的准确性。
内容的提问来源于stack exchange,提问作者blue-create
相关产品推荐
相关产品推荐

