估计目标框架与敏感性分析实战指南)
简介《ICH E9 R1估计目标及敏感性分析蓝皮书》由DIA中国统计社区发布面向临床试验统计分析师、数据管理人员及药企研发人员聚焦估计目标框架的设定与敏感性分析方法。资源为1个PDF文件压缩包约1.63MB内容涵盖ICH E9 R1修订背景、估计目标五大属性主要终点、指标、对照组、参数估计类型及参考值、伴发事件处理策略、主估计方法与敏感性分析、补充分析以及估计目标框架在试验方案中的呈现方式并附淋巴瘤CAR-T疗法、哮喘多臂三期试验等实际案例。已有2784人学习下载适合需要深入理解ICH E9 R1指南、提升临床试验统计设计规范性与结果解释力的从业者参考。1. 从「疗效到底该怎么算」说起ICH E9(R1) 估计目标框架为什么让统计师集体失眠如果你做过 III 期临床试验的统计分析计划大概率遇到过这种场面某受试者随机后吃了两周试验药因为不耐受停药换成了阳性对照药后来发生主要终点事件。问题来了——这个事件算不算试验药的疗效有人说不算因为受试者没按方案吃药有人说算因为随机化之后的事件就该归因到初始治疗组。两种算法结果差 15%注册申报时选哪个ICH E9(R1) 就是来终结这种「玄学」的。它要求你在试验设计阶段就把「估计目标」写清楚你到底想估计什么疗效是「不管吃没吃药、换没换药只要随机到我这组就算我的」还是「只要坚持吃我的药疗效就是我的」不同的问题对应不同的伴发事件处理策略而敏感性分析就是用来验证你的主分析结论在不同假设下是否站得住。这套框架 2019 年定稿后FDA、EMA、NMPA 陆续落地要求2022 年以后递交的 III 期试验基本都要在 SAP 里专门写估计目标章节。但真正动手写的时候你会发现伴发事件怎么分类假想策略和复合变量策略到底差在哪敏感性分析做几套才够这些问题在指导原则里只有框架没有模板。这篇笔记就是把我自己从零搭估计目标框架、跑敏感性分析的路径拆开让你能照着复现。2. 估计目标五要素拆解从「治什么人群」到「怎么算疗效」2.1 五要素不是五个词是一条逻辑链ICH E9(R1) 把估计目标定义为五个属性治疗条件、目标人群、变量、伴发事件的处理策略、群体层面汇总。很多人第一次看觉得就是五个填空题实际上它们之间有严格的依赖关系。治疗条件决定了你问的是什么问题。比如「试验药 标准治疗 vs 安慰剂 标准治疗」和「试验药单药 vs 安慰剂」是两个完全不同的估计目标后续所有选择都跟着变。目标人群不是简单的入排标准而是要明确「随机化之后的人群」还是「实际接受治疗的人群」——这直接决定了伴发事件的处理策略。变量是终点指标的定义包括测量时间点、测量方式、缺失值处理。伴发事件的处理策略是整套框架的核心ICH 给了五种治疗政策策略、假想策略、复合变量策略、在治策略、主层策略。群体层面汇总就是你的主要分析方法比如 Cox 比例风险模型、混合效应模型重复测量。我一般建议团队先把治疗条件和目标人群锁死再讨论变量和伴发事件。因为前两个变了后面全要重来。很多项目返工就是因为一开始没把「到底想问什么临床问题」说清楚写到一半发现策略选错了。2.2 五种伴发事件处理策略用一张表说清什么时候用哪个伴发事件是指随机化之后发生的、影响终点测量或解读的事件比如停药、换药、使用补救药物、死亡。不同策略对应不同的临床问题下面这张表是我在实际项目里总结的选型依据。策略核心逻辑适用临床问题典型终点分析人群治疗政策不管是否发生伴发事件都归因到初始随机组评估「开处方」的效果生存、住院ITT假想假设伴发事件未发生时的疗效评估「如果坚持治疗」的效果症状评分符合方案集复合变量把伴发事件本身作为不良结局纳入终点评估「净获益」复合终点ITT在治只评估实际在治期间的疗效评估「药物直接效应」生物标志物在治人群主层只在不会发生伴发事件的亚人群中评估评估「无伴发事件人群」的疗效任何主层人群选策略的时候有个血泪经验不要为了「好看」选假想策略。假想策略需要估计「如果没停药会怎样」这通常需要额外的统计假设审评时容易被挑战。如果临床问题允许治疗政策策略加复合变量策略的组合最稳妥因为不需要额外假设。2.3 从 SAP 到代码用 R 跑通一个估计目标的主分析假设你有一个 III 期肿瘤试验主要终点是 PFS伴发事件是「使用后续抗肿瘤治疗」。你的估计目标可能是在随机化人群中评估试验药 vs 对照药对 PFS 的疗效伴发事件采用治疗政策策略后续治疗不影响归因用 Cox 模型汇总。下面是用 R 的 survival 包跑主分析的代码library(survival) library(dplyr) # 假设数据框 trial_data 包含 # trt: 治疗组 (1试验, 0对照) # pfs_time: PFS 时间 (月) # pfs_event: 事件指示 (1事件, 0删失) # age, sex, ecog: 协变量 # 治疗政策策略所有随机化受试者纳入按初始分组分析 # 后续治疗不删失、不调整 # 拟合 Cox 比例风险模型 cox_fit - coxph( Surv(pfs_time, pfs_event) ~ trt age sex ecog, data trial_data ) # 输出结果 summary(cox_fit) # 提取 HR 和 95% CI hr - exp(coef(cox_fit)[trt]) ci - exp(confint(cox_fit)[trt, ]) cat(sprintf(HR %.3f (95%% CI: %.3f - %.3f)\n, hr, ci[1], ci[2]))这段代码的关键在于Surv(pfs_time, pfs_event)直接使用原始 PFS 数据不对后续治疗做任何删失或调整。这就是治疗政策策略的实现方式——所有随机化受试者都在分析集中事件归因到初始治疗组。参数说明trt的系数就是 log(HR)exp(coef)得到 HR。confint默认用 Wald 法如果样本量小可以用 profile likelihood。协变量根据 SAP 预先指定不要事后挑选。如果换成假想策略你需要对使用后续治疗的受试者在后续治疗开始时删失然后用逆概率加权或多重插补来估计「如果没使用后续治疗」的疗效。代码会复杂很多而且需要额外的敏感性分析来验证假设。3. 敏感性分析怎么设计从「随便跑跑」到「审评认可」3.1 敏感性分析不是越多越好而是要覆盖关键假设很多统计师第一次写敏感性分析恨不得把所有能跑的方法都跑一遍。审评老师看到 20 个敏感性分析第一反应不是「你好严谨」而是「你到底想掩盖什么」。ICH E9(R1) 的要求是敏感性分析要针对主分析的关键假设评估结论的稳健性。关键假设通常来自两个方面伴发事件处理策略的假设以及统计模型的假设。比如主分析用治疗政策策略关键假设是「后续治疗不影响试验药疗效的归因」。敏感性分析就可以用假想策略或复合变量策略来验证如果换一种伴发事件处理方式结论是否一致如果一致说明结论稳健如果不一致需要解释为什么。我一般建议做 3-5 个敏感性分析覆盖以下维度伴发事件处理策略的替代方案、缺失值处理的替代方案、分析人群的替代定义、统计模型的替代假设。每个敏感性分析都要在 SAP 里预先指定不能看结果再补。3.2 用多重插补做缺失值敏感性分析一个可复现的 R 实现缺失值是敏感性分析最常见的触发点。主分析如果用完整病例分析敏感性分析就可以用多重插补。下面是一个可复现的流程library(mice) library(survival) # 假设 trial_data 有缺失值 # 先查看缺失模式 md.pattern(trial_data) # 多重插补对缺失的协变量和结局进行插补 # m5 表示生成 5 个插补数据集 # maxit10 表示迭代 10 次 imp - mice(trial_data, m 5, maxit 10, seed 12345) # 在每个插补数据集上跑 Cox 模型 # 然后用 Rubin 规则合并 cox_imp - with(imp, coxph( Surv(pfs_time, pfs_event) ~ trt age sex ecog )) # 合并结果 pooled - pool(cox_imp) summary(pooled) # 提取合并后的 HR hr_pooled - exp(pooled$pooled$estimate[2]) cat(sprintf(Pooled HR %.3f\n, hr_pooled))这段代码的逻辑是先用mice对缺失值进行多重插补生成 5 个完整数据集然后在每个数据集上独立跑 Cox 模型最后用 Rubin 规则合并 5 个结果得到考虑插补不确定性的合并估计。参数说明m5是插补次数通常 5-20 次缺失比例高时用 20 次。maxit10是每次插补的迭代次数一般 5-10 次就收敛。seed保证结果可复现。pool()函数自动计算合并标准误和置信区间。注意多重插补的前提是缺失机制为随机缺失。如果缺失与未观测的结局相关需要用模式混合模型或 delta 调整法做更复杂的敏感性分析。这些方法在 SAP 里要写清楚假设和实现方式。3.3 敏感性分析的呈现一张森林图比十张表更有效敏感性分析的结果呈现很关键。审评老师不会逐行看你的表格他们更关注结论是否一致。我习惯用森林图把所有敏感性分析的 HR 和 95% CI 画在一起主分析用实线标注敏感性分析用不同颜色区分。下面是用 forestplot 包画图的代码library(forestplot) # 假设你已经跑完主分析和 4 个敏感性分析 # 整理结果 results - data.frame( analysis c(主分析 (治疗政策), 敏感性1 (假想策略), 敏感性2 (复合变量), 敏感性3 (多重插补), 敏感性4 (符合方案集)), hr c(0.75, 0.78, 0.72, 0.76, 0.80), lower c(0.62, 0.64, 0.58, 0.63, 0.66), upper c(0.91, 0.95, 0.89, 0.92, 0.97) ) # 画森林图 forestplot( labeltext results$analysis, mean results$hr, lower results$lower, upper results$upper, xlab Hazard Ratio, zero 1, graph.pos 2 )这张图能直观展示所有敏感性分析的 HR 都在 1 的左侧说明试验药优于对照药的结论在不同假设下都成立。如果某个敏感性分析的 CI 跨过 1就需要在讨论部分解释原因。参数说明zero1表示参考线在 HR1 处。graph.pos2表示图形放在第二列。labeltext是分析名称要写清楚每个敏感性分析对应的策略。4. 避坑指南估计目标和敏感性分析最容易翻车的五个地方4.1 伴发事件定义不清导致策略无法落地现象SAP 里写「伴发事件采用治疗政策策略」但没定义什么是伴发事件。结果分析时有人把「停药」算伴发事件有人把「换药」算伴发事件分析集不一致。原因ICH E9(R1) 要求伴发事件必须在 SAP 里预先定义包括事件类型、发生时间、处理方式。很多团队只写了策略名称没写具体定义。解决在 SAP 里用表格列出所有伴发事件包括事件名称、定义、发生时间窗口、对应策略、分析时如何处理。比如「后续抗肿瘤治疗随机化后首次使用任何非方案规定的抗肿瘤药物采用治疗政策策略不删失、不调整」。4.2 假想策略的假设太强审评不认可现象主分析用假想策略假设「如果受试者没停药疗效会持续」。审评质疑这个假设没有数据支持为什么认为停药后疗效和继续用药一样原因假想策略需要估计反事实通常需要额外的统计假设。如果假设太强审评会要求补充敏感性分析。解决如果临床问题允许优先用治疗政策策略或复合变量策略。如果必须用假想策略要在 SAP 里写清楚假设并用敏感性分析验证假设的合理性。比如用「停药后疗效立即消失」和「停药后疗效逐渐消失」两种假设分别分析。4.3 敏感性分析没有预先指定被质疑数据挖掘现象主分析结果不显著于是补了 5 个敏感性分析终于有一个显著了。审评质疑这些敏感性分析是预先指定的还是事后选的原因ICH E9(R1) 要求敏感性分析必须在 SAP 里预先指定包括分析方法、假设、判断标准。事后补的敏感性分析只能作为探索性分析。解决在揭盲前把敏感性分析的方案写进 SAP包括分析目的、方法、假设、与主分析的关系、结果解读标准。如果揭盲后需要补充要在报告中明确标注为「事后分析」。4.4 缺失值处理方法和伴发事件策略混淆现象SAP 里写「缺失值用多重插补」但没区分「缺失」和「伴发事件」。结果把停药后的缺失值也插补了导致假想策略和治疗政策策略混在一起。原因缺失值和伴发事件是两个不同的概念。缺失值是没观测到数据伴发事件是观测到了但影响解读。处理方法完全不同。解决在 SAP 里分开写缺失值处理和伴发事件处理。缺失值处理针对的是「应该观测但没观测到」的数据伴发事件处理针对的是「观测到了但需要决定如何归因」的数据。两者不能混。4.5 敏感性分析结果不一致时没有合理解释现象主分析 HR0.75敏感性分析 HR0.95结论不一致。审评问到底哪个结果可信原因敏感性分析不一致说明结论对假设敏感需要解释为什么。很多团队只报告结果不解释原因。解决在 SAP 里预先定义「一致性」的判断标准。比如如果所有敏感性分析的 HR 方向一致且 CI 重叠认为结论稳健如果不一致要分析原因比如某个敏感性分析的人群不同、假设不同。在讨论部分要诚实报告不一致并解释可能的来源。5. 进阶技巧用模拟研究验证估计目标框架的稳健性当你把估计目标和敏感性分析写进 SAP 之后还有一个问题没解决你怎么知道这套框架在样本量有限的情况下能正常工作这时候可以用模拟研究来验证。模拟研究的思路是设定一个真实的疗效参数生成模拟数据然后按照你的估计目标框架跑分析看估计值是否接近真实值覆盖率是否达到 95%。如果偏差大或覆盖率低说明框架有问题。下面是一个简单的模拟研究代码框架library(survival) library(mice) # 模拟参数 n_sim - 1000 # 模拟次数 n_sample - 500 # 每次模拟的样本量 true_hr - 0.75 # 真实 HR # 存储结果 results - data.frame( sim_id 1:n_sim, hr_main NA, hr_sens NA, cover_main NA, cover_sens NA ) for (i in 1:n_sim) { # 生成模拟数据 set.seed(i) trt - rbinom(n_sample, 1, 0.5) # 生成生存时间简化版实际要用更复杂的模型 pfs_time - rexp(n_sample, rate 0.1 * exp(-0.3 * trt)) pfs_event - rbinom(n_sample, 1, 0.7) # 主分析 fit_main - coxph(Surv(pfs_time, pfs_event) ~ trt) hr_main - exp(coef(fit_main)[trt]) ci_main - exp(confint(fit_main)[trt, ]) # 敏感性分析这里用简单替代实际要按策略实现 fit_sens - coxph(Surv(pfs_time, pfs_event) ~ trt) hr_sens - exp(coef(fit_sens)[trt]) ci_sens - exp(confint(fit_sens)[trt, ]) # 存储结果 results$hr_main[i] - hr_main results$hr_sens[i] - hr_sens results$cover_main[i] - (ci_main[1] true_hr true_hr ci_main[2]) results$cover_sens[i] - (ci_sens[1] true_hr true_hr ci_sens[2]) } # 汇总结果 cat(sprintf(主分析平均 HR: %.3f\n, mean(results$hr_main))) cat(sprintf(主分析覆盖率: %.1f%%\n, mean(results$cover_main) * 100)) cat(sprintf(敏感性分析平均 HR: %.3f\n, mean(results$hr_sens))) cat(sprintf(敏感性分析覆盖率: %.1f%%\n, mean(results$cover_sens) * 100))这段代码的逻辑是重复 1000 次模拟每次生成 500 个受试者的数据跑主分析和敏感性分析记录 HR 和覆盖率。最后看平均 HR 是否接近真实 HR覆盖率是否接近 95%。参数说明n_sim是模拟次数一般 1000-5000 次。n_sample是每次模拟的样本量要根据实际试验的样本量设定。true_hr是真实疗效参数根据临床假设设定。覆盖率是判断估计目标框架是否稳健的关键指标如果覆盖率低于 90%说明框架有问题。这个模拟研究可以在 SAP 定稿前跑用来验证你的估计目标框架是否合理。如果发现某个敏感性分析的覆盖率很低说明那个策略的假设太强需要调整。我自己做估计目标框架的时候最大的教训是不要等到分析阶段才想这些问题。估计目标必须在设计阶段就锁死敏感性分析必须在揭盲前就写好。一旦揭盲任何改动都会被质疑。所以我的习惯是在 SAP 定稿前把估计目标五要素、伴发事件处理策略、敏感性分析方案全部写清楚然后用模拟研究验证一遍。这样到了分析阶段就是按部就班跑代码不会手忙脚乱。希望帮到你。本文还有配套的精品资源点击获取