如何用gtsummary的tbl_summary()处理数值列中的占位值?
问题
使用gtsummary包的tbl_summary()汇总调查数据时,数值列中的占位值会干扰统计结果。例如变量weight中,998代表“不知道/无答案”,999代表“拒绝回答”,直接调用tbl_summary()会将这些值纳入均值、标准差计算,导致结果失真。期望实现:
- 计算均值、标准差时排除998/999
- 单独显示这两个占位值的计数和占比
- 为统计项添加友好的描述性标签
初始代码及问题:
library(tidyverse) library(gtsummary) df <- tibble( weight = c( 72, 83, 65, 998, 79, 56, 999, 92, 67, 84, 998, 75, 68, 999, NA, 998, 73, 80, 91, NA ) ) tbl_summary( data = df, statistic = all_continuous() ~ "{mean} ({sd})" )
解决方案
方法1:预处理数据拆分变量(最直观)
将原始变量拆分为“有效数值”和“应答情况”两个变量,让gtsummary自动处理统计逻辑:
library(tidyverse) library(gtsummary) df_processed <- df %>% mutate( # 提取有效体重值,占位值转为NA weight_valid = ifelse(weight %in% c(998, 999), NA, weight), # 将占位值转为分类标签,有效数值转为NA weight_response = case_when( weight == 998 ~ "不知道/无答案", weight == 999 ~ "拒绝回答", TRUE ~ NA_character_ ) ) # 汇总并合并行(可选) tbl_summary( data = df_processed, include = c(weight_valid, weight_response), statistic = list( weight_valid ~ "{mean} ({sd})", weight_response ~ "{n} ({p}%)" ), label = list( weight_valid ~ "体重(有效数值)", weight_response ~ "体重应答情况" ) ) %>% # 可选:将两个变量的行合并到同一组 modify_table_body( mutate, variable = case_when( variable == "weight_response" ~ "weight_valid", TRUE ~ variable ) ) %>% modify_header(label ~ "**体重**")
方法2:自定义统计+标签修改(无需改原始数据)
直接在tbl_summary()中定义自定义统计函数,再通过modify_table_body修改标签:
library(tidyverse) library(gtsummary) df <- tibble( weight = c( 72, 83, 65, 998, 79, 56, 999, 92, 67, 84, 998, 75, 68, 999, NA, 998, 73, 80, 91, NA ) ) # 定义简洁的自定义统计函数 stat_funs <- list( mean_sd = function(x) { x_clean <- x[!x %in% c(998, 999) & !is.na(x)] paste0(round(mean(x_clean), 1), " (", round(sd(x_clean), 1), ")") }, donknow = function(x) { n <- sum(x == 998, na.rm = TRUE) p <- round(n/length(x)*100, 1) paste0(n, " (", p, "%)") }, refused = function(x) { n <- sum(x == 999, na.rm = TRUE) p <- round(n/length(x)*100, 1) paste0(n, " (", p, "%)") } ) tbl_summary(df, type = weight ~ "continuous2", statistic = weight ~ c("{mean_sd}", "{donknow}", "{refused}") ) %>% # 修改统计项的显示标签 modify_table_body( mutate, label = case_when( row_type == "statistic" & label == "{mean_sd}" ~ "均值(标准差)", row_type == "statistic" & label == "{donknow}" ~ "不知道/无答案", row_type == "statistic" & label == "{refused}" ~ "拒绝回答", TRUE ~ label ) ) %>% modify_header(label ~ "**体重**")
方法3:用add_stat()追加占位值统计(贴合gtsummary工作流)
先计算有效数值的统计,再通过add_stat()添加占位值的统计行:
library(tidyverse) library(gtsummary) df <- tibble( weight = c( 72, 83, 65, 998, 79, 56, 999, 92, 67, 84, 998, 75, 68, 999, NA, 998, 73, 80, 91, NA ) ) # 先汇总有效数值(排除占位值) tbl <- df %>% mutate(weight = ifelse(weight %in% c(998, 999), NA, weight)) %>% tbl_summary( statistic = weight ~ "{mean} ({sd})", label = weight ~ "体重" ) # 添加占位值的统计行 tbl %>% add_stat( fns = list( ~ paste0(sum(.x == 998, na.rm=T), " (", round(sum(.x == 998, na.rm=T)/length(.x)*100,1), "%)"), ~ paste0(sum(.x == 999, na.rm=T), " (", round(sum(.x == 999, na.rm=T)/length(.x)*100,1), "%)") ), location = "after", label = c("不知道/无答案", "拒绝回答") )
内容的提问来源于stack exchange,提问作者Reiko Okamoto
相关产品推荐
相关产品推荐

