一个 III 期试验的主要终点常常是"第 24 周相对基线的变化"。脱落让每个受试者的观测条数
不同,而监管要的是所有随机受试者的平均治疗效应。这一段 PROC MIXED 就是为此而存在的:不设
随机效应,直接把残差协方差建成非结构化,用全部已观测数据估计边际均值差。读完你会知道每个选项为什么
在那儿、换掉它会付出什么代价,以及为什么真正决定成败的是揭盲前写进 SAP 的那几行。
研究编号、方案号、库中路径、程序头、作者与修订历史均已移除或泛化;输入数据集名泛化为
ADLBC / ADBDS;访视标签保留为通用英文。本笔记覆盖的是主要终点的主分析那一次
拟合:从分析数据集构建到访视内治疗差异的读出。它不覆盖多重插补、参考基准插补(J2R / CIR)、
tipping-point 敏感性分析,也不覆盖二分类与生存终点——那些是另一组模式。本书其余章节的精读见
《Linear Mixed Models》全书精读笔记:本篇用到的每一个概念在原书里的位置,
以及第 3、4、5、8、9 章的临床映射,都在那一篇。
一句话的需求,以及由它决定的数据形状。
需求:估计每个剂量组与安慰剂在第 24 周的基线变化之差,采用 treatment-policy 估计目标,并且 不丢弃任何一条已观测到的治疗后测量。第 24 周是主要时间点,但第 4、8、12、16 周的测量不是多余的—— 它们为协方差结构和脱落受试者的信息提供了依据。
输入是 ADaM BDS 的纵向形态:一行一个受试者 × 一个访视。这不是偏好问题,而是
REPEATED 语句要求的形状——SUBJECT= 识别聚类,REPEATED 的效应识别聚类
内部的位置。
| 变量 | 角色 | 在这段代码里的作用 |
|---|---|---|
USUBJID | 聚类标识 | REPEATED ... / SUBJECT= 的聚类单元;同时进 CLASS。V 矩阵的块由它切分。 |
AVISITN | 位置 | REPEATED AVISITN 的重复效应。必须是分类变量:进 CLASS,否则模型把时间当成连续直线。 |
TRTP | 计划治疗 | treatment-policy 估计目标下用计划分组,而非实际用药。 |
CHG | 响应 | AVAL - BASE。只在治疗后访视上定义;基线记录的 CHG 恒为 0。 |
BASE / BASE_C | 协变量 | 基线作为协变量进入模型,不是响应。BASE_C 是中心化版本,只影响截距的可读性。 |
ANL01FL | 纳入标志 | 分析集标志。注意它不等于"这条记录进入响应向量"——见第 5 节 F1。 |
三件事同时成立,才把问题推到 MMRM 上:(一)同一个受试者的多次测量彼此相关,任何假设观测独立
的过程都会低估标准误;(二)每个受试者的观测条数不同,脱落让数据天然不平衡;(三)要推断的是
总体平均,不是某个特定受试者的效应。前两条排除了 PROC GLM,第三条排除了带随机效应的
条件模型。
MMRM 不填补任何东西。它把每个受试者已观测到的那部分测量放进似然,缺失的那部分根本不出现——这就是 它"处理缺失数据"的全部含义,也是它在 MAR 下无偏、在 MNAR 下同样无能为力的原因。
只讲下面这段拟合所依赖的机制,其余一概不提。
带随机截距的 LMM 写成 Yₕ = Xₕβ + Zₕuₕ + εₕ。把它对
uₕ 积分掉,得到隐含的边际模型
Vₕ = Zₕ D Zₕ' + Rₕ
这说明两件实用的事。第一,随机截距 + 方差恒定的残差,其隐含边际模型就是复合对称(CS)
[doc]——所以"加随机截距"和"直接指定 CS 残差结构"在线性模型下是同一个模型,差别只在
你想推断什么。第二,MMRM 跳过了中间那一步:不写 RANDOM,直接把 Vₕ
建成非结构化。代价是不能推断方差分量和 EBLUP;收益是固定效应直接就是总体平均效应,而这正是
监管要的量。
非结构化不是"更高级",而是代价更高但假设更少。K 个访视的非结构化矩阵要估
K(K+1)/2 个参数,且随访视数平方增长。下面这些数字不是抄来的,是随笔记附带的
mmrm_check.sas 在 K = 5 的夹具上数出来的
[实践]。
| 结构 | 参数个数 | K = 5 | 什么时候用它,以及它的假设 |
|---|---|---|---|
| TYPE=UN | K(K+1)/2 | 15 | 主分析默认。不对方差与相关施加任何模式,因此不会因为结构错设而偏倚;代价是小样本下可能不收敛。 |
| TYPE=TOEP | 2K − 1 | 9 | UN 不收敛时的第一顺位降级。同一时间滞后共享一个相关,但方差仍可各访视不同。 |
| TYPE=AR(1) | 2 | 2 | 相关随时间间隔指数衰减。隐含等间隔假设——访视在 0/4/8/12/16/24 周时,间隔并非全部相等,用它需要论证。 |
| TYPE=CS | 2 | 2 | 任意两次观测相关相同、方差恒定。等价于随机截距模型的隐含边际结构,作为敏感性分析有意义,作为主分析假设过强。 |
| 默认(不写) | 1 | 1 | fail 残差独立同方差。纵向数据上漏写 TYPE= 等于完全没建模时间相关,标准误被严重低估。 |
REML 修正了 ML 因估计固定效应而损失的自由度,因此协方差参数要用 REML;但 REML 的似然依赖固定
效应设计矩阵,因此比较两个固定效应结构时必须切回 ML。这是同一段分析里会切换 METHOD=
的唯一正当理由 [doc]。校验程序 A12 / A13 断言了同一组固定效应在 ML 与 REML 下结构
一致——协方差参数个数与交互项的分子自由度都不变,变的只是协方差估计值。
无论 ML 还是 REML,固定效应的方差都因为用 V̂ 代替真实 V 而向下偏倚。
Kenward & Roger (1997) 的调整把 V̂ 的变异也计入,并给出近似的分母自由度
[lit]。在样本量只有几百、访视缺失又严重的 II/III 期试验里,这是把 I 类错误压回名义水平
的手段。校验程序 A14 断言 KR 的分母自由度与默认的 containment 不相同——如果两者相同,说明
DDFM=KR 根本没生效。
当前的实现,按步骤标注。 listings 与 mmrm_check.sas 逐语句一致。
data adbds;
set adlbc;
base_c = base - 26;
chg = aval - base;
if avisitn > 0 then output;
run;
三条语句各有一件事要说:
base_c = base - 26 —— 中心化。26 是基线总均值的近似,只为了让截距落在"基线
HAM-D 约 26 分的受试者"这个可解释的位置上。治疗对比不受影响;但它能显著降低截距与基线协变量之间
的共线,让收敛更稳。chg = aval - base —— 在真实 ADaM 里 CHG 通常已在上游算好,这里重建
一次只是为了说明它的定义。BASE 在 BDS 的每一行上都带着,所以不需要跨访视去取。if avisitn > 0 then output; —— 整段代码里最重要的一行。基线记录上的
CHG 恒等于 0,方差为 0;把它留在响应向量里,等于往非结构化矩阵塞进一个零方差的行列。
校验程序的 A11 断言响应向量里最小的 AVISITN 是 4 而不是 0。proc mixed data=adbds method=reml;
class usubjid trtp(ref='Placebo') avisitn;
model chg = base_c trtp avisitn trtp*avisitn / solution htype=3 ddfm=kr;
repeated avisitn / subject=usubjid type=un r=1 rcorr=1;
lsmeans trtp*avisitn / cl diff slice=avisitn;
ods output CovParms = cp_un
Tests3 = t3
LSMeans = lsm
SolutionF= solf;
run;
逐项:
| 写法 | 它承担什么,去掉会怎样 |
|---|---|
class ... avisitn | 把时间当分类变量。这样每个访视有自己的均值参数,响应轨迹可以是任意形状。若 AVISITN 不进 CLASS 而被当作数值,时间效应退化成一条直线,Type 3 的 AVISITN 分子自由度从 4 掉到 1——校验程序的 A6 就是抓这个的。 |
trtp(ref='Placebo') | 把安慰剂设为参照水平,使 solution 里的系数与 diff 的对比直接以安慰剂为基准,不依赖字母序。 |
trtp*avisitn | 允许治疗效应随访视变化。没有这一项,等于假设各访视的治疗效应相同,会掩盖真实的时程差异。代价:它通常是模型里最大的一项,也是 UN 不收敛时第一个被审查的对象。 |
repeated ... / subject=usubjid | 声明聚类单元。没有 RANDOM 语句是刻意的——这正是边际模型与条件模型的分界。 |
type=un | 非结构化。不写就是对角阵(见 2.2 的表格)。 |
r=1 rcorr=1 | 打印第一个受试者的 R 与相关矩阵。不是为了好看:这是审稿人判断"相关是否随时间间隔衰减"的唯一直接材料。 |
ddfm=kr | Kenward–Roger 自由度。见 2.4。 |
lsmeans ... / slice=avisitn | 给出每个访视内的组间两两比较,第 24 周那一组就是主要终点的对比。见 3.3。 |
ods output | 把 CovParms / Tests3 / LSMeans 落到数据集,供 TFL 复用。不要靠人工从 output 窗口抄数字。 |
slice=,不要手写系数想要"第 24 周,Drug_High 减 Placebo",最稳的写法是让 LSMEANS 自己去切,而不是手写
ESTIMATE 的系数向量。原因是后者对分类水平顺序极其敏感:交互项
TRTP*AVISITN 的 15 个列按 TRTP 慢变、AVISITN 快变排列,一旦
CLASS 的水平顺序因为 ORDER= 选项或数据内容而变,同一串系数指的就是别的对比,
而且不会报错。SLICE=AVISITN 按标签取值,不存在这个问题。
先在 CLASS 里固定水平顺序(例如加 ORDER=DATA 并用格式控制),再用
/ E 选项把 L 矩阵打印出来核对一遍系数落点。把这一步写进程序的注释里——
下一个接手的人是靠它判断对比对不对的。
先比较,再论证。
| 候选 | 结论 | 为什么 |
|---|---|---|
| MMRM(本笔记) | pass | 用全部已观测数据;MAR 下无偏;直接给出总体平均效应;UN 不施加相关模式;KR 控制小样本 I 类错误。代价是必须在 SAP 里把结构、估计方法、自由度方法和降级路径全部写死。 |
| LOCF + ANCOVA | fail | 假设脱落者此后的数值不再变化,与医学常识相悖;人为压低方差导致假阳性。ICH E9(R1) 与 FDA 缺失数据指南均不把它作为主分析 [doc]。它还能作为敏感性分析存在,但绝非主分析。 |
| Complete-case ANCOVA | defect | 只用在第 24 周有观测的受试者。脱落与疗效相关时直接引入选择偏倚,且丢弃了中间访视的全部信息。作为敏感性分析有价值,作为主分析不够。 |
| 随机截距 LMM | defect | 数学上等价于 CS 边际结构(2.1),等于给相关模式加了一个很强的假设;固定效应变成"给定随机效应为 0 时"的对象特异效应,与监管要的总体平均不是同一个量。 |
| GEE | defect | 同样估计总体平均,且作业相关设错也有稳健 SE 兜底。但标准 GEE 在 MAR 下并不自动有效(需要加权 GEE),且小样本下稳健 SE 偏乐观。更常见于不愿做强分布假设、或终点非连续的场合。 |
很多笔记(包括我自己的旧稿)写着"基线 × 访视交互是可选的,多数情况下不需要"。这句话在 2021 年被明确反驳过:Schuler 证明,在调整基线协变量却不包含"协变量 × 时间"交互时,MMRM 相对 complete-case ANCOVA 的功效增益与抗脱落偏倚能力都不再成立,并用模拟做了验证 [lit]。也就是说,加了基线协变量却不让它随时间变化,可能比不做纵向分析更糟。
把基线协变量放进模型,就要同时考虑 BASE_C * AVISITN。这不是"锦上添花",而是 MMRM 相对
单时点 ANCOVA 是否真的占优的前提条件。它要进 SAP,因为它是主分析模型的一部分。
它保证了什么,哪些输入它 silently 处理错,以及那些必须由人来补的缺口。
| 用例 | 输入形状 | MMRM 的处理 | 判定与后果 |
|---|---|---|---|
| S1 | 五个访视全部观测 | 5 行进入似然 | pass 完整贡献固定效应与协方差结构。 |
| S2 | 单调脱落,第 8 周后不再就诊 | 2 行进入似然 | pass 是 MMRM 存在的理由。前两访视既贡献均值轨迹,也贡献相关结构——受试者没有"被填补",只是缺失部分不进似然。校验程序 A17 断言夹具里存在脱落。 |
| S3 | 只有基线记录,无任何治疗后测量 | 0 行进入似然 | defect 被静默丢弃。受试者仍在 ITT 集里,却对主分析零贡献。校验程序 A15 断言夹具里存在这类受试者;报告里要说清楚主分析集与"实际进入模型的受试者数"的差额。 |
| S4 | 只观测到一次治疗后访视 | 1 行进入似然 | pass 仍被保留,贡献均值与方差,但不贡献相关。校验程序 A16 断言夹具里存在这类受试者。UN 能估出来靠的是别人,不是他。 |
| S5 | 访视间隔不等(4 / 4 / 4 / 4 / 8 周) | 当作分类位置处理 | pass CLASS 化之后间隔不等无所谓——这是 UN 相对 AR(1) 的实际优势。但如果改用 TYPE=AR(1),等间隔假设就被破坏了,此时应留在 UN 或 TOEP。 |
| S6 | 间歇性缺失(中间缺、后面又来) | 照常进入似然 | pass MMRM 不要求单调缺失模式,这正是它优于只能处理单调缺失的某些插补方案的地方。 |
ANL01FL = 'Y' 在真实 ADaM 里常常同时标在基线记录和治疗后记录上,因为它的含义是
"这条记录属于该分析集",不是"这条记录是响应"。直接 where anl01fl = 'Y' 就把
CHG = 0 的基线记录带进了模型:非结构化矩阵多出一行一列,其中方差为 0,拟合在边界上,
参数估计不可信。防御:显式 if avisitn > 0 then output;,并在校验里断言最小的
AVISITN。这一步不能靠"数据集上游已经处理过"来保证。
SAS 不会因为一个变量"看起来像访视编号"就当它是分类的。漏进 CLASS 时模型照常收敛、照常
出结果,只是时间效应变成一条直线,Type 3 的 AVISITN 分子自由度从 4 变成 1。没有报错,
没有警告。 防御:断言 Type 3 的分子自由度(校验程序 A6–A9)——交互项应为
(3−1) × (5−1) = 8。
看到 UN 的结果不满意再换成 CS,属于数据驱动的选择,会破坏 α 控制,是审评一定会被问的点。 防御不在代码里,在 SAP 里:把主分析结构和有序的降级路径(UN → TOEP → AR(1) → sandwich)在揭盲前 写死,并规定由谁记录偏差。代码能做的只有一件事:把实际使用的结构写进日志和 TFL 脚注。
一项对 2015–2018 年提交给汉诺威医学院伦理委员会的 39 个 II/III 期方案的实际检查发现:95% 规定了固定 效应与随机效应,但只有 77% 给出协方差矩阵结构,给出检验方法的 36%、估计方法的 28%、 计算方法的 3%、降级策略的 18% [lit]。也就是说,"UN + REML + KR"这套默认组合 之所以常见,很大程度上是因为它没被写下来时大家默认这么做——而不是因为它被论证过。这是写 SAP 时 最值得补的空白。
MMRM 的合法性建立在 MAR 上,而 MAR 无法用数据检验——要检验就得有缺失的那些值。因此它必须由
敏感性分析来补。行业会议上给出的成熟做法包括:把 pattern-mixture 模型表达为 MMRM 最小二乘均值的线性
组合,并用 delta 法把脱落/完成者比例本身的多项随机性并入方差(Ratitch & O'Kelly, PharmaSUG 2012
[lit]);以及在 MNAR 下用 PROC MI 做参考基准插补(J2R / CIR),再由
PROC MIANALYZE 合并(PharmaSUG 2025 [lit])。另一条常被忽略的界线是:
标准 MMRM 无法区分伴发事件前后的数据——当缺失与伴发事件(停药、补救用药)高度相关时,MAR 假设会
被实质性地违反,此时 treatment-policy 估计目标与标准 MMRM 之间出现裂缝(PharmaSUG China 2024
[lit])。
MMRM 是一个在 MAR 下无偏的估计器,不是一个"处理了缺失数据"的黑箱。它的可信度来自两处代码之外的 东西:揭盲前写死的模型设定,以及承认 MNAR 可能的敏感性分析。
换到另一个程序里之前,要改什么、要查什么。
| 要改的地方 | 改的时候注意什么 |
|---|---|
AVISITN > 0 的阈值 | 本例用 0 表示基线。若项目用 AVISITN = 99 或负数值标记基线/未计划访视,阈值要跟着变,否则会把不该进的记录放进去。 |
BASE_C 的中心化常数 | 26 是本例基线的近似总均值。换终点要换成新终点的数值——它只影响截距,但写错会让 Solution for Fixed Effects 里的截距无法解释。 |
| 固定效应列表 | 协变量必须逐条来自 SAP,不能来自"哪个显著"。分层因素(地区、基线疾病严重度)通常要进。 |
BASE_C * AVISITN | 按 4.1,默认应该考虑纳入。加进去要同时检查 UN 还收不收敛。 |
TYPE= 与降级路径 | 先确认访视数:K(K+1)/2 随访视数平方增长,8 个访视就是 36 个参数。样本量撑不住时,SAP 里就该预先写 TOEP。 |
DDFM= | KR 是默认选择。极不平衡或极大样本下 KR 计算开销明显,可考虑 ddfm=kr2 或 bw,但要在 SAP 里写明。 |
| 中心效应 | 本例未纳入。多中心试验里中心数少时作固定效应,中心数多时考虑随机效应——但随机中心效应会改变推断目标,需要统计师确认。 |
ODS OUTPUT 的表名 | Tests3 / SolutionF / CovParms / LSMeans 是 PROC MIXED 的表名;换成 PROC GLIMMIX 时部分表名不同,不要照抄。 |
SAS 源码保持全 ASCII:注释、TITLE、LABEL、%PUT 文案一律
英文。中文注释在中文环境里看着没问题,到了服务器的编码环境里会变成乱码,而且可能让程序头校验失败。
它断言什么,夹具长什么样,以及它刻意不解决什么。
mmrm_check.sas 是纯 Base SAS + SAS/STAT:没有研究宏、没有库名、
没有外部输入、不产生永久数据集。它用 CALL STREAMINIT(20260922) 造出 240 个受试者、3 个治疗组、
基线加 5 个治疗后访视的夹具,脱落是单调的且安慰剂组 hazard 更高——这就是一个症状性试验真实的样子。
sas mmrm_check.sas
17 条断言全部是结构性的。它们确定模型"是什么":每个协方差结构值多少参数(A2–A5)、 Type 3 的分子自由度是多少(A6–A9)、基线记录是否真的被排除(A11)、KR 是否真的改变了分母自由度 (A14)、夹具里是否真的存在那几种麻烦的受试者(A15–A17)。期望值不是写死的数字,而是从刚生成的夹具里 数出来的,所以断言不会随夹具漂移。
| 断言 | 内容 | 它挡住哪个错误 |
|---|---|---|
| A1, A11 | K = 5,响应向量最小 AVISITN = 4 | Finding 1:基线混进响应向量 |
| A2–A5 | UN 15 / CS 2 / TOEP 9 / AR(1) 2 | 结构成本算错、SAP 里参数预算写错 |
| A6–A9 | Type 3 分子自由度 4 / 2 / 8 / 1 | Finding 2:分类变量漏进 CLASS |
| A10 | TRTP*AVISITN 的 LS-means 共 15 行 | 单元格缺失、访视标签不一致 |
| A12, A13 | ML 与 REML 结构一致 | 报告用 REML 却在 ML 下比较模型 |
| A14 | KR 的分母自由度 ≠ containment | DDFM=KR 没生效 |
| A15–A17 | 夹具含"无响应""单次访视""有脱落"三类受试者 | 主分析集与"实际进模型的集"混为一谈 |
末尾还有一个脆弱块,由 %let RUN_FRAGILE = 0; 关掉:它把基线记录留在响应向量里再拟合
一次,打印出 6 × 6 非结构化 R 的协方差参数。这个块的失败本身就是结论,所以它被放在最后、
在日志里明确宣告,并且可以由调度跳过。
本笔记的每一条断言都可以被重跑,但它们没有被重跑过——写作环境里没有授权的 SAS。因此笔记里
没有一个数字是"某次运行的输出"。以下行为只有真实会话才能最终确认:UN 在本夹具上的收敛状态与具体
协方差参数估计值;KR 分母自由度的具体数值;SLICE= 输出的对比是否与
PROC MIANALYZE 路线一致;以及脆弱块究竟是报收敛失败还是给出一个零方差的参数估计。
如果你有许可证,跑一遍 mmrm_check.sas,17 条断言应当全部通过。