生存分析的门槛不在公式,在"每一行代表什么"。这篇按你实际操作的顺序讲:数据怎么排、图怎么读、检验怎么选、结论怎么写。
一、数据只要三列,但每一列都有坑
- time(随访时间):从"起点"到"终点"的时间。起点必须统一(入组日 / 手术日 / 首次给药日),混用会让结果直接失真。
- event(结局事件):1 = 发生,0 = 删失。编码反了是最常见的致命错误,会让 HR 完全反过来。
- group(分组):二分类或多分类;多分类时 log-rank 只能告诉你"有差异",不能告诉你是哪两组。
- 删失的含义:到研究结束时仍未发生事件、或失访。删失不是缺失值,不能删除,删了会系统性高估风险。
二、KM 曲线怎么读,别只看 P 值
- 中位生存时间 = 生存曲线跨过 0.5 的那个时间点;曲线始终在 0.5 以上时中位生存"未达到",这是结果,不是失败。
- 曲线尾部的台阶非常不稳(风险集人数很少):报告时给出各时间点的 number at risk。
- 两条曲线交叉 ⇒ 比例风险假设很可能不成立,此时单一 HR 没有意义,应报告中位生存或分时段 HR。
- log-rank 是"整条曲线"的比较,对早期/晚期差异不加权;加权版本(Gehan、Tarone-Ware)只在特定情形更合适。
三、log-rank 与 Cox 各回答什么
- log-rank:两组(或多组)生存分布是否不同 —— 不校正任何混杂,适合随机对照试验。
- Cox:在调整年龄、病情严重度等协变量后,某因素的独立效应(HR)—— 适合观察性研究。
- 两者不可互相替代:log-rank 显著的结论是"曲线不同",Cox 的结论是"校正后该因素每变化一单位,风险变为 HR 倍"。
- 比例风险假设必须检验(Schoenfeld 残差 / 时依协变量);不成立时改用分层 Cox、时依系数或 RMST。
四、五个最常见的错误
- 把"住院天数"当生存时间,却把"出院"当删失(出院不是删失,是竞争事件)。
- 组间比较用 t 检验或卡方,而不是 log-rank。
- 只报告 P 值,不报告 HR 与 95% CI —— 审稿人几乎一定要求补。
- 多因素 Cox 里塞入 10 个变量却只有 20 个事件(EPV < 10,模型过拟合)。
- 竞争风险存在时仍用 1−KM 估计累积发生率(会系统性高估)。
五、用接口直接算(可复制)
给时间和事件两个数组,直接返回 KM 估计、中位生存与 log-rank;需要校正混杂时改用生存分析全流程(KM + Cox + HR)。
REST:KM 曲线 + log-rank
curl -X POST https://sanyu.wentangkeji.com/api/open/v1/run/act_km_curve \
-H "Authorization: Bearer sk-sanyu-你的密钥" \
-H "Content-Type: application/json" \
-d '{"times":[5,12,18,24,30,42],"events":[1,1,0,1,1,0]}'
常见问题
- 生存分析需要多少例才够?
- 按事件数(不是样本量)算:Cox 回归的经验法则是每个协变量至少 10 个事件(EPV ≥ 10)。只有 20 个事件却放 5 个以上协变量,模型会过拟合,HR 的置信区间会宽到没有解释力。
- 中位生存时间显示"未达到"怎么办?
- 这是合法结果,写法是 "median OS was not reached"。同时应报告固定时间点的生存率(如 1 年、2 年 OS)与 number at risk,而不是硬凑一个中位数。
- 删失数据能不能直接删掉再做分析?
- 不能。删失样本贡献了"到删失时点为止未发生事件"的信息,删掉会高估风险、低估生存。删失是生存分析的核心机制,不是数据缺陷。