Можно ли запустить модель Кокса-Пропорционально-Опасных Опасностей с экспоненциальным распределением базовой опасности в "линиях жизни" или другом пакете?

Я считаю использование lifelines пакет, чтобы соответствовать модели Кокса-Пропорционально-Опасности. Я читал, что линии жизни используют непараметрический подход, чтобы соответствовать базовой опасности, что приводит к различным baseline_hazards для некоторых моментов времени (см. Пример кода ниже). Для моего приложения мне нужно экспоненциальное распределение, приводящее к базовой опасности h0(t) = lambda, которая постоянна во времени.

Таким образом, мой вопрос: возможно ли (в то же время) запустить модель Кокса-Пропорционально-Опасности-опасности с экспоненциальным распределением для базовой опасности в lifelines или другой пакет Python?

Пример кода:

from lifelines import CoxPHFitter
import pandas as pd

df = pd.DataFrame({'duration': [4, 6, 5, 5, 4, 6], 
                   'event': [0, 0, 0, 1, 1, 1], 
                   'cat': [0, 1, 0, 1, 0, 1]})

cph = CoxPHFitter()
cph.fit(df, duration_col='duration', event_col='event', show_progress=True)
cph.baseline_hazard_

дает

        baseline hazard
T   
4.0     0.160573
5.0     0.278119
6.0     0.658032

1 ответ

Решение

Автор спасательных кругов здесь.

Таким образом, эта модель изначально не существует, но вы можете легко реализовать ее самостоятельно (и, возможно, что-то, что я сделаю для будущего выпуска). Эта идея опирается на пересечение моделей пропорциональной опасности и моделей AFT (ускоренное время отказа). В модели cox-ph с экспоненциальной опасностью (то есть постоянной базовой опасностью) опасность выглядит следующим образом:

h(t|x) = lambda_0(t) * exp(beta * x) = lambda_0 * exp(beta * x)

В спецификации AFT для экспоненциального распределения опасность выглядит следующим образом:

h(t|x) = exp(-beta * x - beta_0) = exp(-beta * x) * exp(-beta_0) = exp(-beta * x) * lambda_0

Обратите внимание на разницу отрицательных знаков!

Таким образом, вместо того, чтобы делать CoxPH, мы можем сделать экспоненциальную подборку AFT (и перевернуть знаки, если мы хотим получить ту же интерпретацию, что и CoxPH). Мы можем использовать синтаксис пользовательской модели регулярности для этого:

from lifelines.fitters import ParametricRegressionFitter
from autograd import numpy as np


class ExponentialAFTFitter(ParametricRegressionFitter):

    # this is necessary, and should always be a non-empty list of strings.
    _fitted_parameter_names = ['lambda_']

    def _cumulative_hazard(self, params, T, Xs):
        # params is a dictionary that maps unknown parameters to a numpy vector.
        # Xs is a dictionary that maps unknown parameters to a numpy 2d array
        lambda_ = np.exp(np.dot(Xs['lambda_'], params['lambda_']))
        return T / lambda_

Проверяя это,

from lifelines.datasets import load_rossi
from lifelines import CoxPHFitter

rossi = load_rossi()
rossi['intercept'] = 1
regressors = {'lambda_': rossi.columns}
eaf = ExponentialAFTFitter().fit(rossi, "week", "arrest", regressors=regressors)

eaf.print_summary()
"""
<lifelines.ExponentialAFTFitter: fitted with 432 observations, 318 censored>
         event col = 'arrest'
number of subjects = 432
  number of events = 114
    log-likelihood = -686.37
  time fit was run = 2019-06-27 15:13:18 UTC

---
                    coef exp(coef)  se(coef)     z      p  -log2(p)  lower 0.95  upper 0.95
lambda_ fin         0.37      1.44      0.19  1.92   0.06      4.18       -0.01        0.74
        age         0.06      1.06      0.02  2.55   0.01      6.52        0.01        0.10
        race       -0.30      0.74      0.31 -0.99   0.32      1.63       -0.91        0.30
        wexp        0.15      1.16      0.21  0.69   0.49      1.03       -0.27        0.56
        mar         0.43      1.53      0.38  1.12   0.26      1.93       -0.32        1.17
        paro        0.08      1.09      0.20  0.42   0.67      0.57       -0.30        0.47
        prio       -0.09      0.92      0.03 -3.03 <0.005      8.65       -0.14       -0.03
        _intercept  4.05     57.44      0.59  6.91 <0.005     37.61        2.90        5.20
_fixed  _intercept  0.00      1.00      0.00   nan    nan       nan        0.00        0.00
---
"""

CoxPHFitter().fit(load_rossi(), 'week', 'arrest').print_summary()
"""
<lifelines.CoxPHFitter: fitted with 432 observations, 318 censored>
      duration col = 'week'
         event col = 'arrest'
number of subjects = 432
  number of events = 114
partial log-likelihood = -658.75
  time fit was run = 2019-06-27 15:17:41 UTC

---
      coef exp(coef)  se(coef)     z      p  -log2(p)  lower 0.95  upper 0.95
fin  -0.38      0.68      0.19 -1.98   0.05      4.40       -0.75       -0.00
age  -0.06      0.94      0.02 -2.61   0.01      6.79       -0.10       -0.01
race  0.31      1.37      0.31  1.02   0.31      1.70       -0.29        0.92
wexp -0.15      0.86      0.21 -0.71   0.48      1.06       -0.57        0.27
mar  -0.43      0.65      0.38 -1.14   0.26      1.97       -1.18        0.31
paro -0.08      0.92      0.20 -0.43   0.66      0.59       -0.47        0.30
prio  0.09      1.10      0.03  3.19 <0.005      9.48        0.04        0.15
---
Concordance = 0.64
Log-likelihood ratio test = 33.27 on 7 df, -log2(p)=15.37
"""

Обратите внимание на изменение знака! Так что если вы хотите постоянную базовую опасность в модели, это exp(-4.05),

Другие вопросы по тегам