Inicio rápido

Instalación

Instalar mediante pip:

pip install lifelines

O

Instalar mediante conda :

conda install -c conda-forge lifelines

Modelos de Kaplan-Meier, Nelson-Aalen y paramétricos

Nota

Para los lectores que busquen una introducción al análisis de supervivencia, se recomienda comenzar con Introducción al análisis de supervivencia

Comencemos importando algunos datos. Necesitamos saber la duración de las observaciones de los individuos y si "murieron" o no.

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']

Tes una matriz de duraciones, Ey es una matriz booleana o binaria que representa si se observó o no la “muerte” (alternativamente, un individuo puede ser censurado). Ajustaremos un modelo de Kaplan-Meier a esto, implementado como KaplanMeierFitter:

from lifelines import KaplanMeierFitter
kmf = KaplanMeierFitter()
kmf.fit(T, event_observed=E)  # or, more succinctly, kmf.fit(T, E)

Tras llamar al fit()método, tenemos acceso a nuevas propiedades survival_function_y métodos plot(). Este último es una interfaz para la biblioteca de gráficos interna de Pandas.

kmf.survival_function_
kmf.cumulative_density_
kmf.plot_survival_function()
_images/quickstart_kmf.png

Alternativamente, puede graficar la función de distribución acumulativa:

kmf.plot_cumulative_density()
_images/quickstart_kmf_cdf.png

Al especificar el timelineargumento de palabra clave en fit(), podemos cambiar la forma en que se indexan los modelos anteriores:

kmf.fit(T, E, timeline=range(0, 100, 2))

kmf.survival_function_   # index is now the same as range(0, 100, 2)
kmf.confidence_interval_ # index is now the same as range(0, 100, 2)

Un dato estadístico útil para resumir es el tiempo medio de supervivencia, que representa el momento en que ha fallecido el 50% de la población:

from lifelines.utils import median_survival_times

median_ = kmf.median_survival_time_
median_confidence_interval_ = median_survival_times(kmf.confidence_interval_)

En lugar del estimador de Kaplan-Meier, quizás le interese un modelo paramétrico. Lifelines incluye modelos paramétricos predefinidos, como por ejemplo Weibull, Log-Normal, Log-Logístico, entre otros.

import matplotlib.pyplot as plt
import numpy as np
from lifelines import *

fig, axes = plt.subplots(3, 3, figsize=(13.5, 7.5))

kmf = KaplanMeierFitter().fit(T, E, label='KaplanMeierFitter')
wbf = WeibullFitter().fit(T, E, label='WeibullFitter')
exf = ExponentialFitter().fit(T, E, label='ExponentialFitter')
lnf = LogNormalFitter().fit(T, E, label='LogNormalFitter')
llf = LogLogisticFitter().fit(T, E, label='LogLogisticFitter')
pwf = PiecewiseExponentialFitter([40, 60]).fit(T, E, label='PiecewiseExponentialFitter')
ggf = GeneralizedGammaFitter().fit(T, E, label='GeneralizedGammaFitter')
sf = SplineFitter(np.percentile(T.loc[E.astype(bool)], [0, 50, 100])).fit(T, E, label='SplineFitter')

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])
ggf.plot_survival_function(ax=axes[2][0])
sf.plot_survival_function(ax=axes[2][1])
_images/waltons_survival_function.png

Múltiples grupos

groups = df['group']
ix = (groups == 'miR-137')

kmf.fit(T[~ix], E[~ix], label='control')
ax = kmf.plot_survival_function()

kmf.fit(T[ix], E[ix], label='miR-137')
ax = kmf.plot_survival_function(ax=ax)
_images/quickstart_multi.png

Alternativamente, para muchos más grupos y más "al estilo panda":

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_survival_function(ax=ax)

Existe una funcionalidad similar para NelsonAalenFitter:

from lifelines import NelsonAalenFitter
naf = NelsonAalenFitter()
naf.fit(T, event_observed=E)

pero en lugar de que survival_function_se exponga algo, cumulative_hazard_se expone algo.

Nota

Al igual que en Scikit-Learn , todas las cantidades estimadas estadísticamente añaden un guion bajo al nombre de la propiedad.

Nota

En Análisis de supervivencia con líneas de vida se encuentran documentos más detallados sobre la estimación de la función de supervivencia y el riesgo acumulado .

Obtener los datos en el formato correcto

A menudo tendrás datos con el siguiente aspecto:

*start_time1*, *end_time1*
*start_time2*, *end_time2*
*start_time3*, None
*start_time4*, *end_time4*

Lifelines dispone de algunas funciones de utilidad para transformar este conjunto de datos en vectores de duración y censura. La más común es lifelines.utils.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')

Quizás le interese ver la tabla de supervivencia dadas ciertas duraciones y vectores de censura. La siguiente función lifelines.utils.survival_table_from_events()le ayudará con ello:

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
"""

regresión de supervivencia

Si bien el KaplanMeierFittermodelo anterior es útil, solo nos ofrece una visión «promedio» de la población. A menudo disponemos de datos específicos a nivel individual que nos gustaría utilizar. Para ello, recurrimos a la regresión de supervivencia .

Nota

En Regresión de Supervivencia se encuentran disponibles documentación y tutoriales más detallados .

El conjunto de datos para los modelos de regresión es diferente de los conjuntos de datos anteriores. Todos los datos, incluidas las duraciones, los indicadores censurados y las covariables, deben estar contenidos en un DataFrame de Pandas .

from lifelines.datasets import load_regression_dataset
regression_dataset = load_regression_dataset() # a Pandas DataFrame

Se crea una instancia de un modelo de regresión y se ajusta a un conjunto de datos fit. La columna de duración y la columna de evento se especifican en la llamada a la función fit. A continuación, modelamos nuestro conjunto de datos de regresión utilizando el modelo de riesgos proporcionales de Cox (documentación completa aquí) .

from lifelines import CoxPHFitter

# Using Cox Proportional Hazards model
cph = CoxPHFitter()
cph.fit(regression_dataset, 'T', event_col='E')
cph.print_summary()

"""
<lifelines.CoxPHFitter: fitted with 200 total observations, 11 right-censored observations>
             duration col = 'T'
                event col = 'E'
      baseline estimation = breslow
   number of observations = 200
number of events observed = 189
   partial log-likelihood = -807.62
         time fit was run = 2020-06-21 12:26:28 UTC

---
       coef  exp(coef)   se(coef)   coef lower 95%   coef upper 95%  exp(coef) lower 95%  exp(coef) upper 95%
var1   0.22       1.25       0.07             0.08             0.37                 1.08                 1.44
var2   0.05       1.05       0.08            -0.11             0.21                 0.89                 1.24
var3   0.22       1.24       0.08             0.07             0.37                 1.07                 1.44

        z      p   -log2(p)
var1 2.99 <0.005       8.49
var2 0.61   0.54       0.89
var3 2.88 <0.005       7.97
---
Concordance = 0.58
Partial AIC = 1621.24
log-likelihood ratio test = 15.54 on 3 df
-log2(p) of ll-ratio test = 9.47
"""

cph.plot()
_images/coxph_plot_quickstart.png

El mismo conjunto de datos, pero con un modelo de tiempo de falla acelerado de Weibull . Este modelo tiene dos parámetros (ver la documentación aquí ), y podemos optar por modelar ambos usando nuestras covariables o solo uno. A continuación, modelamos únicamente el parámetro de escala lambda_.

from lifelines import WeibullAFTFitter

wft = WeibullAFTFitter()
wft.fit(regression_dataset, 'T', event_col='E')
wft.print_summary()

"""
<lifelines.WeibullAFTFitter: fitted with 200 total observations, 11 right-censored observations>
             duration col = 'T'
                event col = 'E'
   number of observations = 200
number of events observed = 189
           log-likelihood = -504.48
         time fit was run = 2020-06-21 12:27:05 UTC

---
                     coef  exp(coef)   se(coef)   coef lower 95%   coef upper 95%  exp(coef) lower 95%  exp(coef) upper 95%
lambda_ var1        -0.08       0.92       0.02            -0.13            -0.04                 0.88                 0.97
        var2        -0.02       0.98       0.03            -0.07             0.04                 0.93                 1.04
        var3        -0.08       0.92       0.02            -0.13            -0.03                 0.88                 0.97
        Intercept   2.53      12.57       0.05             2.43             2.63                11.41                13.85
rho_    Intercept   1.09       2.98       0.05             0.99             1.20                 2.68                 3.32

                       z      p   -log2(p)
lambda_ var1       -3.45 <0.005      10.78
        var2       -0.56   0.57       0.80
        var3       -3.33 <0.005      10.15
        Intercept 51.12 <0.005        inf
rho_    Intercept 20.12 <0.005     296.66
---
Concordance = 0.58
AIC = 1018.97
log-likelihood ratio test = 19.73 on 3 df
-log2(p) of ll-ratio test = 12.34
"""

wft.plot()
_images/waft_plot_quickstart.png

También existen otros modelos AFT, véase aquí . Un modelo de regresión alternativo es el modelo aditivo de Aalen, que presenta riesgos variables en el tiempo:

# Using Aalen's Additive model
from lifelines import AalenAdditiveFitter
aaf = AalenAdditiveFitter(fit_intercept=False)
aaf.fit(regression_dataset, 'T', event_col='E')

Junto con `x` CoxPHFittere `y` WeibullAFTFitter, tras el ajuste tendrás acceso a propiedades como `x` e summary`y` y a métodos como plotpredict_cumulative_hazardsx` e `y` predict_survival_function. Los dos últimos métodos requieren un argumento adicional de covariables:

X = regression_dataset.loc[0]

ax = wft.predict_survival_function(X).rename(columns={0:'WeibullAFT'}).plot()
cph.predict_survival_function(X).rename(columns={0:'CoxPHFitter'}).plot(ax=ax)
aaf.predict_survival_function(X).rename(columns={0:'AalenAdditive'}).plot(ax=ax)
_images/quickstart_predict_aaf.png

Nota

En Regresión de Supervivencia se encuentran disponibles documentación y tutoriales más detallados .