lifelines 生存数据生成指南:3 步构建你的模拟数据集
【免费下载链接】lifelinesSurvival analysis in Python项目地址: https://gitcode.com/gh_mirrors/li/lifelines
真实生存数据获取贵、采集慢,还受隐私限制。lifelines 数据生成模块 generate_datasets 让你几分钟造出带协变量、带截尾的合成生存数据。按这篇指南,你 30 秒跑通最小示例,再用三步流水线定制自己的模拟生存数据集。
快速上手:一个能跑的最小示例
先说结论:指数分布是最简单的起点,没有协变量,跑起来也最快。
import numpy as np from lifelines.generate_datasets import exponential_survival_data np.random.seed(123) # 固定种子,让结果可复现 times, events = exponential_survival_data( n=1000, # 样本量 cr=0.2, # 截尾(Censoring)比例:约两成样本只被"看到一半" scale=5.0 # 指数分布尺度参数,越大存活越久 ) print(times[:5], events[:5]) # 看一眼前 5 个样本times 是观测时间,被截尾的样本会停在截尾时刻;events 是布尔标记,True 表示事件发生,False 表示截尾。把这两列交给 KaplanMeierFitter,就能直接画出生存曲线。
三步流水线:数据生成背后的逻辑
跑通之后你可能会问:带协变量的数据是怎么造出来的?整条链路是「协变量 → 风险率 → 生存时间」三步。
第一步,协变量。generate_covariates(n, d, n_binary, p)生成 (n, d+1) 矩阵:连续列服从指数分布,二值列是 0/1,最后一列全为 1,留给截距项。
第二步,风险率。generate_hazard_rates把协变量和系数相乘,得到每个个体在每个时刻的风险率。这里给两个直觉:生存函数 S(t) 回答"活过 t 时刻的概率",它随时间单调下降;风险函数 h(t) 回答"此刻事件发生的瞬时速率"。两者的关系是 S(t) = exp(−∫h(u)du),累积风险越大,存活概率越低。
第三步,生存时间。generate_random_lifetimes对累积风险做反演,抽出每个人的事件时间。这里有个容易忽略的点:真实随访里总有人到期末还没发生事件。给模拟叠加截尾(Censoring)就是在模拟这件事——超过截尾时刻的样本只记录到该时刻,事件标记改为 False。
核心函数速查
六个函数覆盖从简单到定制的全部需求,先记住名字和分工:
| 函数 | 用途 | 关键参数 |
|---|---|---|
exponential_survival_data | 生成指数分布生存数据,带截尾 | n样本量;cr截尾比例 |
piecewise_exponential_survival_data | 生成风险率分段的生存数据,无截尾 | breakpoints变点;lambdas各段风险率 |
generate_covariates | 生成连续+二值协变量矩阵 | d协变量数;n_binary二值列数 |
generate_hazard_rates | 由协变量算出每个个体的风险率 | model取 cox/aalen;constant系数是否恒定 |
generate_random_lifetimes | 从风险率反演生存时间,可选截尾 | censor截尾开关或截尾时刻 |
generate_observational_matrix | 一站式生成协变量+事件时间矩阵,无截尾 | model取 cox/aalen;timelines时间轴 |
最常用的就是中间三步,串起来就是完整调用链:
import numpy as np from lifelines.generate_datasets import generate_hazard_rates, generate_random_lifetimes timelines = np.linspace(0, 100, 1000) # 观测时间轴:0 到 100 共 1000 个点 hazard_rates, coefs, covariates = generate_hazard_rates( n=1000, d=5, timelines=timelines, model="cox" # 比例风险模型(Cox PH) ) times, observed = generate_random_lifetimes( hazard_rates, timelines, censor=True # 叠加均匀截尾 ) print(times.shape, observed.mean()) # 数据形状与事件发生率model="cox"表示比例风险模型(Cox PH),风险比不随时间变;换成"aalen"则是加法风险模型,系数可以随时间漂移。
进阶:让模拟数据更贴近真实场景
真实场景里,协变量的分布和组间差异才是数据"像不像"的关键。
模拟 SaaS 客户流失数据
import numpy as np from lifelines.generate_datasets import generate_covariates np.random.seed(42) # 固定种子,保证每次结果一致 # 2 个二值列模拟套餐等级、是否企业客户 x = generate_covariates(n=1000, d=6, n_binary=2, p=0.3)连续列由指数分布生成,可当作使用频率、接口调用量这类特征;n_binary=2把两列换成 0/1,p=0.3控制"高级套餐"这类少数派占比。后面接generate_random_lifetimes时,把censor设成一个具体时刻,让约两成客户在观测期末仍在用,模拟"还没流失"。
模拟医疗随访数据
import numpy as np age = np.random.normal(55, 12, size=1000).clip(30) # 年龄:均值55、标准差12,截到30以上 treat = np.random.binomial(1, 0.5, size=1000) # 治疗组/对照组各占一半 hz = np.exp(0.04 * (age - 55) / 12) * np.where(treat, 0.6, 1.0)年龄取正态(55, 12) 再 clip 到 30 以上,贴合成人随访队列的常识。np.where给治疗组风险打六折,相当于风险比(HR)约 0.6,模拟"治疗有效",对照组保持 1.0。
参数怎么选:避免踩坑
这 5 个参数最容易在第一次模拟时翻车:
| 参数 | 推荐值 | 注意事项 |
|---|---|---|
n | ≥ 1000 | 太小曲线跳动剧烈,估计不稳;太大模拟变慢 |
d | 3–8 | 维度太高容易过拟合,系数也难以解释 |
cr | 0.1–0.3 | 截尾比例过高会让事件变少,参数方差变大 |
model | cox 或 aalen | 相信比例风险用 cox;系数随时间变用 aalen |
breakpoints/lambdas | 2–3 个变点 | lambdas必须比breakpoints多 1 段;该函数不产生截尾 |
还有一个隐藏坑:cr只作用于exponential_survival_data,其他函数要传censor参数来控制截尾。
总结与下一步
你手里现在有一条完整的 Python 生存分析数据生成链路:协变量 → 风险率 → 生存时间,外加两个分布类的快捷函数。调好n、d、cr这几个旋钮,就能造出覆盖流失、随访等场景的自定义生存数据集。想看内部怎么抽样,直接翻源码比读文档更快。
git clone https://gitcode.com/gh_mirrors/li/lifelines源码入口:lifelines.generate_datasets 模块
跑通第一个模拟数据集之后,你会发现自己离能用的生存模型只差一张图。
【免费下载链接】lifelinesSurvival analysis in Python项目地址: https://gitcode.com/gh_mirrors/li/lifelines
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考