使用ggalluvial/ggsankey库处理缺失组合与脱落病例的绘图问题
问题需求
需要展示3个不同年份治疗组间的患者流动情况,数据存在脱落/新增患者:部分患者在后续年份缺失,或后续年份出现新患者,用"none"标记这些缺失组合。希望使用geom_sankey绘制桑基图时,保留正常的患者流动连线(冲积流),但隐藏标注为"none"或NA的分层节点。
解决方案
核心思路是预处理数据,过滤掉无效的"none"/NA节点,仅保留患者的有效流动路径,再生成桑基图数据。
步骤1:数据预处理
先将原始数据中的"none"统一替换为NA,再转换为宽格式:
library(tidyverse) library(ggsankey) # 合并年份数据并预处理 data <- bind_rows(data_2015, data_2017, data_2019) %>% select(sip, Year, Grp) %>% # 将"none"替换为NA,统一缺失值标记 mutate(Grp = ifelse(Grp == "none", NA, as.character(Grp))) %>% mutate(Grp = factor(Grp), Year = factor(Year)) %>% arrange(sip) %>% # 转换为宽格式:每一行是一个患者的三年分组情况 pivot_wider(names_from = Year, values_from = Grp)
步骤2:生成有效流动路径
提取每个患者的非NA分组记录,跳过缺失年份,直接连接前后有效分组:
# 处理每个患者的有效路径,跳过NA节点 df_sankey <- data %>% rowwise() %>% # 提取当前患者的非NA(年份,分组)对 mutate(valid_path = list( na.omit(tibble( year = c(`2015`, `2017`, `2019`), grp = c(`2015`, `2017`, `2019`) )) )) %>% ungroup() %>% unnest(valid_path) %>% # 为每个路径节点生成下一个节点信息 group_by(sip) %>% mutate( next_year = lead(year), next_grp = lead(grp) ) %>% # 过滤掉没有后续节点的行(每个患者的最后一个有效节点) drop_na(next_year, next_grp) %>% ungroup() %>% # 重命名为ggsankey要求的列名格式 rename( x = year, node = grp, next_x = next_year, next_node = next_grp ) %>% # 确保年份顺序正确 mutate( x = factor(x, levels = c("2015", "2017", "2019")), next_x = factor(next_x, levels = c("2015", "2017", "2019")) )
步骤3:绘制桑基图
使用处理后的有效路径数据绘图,此时不会出现NA/"none"的节点:
ggplot(df_sankey, aes( x = x, next_x = next_x, node = node, next_node = next_node, fill = factor(node), label = node, color = factor(node) )) + geom_sankey(flow.alpha = 0.5, node.color = 1) + geom_sankey_label(size = 3.5, color = 1, fill = "white") + scale_fill_viridis_d() + scale_colour_viridis_d() + theme_sankey(base_size = 16) + theme(legend.position = "none") + xlab("")
说明
- 该方法会自动跳过患者的缺失年份,直接连接前后有效治疗组的流动,同时完全隐藏无效的"none"/NA节点。
- 如果需要保留缺失年份的间隔(比如2015到2019的流动线跨过年份2017的位置),上述代码会自动处理,流动线会在对应的年份位置之间绘制。
内容的提问来源于stack exchange,提问作者RobertoT
相关产品推荐
相关产品推荐

