Nesse caso, acredito que exista um caminho para uma solução se colocarmos nosso chapéu de análise de sobrevivência. Observe que, embora esse modelo não tenha assuntos censurados (no sentido tradicional), ainda podemos usar a análise de sobrevivência e falar sobre os perigos dos sujeitos.
Precisamos modelar três coisas nesta ordem: i) o risco cumulativo, ii) o perigo, iii) a probabilidade do log.
H( T )H( t ) = - logS( T )T∼ Po i ( λ )
HT( T )= - log( 1 - Q ( t , λ ) ) = - logP( t , λ )
Q , P
Agora, queremos adicionar os "riscos" do seguro acabando. O bom dos riscos cumulativos é que eles são aditivos, por isso precisamos simplesmente adicionar "riscos" nos horários 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))
Conectando nosso risco cumulativo e simplificando:
hT′(t)=1−P(t+1,λ)P(t,λ)exp(−a⋅1(t=7)−b⋅1(t=14)−∞⋅1(t=21))
iii) Finalmente, escrever a probabilidade do log para modelos de sobrevivência (sem censura) é super fácil, uma vez que temos o risco e o risco cumulativo:
ll(λ,a,b|t)=∑i=1N(logh(ti)−H(ti))
E aí está!
a=−log(1−pa),b=−log(1−pa−pb)−log(1−pa),pc=1−(pa+pb)
A prova está no pudim. Vamos fazer algumas simulações e inferência usando a semântica do modelo personalizado das linhas de vida .
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
"""
¹ veja a Seção 1.2 aqui