Dans ce cas, je crois qu'un chemin vers une solution existe si nous mettons notre chapeau d'analyse de survie. Notez que même si ce modèle n'a pas de sujets censurés (au sens traditionnel), nous pouvons toujours utiliser l'analyse de survie et parler des dangers des sujets.
Nous devons modéliser trois choses dans cet ordre: i) le risque cumulatif, ii) le danger, iii) la probabilité logarithmique.
H( t )H( t ) = - logS( t )T∼ Po i ( λ )
HT( t ) = - log( 1 - Q ( t , λ ) ) =-logP( t , λ )
Q , P
Maintenant, nous voulons ajouter les "risques" de l'assurance qui s'épuise. La bonne chose à propos des dangers cumulatifs est qu'ils sont additifs, nous devons donc simplement ajouter des "risques" aux moments 7, 14, 21:
HT′( t ) = - logP( t , λ ) + a ⋅ 1(t > 7 )+ b⋅ 1(t > 14 )+ c ⋅ 1( t > 21)
>a , bc
c
HT′( t ) = - logP( t , λ ) +a⋅ 1( t > 7 )+ b ⋅ 1( t > 14 )+ ∞ ⋅ 1( t > 21 )
h ( t )
h ( t ) = 1 - exp( H( t ) - H( t + 1 ) )
Brancher notre risque cumulatif et simplifier:
hT′( t ) = 1 - P( t + 1 , λ )P( t , λ )exp( - a ⋅ 1( t = 7 )- b ⋅ 1( t = 14 )- ∞ ⋅ 1( t = 21 ))
iii) Enfin, écrire le log vraisemblance pour les modèles de survie (sans censure) est super facile une fois que nous avons le danger et le risque cumulatif:
l l ( λ , a , b|t ) = ∑i = 1N( journalh ( tje) - H( tje) )
Et voilà!
a = - log( 1 - pune) , b = - log( 1 - pune- pb) - journal( 1 - pune) , pc= 1 - ( pune+ pb)
La preuve est dans le pudding. Faisons quelques simulations et inférences en utilisant la sémantique du modèle personnalisé des lignes de vie .
from lifelines.fitters import ParametericUnivariateFitter
from autograd_gamma import gammaincln, gammainc
from autograd import numpy as np
MAX = 1e10
class InsuranceDischargeModel(ParametericUnivariateFitter):
"""
parameters are related by
a = -log(1 - p_a)
b = -log(1 - p_a - p_b) - log(1 - p_a)
p_c = 1 - (p_a + p_b)
"""
_fitted_parameter_names = ["lbd", "a", "b"]
_bounds = [(0, None), (0, None), (0, None)]
def _hazard(self, params, t):
# from (1.64c) in http://geb.uni-giessen.de/geb/volltexte/2014/10793/pdf/RinneHorst_hazardrate_2014.pdf
return 1 - np.exp(self._cumulative_hazard(params, t) - self._cumulative_hazard(params, t+1))
def _cumulative_hazard(self, params, t):
lbd, a, b = params
return -gammaincln(t, lbd) + a * (t > 7) + b * (t > 14) + MAX * (t > 21)
def gen_data():
p_a, p_b = 0.4, 0.2
p = [p_a, p_b, 1 - p_a - p_b]
lambda_ = 18
death_without_insurance = np.random.poisson(lambda_)
insurance_covers_until = np.random.choice([7, 14, 21], p=p)
if death_without_insurance < insurance_covers_until:
return death_without_insurance
else:
return insurance_covers_until
durations = np.array([gen_data() for _ in range(40000)])
model = InsuranceDischargeModel()
model.fit(durations)
model.print_summary(5)
"""
<lifelines.InsuranceDischargeModel: fitted with 40000 observations, 0 censored>
number of subjects = 40000
number of events = 40000
log-likelihood = -78845.10392
hypothesis = lbd != 1, a != 1, b != 1
---
coef se(coef) lower 0.95 upper 0.95 p -log2(p)
lbd 18.05026 0.03353 17.98455 18.11598 <5e-06 inf
a 0.50993 0.00409 0.50191 0.51794 <5e-06 inf
b 0.40777 0.00557 0.39686 0.41868 <5e-06 inf
"""
¹ voir la section 1.2 ici