生存分析(Survival Analysis)是一种统计分析方法,用于研究时间至一个或多个事件发生的预期持续时长,这些事件可以包括各种感兴趣的情况,如心脏病发作、癌症缓解或死亡等。这个方法也被称为持续时间分析(Duration Analysis)或持续时间建模(Duration Modelling)、时间至事件分析(Time-to-Event Analysis)、可靠性分析(Reliability Analysis)和事件历史分析(Event History Analysis)。与其他类型的分析不同,生存分析具有独特的特点,因此需要不同的统计技术。
在这个上下文中,"生存"并不总是指死亡,而是指随着时间的推移而发生的各种事件。例如,员工的离职就是这种事件类型,可以利用生存分析的技术来分析员工流动率,为管理和招聘提供决策支持。这种分析有助于理解事件发生的时间模式,从而为组织提供更有效的人力资源策略和管理方法。
从lifelines的示例开始
lifelines 是一个用于建模和分析生存数据的 Python 库。它提供了多种生存分析工具,包括 Kaplan-Meier 生存曲线、Cox 比例风险模型、Aalen 加法风险模型等。
- Kaplan-Meier 生存曲线是一种非参数方法,用于估计生存概率。它适用于分析诸如患者存活时间等生存数据。使用 KaplanMeierFitter 类拟合生存曲线,通过 fit 方法拟合数据,然后使用 plot 方法绘制生存曲线图。
- Cox 比例风险模型是一种半参数方法,用于分析生存数据。它可以研究不同因素对生存时间的影响。使用 CoxPHFitter 类拟合 Cox 比例风险模型,通过 fit 方法拟合模型,然后进行参数估计和假设检验。
- Aalen 加法风险模型是一种考虑时间依赖性的生存分析方法,适用于具有时间相关危险率的数据。使用 AalenAdditiveFitter 类拟合 Aalen 加法风险模型,通过 fit 方法拟合模型,然后进行参数估计和假设检验。
lifelines 还提供了一系列生存分析统计量,例如中位生存时间、生存概率、累积危险函数等,用于描述生存数据的特征。
lefelines 示例数据集中包含163个观察结果,包含三列:
- T代表min(T, C),其中T为死亡时间,C为观测截止时间。
- E代表是否观察到“死亡”,1代表观测到了,0代表未观测到,即生存分析中的删失数据,共7个。
- group代表是否存在病毒, miR-137代表存在病毒,control代表为不存在即对照组,根据统计,存在miR-137病毒人数34人,不存在129人。
Kaplan-Meier 估计
估计生存函数的最简单方法是使用 Kaplan-Meier 估计量。其方程如下所示。基本上是计算每个时间点有多少人死亡/存活。其中,di 表示时间 ti 发生的死亡事件数,ni 表示时间 ti 时有生存风险的人数。
举个例子,我们有 21 个数据点。在时间 33,21 人中有 1 人死亡。因此,时间 33 的生存率计算为 1?1/21。在时间 54,剩下的 20 人中有 2 人死亡。在时间 61,剩下的 18 人中有 9 人死亡。在时间 67,我们只剩下 7 人,其中 6 人已经死亡。可以看出,Kaplan-Meier 估计是非常容易理解和计算的,即使是手动计算也很容易。
在 lifelines 中使用 KaplanMeierFitter,我们会得到相同的结果。除了下面的函数之外,我们还可以从 kmf.event_table 获取事件表,从 kmf.median_survival_times 获取中位生存时间(50% 的人口死亡的时间),以及从 kmf.confidence_interval_ 获取生存估计的置信区间。
from lifelines.datasets import load_waltons
df = load_waltons()
T = df['T']
E = df['E']
from lifelines import KaplanMeierFitter
kmf = KaplanMeierFitter()
kmf.fit(T, event_observed=E)
#print(kmf.survival_function_)
kmf.plot_survival_function()
Nelson-Aalen 估计
Nelson-Aalen 估计量首先通过以下方程估计危险率。其中,di 表示时间ti 发生的死亡事件数,ni 表示时间 ti 时有死亡风险的人数。我们可以通过下面的简单计算获得所有的危险率。
from lifelines import NelsonAalenFitter
naf = NelsonAalenFitter(nelson_aalen_smoothing=False)
naf.fit(T, event_observed=E)
naf.cumulative_hazard_
naf.plot_cumulative_hazard()
Kaplan-Meier 和 Nelson-Aalen 估计都是非参数的。它们易于解释,但没有功能形式,因此我们无法用它来建模分布函数。
指数模型(Exponential model)生存函数
指数分布基于泊松过程,其中事件以恒定的事件发生率 连续且独立地发生。指数分布模拟了事件发生前需要多长时间,其概率密度函数为 ()=xp(?),累积分布函数为 ()=(≤)=1?xp(?)。指数模型的累积分布函数表示了在时间 t 之后未生存的概率,但生存函数则相反。因此,对于生存函数:
- ()=1?()=exp(?)
- ?()=
- ()=
from lifelines import ExponentialFitter
exf=ExponentialFitter().fit(T,E,label='Exponential model')
exf.plot_survival_function()
威布尔模型(Weibull model)生存函数
指数分布是威布尔分布的特例:x~exp()~威布尔分布 (1/,1)。威布尔分布的累积分布函数为 ()=1?exp(?(/))。
- 当 < 1 时:失效率随时间降低
- 当 = 1 时:失效率保持恒定(指数分布)
- 当 > 1 时:失效率随时间增加
同样,我们可以将生存函数写作 1-F(t):
- ()=exp(?(/))
- ?()=/(/)^(?1)
- ()=(/)
from lifelines import WeibullFitter
wbf=WeibullFitter().fit(T,E,label='Weibull model')
wbf.plot_survival_function()
Cox 比例风险模型
Cox 比例风险模型是指当 0 变为 (0()) 时,基线风险是时间的函数。
?(|)=0()(∑)
其中:
- ?() 表示风险
- 0() 表示基线风险,随时间变化
- (∑) 表示部分风险,与时间无关
- xi 通常以均值为中心
from lifelines import CoxPHFitter
from lifelines.datasets import load_rossi
rossi_dataset = load_rossi()
cph = CoxPHFitter()
cph.fit(rossi_dataset, duration_col='week', event_col='arrest')
#cph.print_summary()
cph.plot()
#cph.plot_partial_effects_on_outcome()
#'plot', 'plot_covariate_groups', 'plot_partial_effects_on_outcome'
Aalen 加法风险模型(Aalen’s additive model)
h(tx)=b0(t)+b1(t)x1+...+bN(t)xN
from lifelines import AalenAdditiveFitter
df = pd.DataFrame({
'T': [5, 3, 9, 8, 7, 4, 4, 3, 2, 5, 6, 7],
'E': [1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0],
'var': [0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2],
'age': [4, 3, 9, 8, 7, 4, 4, 3, 2, 5, 6, 7],
})
aaf = AalenAdditiveFitter()
aaf.fit(df, 'T', 'E')
aaf.predict_median(df)
aaf.print_summary()
生存分析是一种重要的统计分析方法,用于研究事件发生的持续时间,无论这些事件是什么。它不仅限于分析死亡事件,还适用于各种其他情况,如疾病缓解、员工离职等。这种分析方法为研究人员提供了深入了解事件发生时间模式的途径,从而可以制定有效的战略和管理措施。
无论是医疗领域对患者治疗效果的研究,还是企业对员工留存率的分析,生存分析都发挥着关键作用。这种方法帮助我们深入了解事件发生的规律,从而为未来制定决策和规划提供支持。