英文原版链接
通过pip来安装:
pip install lifelines
让我们从数据开始吧。首先需要观察每个人的生存时间,以及终点事件(记录观察实验结束时,每个被观察者已经死去或仍活着)。
from lifelines.datasets import load_waltons
df = load_waltons() # returns a Pandas DataFrame
print(df.head())
"""
T E group
0 6 1 miR-137
1 13 1 miR-137
2 13 1 miR-137
3 13 1 miR-137
4 19 1 miR-137
"""
T = df['T']
E = df['E']
数组T是生存时间,E是一个布尔变量,表示终点事件(观察实验结束时候,被观察者是已死去还是仍活着)。
注意:lifelines假设所有的"死亡"时间都被观察到了。
from lifelines import KaplanMeierFitter
kmf = KaplanMeierFitter()
kmf.fit(T, event_observed=E) # or, more succinctly, kmf.fit(T, E)
调用fit方法后,我们就可以调用kmf的属性survival_function_以及方法plot()。后者是Pandas内部plotting库的高级封装。
kmf.survival_function_
kmf.median_
kmf.plot()
采用KM算法获得的生存曲线如下图所示:
也许你并不想采用KM算法,而是希望采用参数模型。恭喜,lifelines内置了常用的参数模型。例如,Weibull,Log-Logistic等等。
fig, axes = plt.subplots(2, 3, figsize=(9, 5))
kmf = KaplanMeierFitter().fit(T, E, label='KaplanMeierFitter')
wbf = WeibullFitter().fit(T, E, label='WeibullFitter')
exf = ExponentialFitter().fit(T, E, label='ExponentalFitter')
lnf = LogNormalFitter().fit(T, E, label='LogNormalFitter')
llf = LogLogisticFitter().fit(T, E, label='LogLogisticFitter')
pwf = PiecewiseExponentialFitter([40, 60]).fit(T, E, label='PiecewiseExponentialFitter')
wbf.plot_survival_function(ax=axes[0][0])
exf.plot_survival_function(ax=axes[0][1])
lnf.plot_survival_function(ax=axes[0][2])
kmf.plot_survival_function(ax=axes[1][0])
llf.plot_survival_function(ax=axes[1][1])
pwf.plot_survival_function(ax=axes[1][2])
groups = df['group']
ix = (groups == 'miR-137')
kmf.fit(T[~ix], E[~ix], label='control')
ax = kmf.plot()
kmf.fit(T[ix], E[ix], label='miR-137')
ax = kmf.plot(ax=ax)
对于更多分组(Pandas),可采用以下代码来绘制生存曲线
ax = plt.subplot(111)
kmf = KaplanMeierFitter()
for name, grouped_df in df.groupby('group'):
kmf.fit(grouped_df["T"], grouped_df["E"], label=name)
kmf.plot(ax=ax)
类似的功能也存在于NelsonAalenFitter:
from lifelines import NelsonAalenFitter
naf = NelsonAalenFitter()
naf.fit(T, event_observed=E)
但是NelsonAalenFitter不具有survival_function_方法,
与Similar to Scikit-Learn相似,在lifelines里,所有的统计估计量都在名称后面带有一条下划线。
关于生存函数和累计风险的详细介绍,可前往该链接(目前尚未上线)查看。
很多时候,你手上的数据可能是这样格式的:
*start_time1*, *end_time1*
*start_time2*, *end_time2*
*start_time3*, None
*start_time4*, *end_time4*
lifelines内置一些功能函数,可以将数据转化为生存时间和删失数据向量。最常用的一个是datetimes_to_durations。datetimes_to_durations的说明文档在这里(尚未上线)。
from lifelines.utils import datetimes_to_durations
# start_times is a vector or list of datetime objects or datetime strings
# end_times is a vector or list of (possibly missing) datetime objects or datetime strings
T, E = datetimes_to_durations(start_times, end_times, freq='h')
也许你想看看生存表格,那么可以采用survival_table_from_events来绘制:
from lifelines.utils import survival_table_from_events
table = survival_table_from_events(T, E)
print(table.head())
"""
removed observed censored entrance at_risk
event_at
0 0 0 0 163 163
6 1 1 0 0 163
7 2 1 1 0 162
9 3 3 0 0 160
13 3 3 0 0 157
"""
虽然KaplanMeierFitter和NelsonAalenFitter很有用,但是他们只能给出一个集合的整体情况。很多时候,我们对个体数据感兴趣,无论该数据是连续数据还是分类数据。这时候,我们可以采用生存回归方法,即AalenAdditiveFitter,WeibullAFTFitter和CoxPHFitter。
from lifelines.datasets import load_regression_dataset
regression_dataset = load_regression_dataset()
regression_dataset.head()
在生存回归问题中,fit方法的输入与生存分析问题不太一样。所有的数据,包括生存时间、删失数据以及协变量都必须包含在Pandas DataFrame中(是滴,你没看错)。生存时间列和终点时间列必须在fit方法中指明。以下,采用Cox比例风险模型来分析了我们的生存回归数据集。
from lifelines import CoxPHFitter
# Using Cox Proportional Hazards model
cph = CoxPHFitter()
cph.fit(regression_dataset, 'T', event_col='E')
cph.print_summary()
"""
duration col = 'T'
event col = 'E'
number of subjects = 200
number of events = 189
log-likelihood = -807.62
time fit was run = 2019-01-27 23:11:22 UTC
---
coef exp(coef) se(coef) z p -log2(p) lower 0.95 upper 0.95
var1 0.22 1.25 0.07 2.99 <0.005 8.49 0.08 0.37
var2 0.05 1.05 0.08 0.61 0.54 0.89 -0.11 0.21
var3 0.22 1.24 0.08 2.88 <0.005 7.97 0.07 0.37
---
Concordance = 0.58
Likelihood ratio test = 15.54 on 3 df, -log2(p)=9.47
"""
cph.plot()
同样的数据集,采用 Weibull Accelerated Failure Time model。这个模型具有2组参数(详情查看这里(该链接尚未上线)),我们可以选择采用两组参数、也可以选择采用其中一组参数。以下代码块仅采用比例参数:lamda_。
from lifelines import WeibullAFTFitter
wft = WeibullAFTFitter()
wft.fit(regression_dataset, 'T', event_col='E', ancillary_df=regression_dataset)
wft.print_summary()
"""
duration col = 'T'
event col = 'E'
number of subjects = 200
number of events = 189
log-likelihood = -504.48
time fit was run = 2019-02-19 22:07:57 UTC
---
coef exp(coef) se(coef) z p -log2(p) lower 0.95 upper 0.95
lambda_ var1 -0.08 0.92 0.02 -3.45 <0.005 10.78 -0.13 -0.04
var2 -0.02 0.98 0.03 -0.56 0.57 0.80 -0.07 0.04
var3 -0.08 0.92 0.02 -3.33 <0.005 10.15 -0.13 -0.03
_intercept 2.53 12.57 0.05 51.12 <0.005 inf 2.43 2.63
rho_ _intercept 1.09 2.98 0.05 20.12 <0.005 296.66 0.99 1.20
---
Concordance = 0.58
Log-likelihood ratio test = 19.73 on 3 df, -log2(p)=12.34
"""
wft.plot()
至于Aalen’s Additive model模型,它可以对时变风险进行建模:
# Using Aalen's Additive model
from lifelines import AalenAdditiveFitter
aaf = AalenAdditiveFitter(fit_intercept=False)
aaf.fit(regression_dataset, 'T', event_col='E')
与CoxPHFitter、WeibullAFTFitter一样,在fitting之后,我们就可以获得cumulative_hazards_属性,以及plot、predict_cumulative_hazards、predict_survival_function等方法。后两者需一个额外的输入参数——关于数据个体的协变量。
X = regression_dataset.drop(['E', 'T'], axis=1)
aaf.predict_survival_function(X.iloc[10:12]).plot() # get the unique survival functions of two subjects
与其它模型一样,AalenAdditiveFitter也内置一个绘图方法:
aaf.plot()