,公卫/临床科研人必看!)
开源R包medstats搞定医学统计全流程附 10 个代码示例 临床研究者的统计焦虑做过临床研究的小伙伴一定深有体会——数据分析这条路坑太多了痛点传统做法基线特征表手动计算各组均值、频数再复制到 Word 排版单因素多因素回归逐个变量跑模型手动整理结果到表格K-M 生存曲线survminer 参数一大堆风险表也难搞森林图forestplot 包用法复杂数据格式难搞限制性立方样条RCSrms 包学起来陡峭画图还容易报错ROC 曲线 最佳截断值pROC 用完还要手动算 cutoff表格和图片导出到 Word截图、复制、粘贴、调格式……无穷无尽的体力活 medstatsmedstats是一个专为临床医学统计和流行病学研究设计的 R 包由开发者GitHub: shanjiayu1开发并开源。它将临床研究中最常用的统计分析流程封装为15 个核心函数覆盖从数据清洗、统计建模到可视化、结果导出的全链路工作流。一句话概括装一个包干完一整篇论文的统计分析。✨ 核心功能与亮点medstats 的 15 个导出函数可分为四大模块1️⃣ 数据处理模块long_to_surv_data()—— 将纵向临床记录一键转换为一人一行的生存分析数据格式merge_duplicate_records()—— 合并重复记录自动取每列第一个非缺失值make_table1()—— 生成基线特征表支持分组比较2️⃣ 统计建模模块run_glm_auto()—— 自动批量运行单因素 多因素广义线性模型线性回归、Logistic 回归run_cox_auto()—— 自动批量运行单因素 多因素 Cox 回归longdata_analysis()—— 重复测量数据综合分析描述统计 组间比较 GEE 模型3️⃣ 可视化模块plot_km()—— K-M 累积事件曲线 风险表plot_forest()—— 发表级森林图plot_rcs()—— 限制性立方样条图支持线性模型和 Cox 模型plot_roc()—— ROC 曲线 AUC 最佳截断值plot_sankey()—— 桑基图状态流转可视化plot_meanse()—— 均值 ± 标准误折线图plot_stacked()—— 堆叠百分比柱状图4️⃣ 表格与导出模块format_flextable()—— 一行代码将数据框/gtsummary 对象格式化为发表级三线表export_word()—— 将多个表格和图片一键导出到同一个 Word 文档 亮点总结亮点说明全流程覆盖从数据清洗到结果导出一条龙服务一键自动化回归模型自动跑单因素多因素无需手动逐个变量操作发表级输出三线表、森林图、K-M 曲线直接可用于论文Word 一键导出表格 图片混合导出告别手动排版中文友好提供中文 README 文档函数参数清晰易懂依赖主流包基于 ggplot2、gtsummary、survival、rms 等成熟生态 安装方式medstats 目前在 GitHub 上开发维护使用remotes包安装即可# 安装 remotes如已安装可跳过 install.packages(remotes) # 安装 medstats remotes::install_github( shanjiayu1/medstats, dependencies TRUE ) # 加载包 library(medstats) 使用dependencies TRUE会同时安装示例、测试和 vignette 所需的依赖包推荐使用。 使用示例示例 1一键生成发表级三线表library(medstats) # 直接格式化数据框 ft_data - format_flextable(head(mtcars[, 1:5])) table1 - make_table1( data gtsummary::trial, vars c(age, marker, stage, grade), specific_vars marker, # Report as median (P25, P75) group_var trt ) table1示例 2批量跑 Logistic /COX 回归生成整理后的结果# 一行代码搞定单因素 多因素 Logistic 回归 logistic_results - run_glm_auto( data gtsummary::trial, vars c(age, stage), outcome_var response, family binomial ) # 格式化为发表级表格 format_flextable(logistic_results)回归表自动使用上标模型标记脚注标注¹ Univariable analysis.和² Multivariable analysis.无需手动添加。示例 3K-M 生存曲线 风险表library(survival) # 准备数据 lung_data - survival::lung lung_data$status_event - as.integer(lung_data$status 2) lung_data$sex - factor( lung_data$sex, levels c(1, 2), labels c(Male, Female) ) # 一行画 K-M 曲线 plot_km( data lung_data, group_var sex, time_var time, status_var status_event, legend_labs c(Male, Female), legend_title Sex, xlab Follow-up time (days), ylab Cumulative mortality (%), xlim c(0, 1000), break_time 200, show_risk_table TRUE, # 自动添加风险表 save_filename Lung_KM.png )示例 4限制性立方样条RCS# 线性模型 RCS rcs_linear - plot_rcs( data mtcars, exposure wt, outcome mpg, covars c(hp, disp), nk 4, model_type linear, xlab Weight, ylab Predicted MPG ) rcs_linear$plot # Cox 模型 RCS lung_rcs - survival::lung lung_rcs$status_event - as.integer(lung_rcs$status 2) rcs_cox - plot_rcs( data lung_rcs, exposure age, outcome Surv(time, status_event), covars c(sex, ph.ecog), model_type cox, xlab Age, ylab Hazard Ratio ) rcs_cox$plot示例 5森林图forest_data - data.frame( Variable c(Age, Stage II, Stage III), OR (95% CI) c( 1.02 (0.99, 1.05), 1.45 (0.82, 2.56), 2.10 (1.12, 3.94) ), P value c(0.180, 0.200, 0.021), check.names FALSE ) plot_forest( data forest_data, ci_column OR (95% CI), x_ticks c(0, 0.5, 1, 2, 4), output_name Forest_plot.png )示例 6ROC 曲线 AUC 最佳截断值 诊断试验评价利器一行代码画出 ROC 曲线自动标注 AUC 值和最佳截断点再也不用手动算 Youden 指数了。library(medstats) # 使用 survival 包的 lung 数据集演示 # 假设我们想用 age 预测患者是否在随访期内死亡 library(survival) lung_data - survival::lung lung_data$status_event - as.integer(lung_data$status 2) # 一行代码绘制 ROC 曲线 roc_result - plot_roc( data lung_data, marker_var age, # 预测变量连续变量 outcome_var status_event, # 二分类结局0/1 positive_label 1, # 阳性事件的编码值 xlab 1 - Specificity, ylab Sensitivity, save_filename ROC_age.png ) # 查看结果AUC、最佳截断值、灵敏度、特异度 roc_result$auc # AUC 值 roc_result$best_cutoff # 最佳截断值 roc_result$sensitivity # 对应灵敏度 roc_result$specificity # 对应特异度 函数自动使用 Youden 指数灵敏度 特异度 - 1确定最佳截断值并标注在曲线上。适合诊断试验、标志物评价等场景。示例 7桑基图状态流转可视化随访数据中患者状态在不同时间点之间如何流转桑基图一图胜千言直观展示患者从轻症到重症再到康复的动态变化轨迹。library(medstats) # 使用 ChickWeight 数据集演示患者状态流转 sankey_data - datasets::ChickWeight | dplyr::filter(Time %in% c(0, 10, 20)) | dplyr::mutate( # 将连续变量离散化为状态类别 visit factor( paste0(Day , Time), levels c(Day 0, Day 10, Day 20) ), weight_status dplyr::case_when( weight 50 ~ Light, # 轻量 weight 150 ~ Normal, # 正常 TRUE ~ Heavy # 重量级 ), weight_status factor( weight_status, levels c(Light, Normal, Heavy) ) ) # 一行代码绘制桑基图 sankey_plot - plot_sankey( data sankey_data, id_var Chick, # 个体 ID time_var visit, # 时间点变量 state_var weight_status, # 状态变量 na_strategy show, # 缺失值的处理策略显示为单独的流 missing_label Drop-out # 缺失值的标签名 ) sankey_plot 非常适合展示纵向随访研究中患者状态的流转路径如疾病分期变化、治疗方案的切换等。na_strategy show可将脱访患者单独显示方便评估失访情况。示例 8均值 ± 标准误折线图 纵向随访研究中各组的均值随时间如何变化折线图 误差棒 组间差异检验一气呵成。library(medstats) # 使用 ChickWeight 数据集提取关键时间点 growth_data - datasets::ChickWeight | dplyr::filter(Time %in% c(0, 4, 10, 14, 21)) | dplyr::mutate( time_label paste0(Day , Time), diet_label paste0(Diet , Diet) ) # 绘制各饮食组的均值 ± 标准误折线图 meanse_result - plot_meanse( data growth_data, target_var weight, # 数值结局变量 time_var time_label, # 时间点变量 group_var diet_label, # 分组变量 xlab Growth time (days), ylab Mean weight (g), legend_title Diet ) meanse_result$plot # 两两组比较自动在每个时间点进行组间差异检验 two_diet_result - plot_meanse( data dplyr::filter(growth_data, diet_label %in% c(Diet 1, Diet 2)), target_var weight, time_var time_label, group_var diet_label, test_method wilcox, # 使用 Wilcoxon 秩和检验 legend_title Diet ) # 查看每个时间点的 p 值 two_diet_result$test_data 设置test_method t或wilcox后函数会在每个时间点自动进行两组比较显著结果直接标注在图上对应位置p 值可通过$test_data获取。非常适合纵向随访的组间趋势对比示例 9堆叠百分比柱状图 想看各分类在不同时间点的占比变化堆叠百分比柱状图让趋势一目了然。library(medstats) # 使用 ChickWeight 数据集将体重离散化 stacked_data - datasets::ChickWeight stacked_data$Time - factor( stacked_data$Time, levels sort(unique(stacked_data$Time)) ) # 绘制堆叠百分比柱状图 stacked_result - plot_stacked( data stacked_data, target_var weight, # 数值变量将被离散化 time_var Time, # 时间点变量 group_var Diet, # 分组变量可选 breaks c(-Inf, 100, 200, 300, Inf), # 离散化分界点 labels c(≤100 g, 101–200 g, 201–300 g, 300 g), # 分段标签 colors c(#B5D1E8, #A3D9A5, #F2C68F, #EB938F), # 自定义配色 legend_title Weight range, label_size 4.5 # 柱内百分比标签字号 ) stacked_result$plotgroup_var NULL默认时每个时间点画一个堆叠柱设置group_var后百分比按时间×组别计算各组并排展示。用label_size调整柱内百分比字号colors自定义配色方案出图即发表级示例 10表格 图片一键导出 Word# 准备表格和图片 table1 - head(mtcars) p1 - ggplot2::ggplot(mtcars, ggplot2::aes(wt, mpg)) ggplot2::geom_point() # 详细方式自定义标题 export_word( data_list list(table1, p1), table_titles c( Table 1. mtcars dataset, Figure 1. MPG and weight ), output_file tables_and_plots.docx, figure_width 6, figure_height 5 ) # 简化方式直接传入对象标题自动生成 export_word(table1, p1, tables_and_plots.docx) 表格标题在表格上方图片标题在图片下方符合学术规范。还可以混入 PNG 文件路径自动按比例缩放。 应用场景medstats 适用于但不限于以下场景场景适用人群临床队列研究生成基线表、K-M 曲线、Cox 回归病例对照研究Logistic 回归、森林图纵向随访研究重复测量分析、均值趋势图、桑基图诊断试验评价ROC 曲线、AUC、最佳截断值剂量-反应关系RCS 样条图多中心研究数据整合重复记录合并论文撰写三线表 图片一键导出 Word无论你是临床医生——想快速完成论文统计部分研究生/博士生——正在为毕业论文的数据分析发愁流行病学研究者——需要处理大量随访数据药企统计师——需要标准化、可复现的统计流程medstats 都能帮你大幅提升效率️ 技术架构medstats 的代码结构清晰按功能模块组织medstats-clinical-r/ ├── R/ │ ├──>核心依赖包medstats 站在巨人的肩膀上整合了 R 生态中最优秀的包依赖包用途ggplot2绘图引擎gtsummary汇总表生成flextableofficer表格格式化与 Word 导出survivalsurvminer生存分析rms限制性立方样条geepackGEE 广义估计方程forestplot森林图pROCROC 分析ggalluvial桑基图broomcoin统计检验与结果整理 总结medstats是一个小而美的 R 包它不试图重新发明轮子而是将临床研究中最常用的统计分析流程串联起来用最简洁的接口完成最复杂的工作✅15 个核心函数覆盖临床统计全流程✅一行代码完成批量回归 格式化✅发表级三线表、K-M 曲线、森林图、RCS 图✅一键导出 Word表格图片混合排版✅中文文档支持上手零门槛如果你正在做临床研究、写论文、处理随访数据medstats 绝对值得一试项目地址https://github.com/shanjiayu1/medstats-clinical-r安装命令remotes::install_github(shanjiayu1/medstats, dependencies TRUE)觉得好用的话别忘了给个 Star ⭐ 支持一下开发者也欢迎在 Issues 中提出建议和反馈。本文基于 medstats v0.1.0 版本的仓库内容撰写所有代码示例均来自项目 README。