rm(list=ls())
Modèles de Survie
Introduction aux modèles de survie
1 Avant de commencer
Réinitialisation de l’environnement
Librairies utiles
library(dplyr)
library(survival)
2 Génération des données
- Durées de vie : \(X \sim Exp(0.3)\)
- Censures à droite : \(C \sim Exp(0.1)\)
- Temps d’observation : \(T = min(X,C)\)
set.seed(20)
<- 150
n
<- rexp(n, 0.3) # Temps de survie (Xi)
X <- rexp(n, 0.1) # Temps de censures à droite (Ci)
C <- pmin(X, C) # Temps d'observation (Ti)
T
<- data.frame(X, C, T)
data
# statut de censure (0 : censure à droite, 1 : pas de censure, 2 : censure à gauche)
$censure <- ifelse(X <= C, 1, 0)
data
head(data, 10)
X | C | T | censure |
---|---|---|---|
0.6445417 | 1.708531 | 0.6445417 | 1 |
0.1944246 | 3.126684 | 0.1944246 | 1 |
0.2110231 | 2.196058 | 0.2110231 | 1 |
7.3714440 | 10.960311 | 7.3714440 | 1 |
3.3450766 | 5.479652 | 3.3450766 | 1 |
3.9114845 | 1.356186 | 1.3561858 | 0 |
1.4368504 | 4.680558 | 1.4368504 | 1 |
1.7186424 | 5.867553 | 1.7186424 | 1 |
21.2389967 | 4.111656 | 4.1116558 | 0 |
3.2724543 | 34.235329 | 3.2724543 | 1 |
3 Modèles paramétriques
Les fonctions de risque instantané des deux principaux modèles :
- Modèle exponentiel : \(\lambda(t,\ Z)\ =\ \theta\ exp(\beta^T Z)\)
- Modèle de Weibull : \(\lambda(t,\ Z)\ =\ \theta\ \gamma\ (\theta\ t)^{\gamma-1} exp(\beta^T Z)\)
avec \(Z\) : les covariables
3.1 Estimation paramétrique du modèle sans prise en compte des censures
On suppose que toutes les observations sont vraies ie. les censures sont considérées comme des décès
<- survreg(Surv(data$T, rep(1,n)) ~ 1, dist = "exponential")
model1 summary(model1)
Call:
survreg(formula = Surv(data$T, rep(1, n)) ~ 1, dist = "exponential")
Value Std. Error z p
(Intercept) 0.9466 0.0816 11.6 <2e-16
Scale fixed at 1
Exponential distribution
Loglik(model)= -292 Loglik(intercept only)= -292
Number of Newton-Raphson Iterations: 5
n= 150
exp(-model1$coefficients) # Valeur du paramètre de la loi exponentielle estimée
(Intercept)
0.3880494
exp(-model1$coefficients) - 0.3 # Biais
(Intercept)
0.08804942
3.2 Estimation paramétrique du modèle en supprimant les censures
<- survreg(Surv(data$T, data$censure) ~ 1,
model2 dist = "exponential",
subset = data$censure == 1)
summary(model2)
Call:
survreg(formula = Surv(data$T, data$censure) ~ 1, subset = data$censure ==
1, dist = "exponential")
Value Std. Error z p
(Intercept) 0.8622 0.0958 9 <2e-16
Scale fixed at 1
Exponential distribution
Loglik(model)= -203 Loglik(intercept only)= -203
Number of Newton-Raphson Iterations: 5
n= 109
exp(-model2$coefficients) # Valeur du paramètre de la loi exponentielle estimée
(Intercept)
0.4222224
exp(-model2$coefficients) - 0.3 # Biais
(Intercept)
0.1222224
3.3 Estimation paramétrique du modèle en considérant les censures
<- survreg(Surv(data$T, data$censure) ~ 1,
model3 dist = "exponential")
summary(model3)
Call:
survreg(formula = Surv(data$T, data$censure) ~ 1, dist = "exponential")
Value Std. Error z p
(Intercept) 1.2659 0.0958 13.2 <2e-16
Scale fixed at 1
Exponential distribution
Loglik(model)= -247 Loglik(intercept only)= -247
Number of Newton-Raphson Iterations: 5
n= 150
exp(-model3$coefficients) # Valeur du paramètre de la loi exponentielle estimée
(Intercept)
0.2819826
exp(-model3$coefficients) - 0.3 # Biais
(Intercept)
-0.01801742
3.4 Comparaisons
<- data %>%
data_compare arrange(T) %>%
mutate(no_censor = exp(-exp(-model1$coefficients) * T),
tronc_censor = ifelse(censure == 1, exp(-exp(-model2$coefficients) * T), NA),
with_censor = exp(-exp(-model3$coefficients) * T))
plot(with_censor ~ T, data = data_compare,
type = "l", col = "green",
xlab = "Probabilité de Survie", ylab = "Temps")
lines(no_censor ~ T, data = data_compare, type = "l", col = "orange")
lines(tronc_censor ~ T, data = data_compare, type = "l", col = "red")
legend("topright",
legend = c("Modèle paramétrique avec censures",
"Modèle paramétrique sans censures",
"Modèle paramétrique avec données tronquées"),
col=c("green", "orange", "red"),
lty = 1:1)
4 Modèles non paramétriques
4.1 Courbe de survie par la méthode de Kaplan-Meier
<- survfit(Surv(data$T, data$censure) ~ 1,
Kaplan_Meier type = "kaplan-meier",
error = c("greenwood"))
Kaplan_Meier
Call: survfit(formula = Surv(data$T, data$censure) ~ 1, error = c("greenwood"),
type = "kaplan-meier")
n events median 0.95LCL 0.95UCL
[1,] 150 109 2.38 1.71 3.13
Calcul pas à pas de la fonction de Survie, à l’instant t :
- risque = nombre de décès / nombre d’individus à risque
- survie = produit de (1 - risque) pour tous les instants inférieurs ou égal à t
<- data.frame(temps_obs = Kaplan_Meier$time,
taleau_KM nb_deces = Kaplan_Meier$n.event,
nb_censures = Kaplan_Meier$n.censor,
nb_a_risque = Kaplan_Meier$n.risk)
<- taleau_KM %>%
taleau_KM mutate(risque = nb_deces / nb_a_risque) %>%
mutate(survie = cumprod(1 - risque)) # = Kaplan_Meier$surv
head(taleau_KM, 10)
temps_obs | nb_deces | nb_censures | nb_a_risque | risque | survie |
---|---|---|---|---|---|
0.0018103 | 1 | 0 | 150 | 0.0066667 | 0.9933333 |
0.0237061 | 1 | 0 | 149 | 0.0067114 | 0.9866667 |
0.0483489 | 1 | 0 | 148 | 0.0067568 | 0.9800000 |
0.0487304 | 1 | 0 | 147 | 0.0068027 | 0.9733333 |
0.0566822 | 1 | 0 | 146 | 0.0068493 | 0.9666667 |
0.0576510 | 0 | 1 | 145 | 0.0000000 | 0.9666667 |
0.0690159 | 0 | 1 | 144 | 0.0000000 | 0.9666667 |
0.0705573 | 1 | 0 | 143 | 0.0069930 | 0.9599068 |
0.0727950 | 1 | 0 | 142 | 0.0070423 | 0.9531469 |
0.0750514 | 1 | 0 | 141 | 0.0070922 | 0.9463869 |
tail(taleau_KM, 10)
temps_obs | nb_deces | nb_censures | nb_a_risque | risque | survie | |
---|---|---|---|---|---|---|
141 | 7.599810 | 1 | 0 | 10 | 0.1000000 | 0.1262141 |
142 | 7.893794 | 0 | 1 | 9 | 0.0000000 | 0.1262141 |
143 | 7.904069 | 1 | 0 | 8 | 0.1250000 | 0.1104373 |
144 | 7.932746 | 0 | 1 | 7 | 0.0000000 | 0.1104373 |
145 | 8.870664 | 1 | 0 | 6 | 0.1666667 | 0.0920311 |
146 | 8.930153 | 1 | 0 | 5 | 0.2000000 | 0.0736249 |
147 | 9.880971 | 1 | 0 | 4 | 0.2500000 | 0.0552187 |
148 | 10.243681 | 1 | 0 | 3 | 0.3333333 | 0.0368124 |
149 | 11.783160 | 0 | 1 | 2 | 0.0000000 | 0.0368124 |
150 | 13.341401 | 0 | 1 | 1 | 0.0000000 | 0.0368124 |
plot(with_censor ~ T, data = data_compare,
type = "l", col = "green",
xlab = "Probabilité de Survie", ylab = "Temps")
#lines(KM ~ T, data = data_compare, type = "l", col = "blue")
lines(Kaplan_Meier, col = "blue")
legend("topright",
legend = c("Modèle paramétrique avec censures",
"Courbe de Kaplan-Meier"),
col=c("green", "blue"),
lty = 1:1)
4.2 Courbe de survie par méthode actuarielle
🚧
4.3 Comparaisons
# Calcul des fonctions de survie
# S(t) = exp(-lambda) = exp(-exp(fit_event$coefficients))
<- data_compare %>%
data_compare arrange(T) %>%
mutate(KM = Kaplan_Meier$surv)
plot(with_censor ~ T, data = data_compare,
type = "l", col = "green",
xlab = "Probabilité de Survie", ylab = "Temps")
lines(KM ~ T, data = data_compare, type = "l", col = "blue")
legend("topright",
legend = c("Modèle paramétrique avec censures",
"Courbe de Kaplan-Meier"),
col=c("green", "blue"),
lty = 1:1)
5 Modèles semi-paramétriques
5.1 Modèle de Cox
\(\lambda(t,\ Z)\ =\ \lambda_0(t)\ exp(\beta^T Z)\) avec \(\lambda_0(t)\) non spécifié
<- data.frame(sexe = rbinom(n, 1, prob = 0.5),
data7 age = round(runif(n, 20, 80)),
dose = rpois(n, 5))
<- data7 %>%
data7 mutate(X = 100 * rexp(n, 0.1 + age/10 + sexe),
C = 100 *rexp(n, 0.1)) %>%
mutate(T = pmin(X, C),
censure = ifelse(X <= C, 1, 0))
plot(data7$age, data7$X, xlab = "Age", ylab = "Temps de survie", pch = 3, col = data7$sexe + 1)
legend("topright",
legend=c("Sexe = 0", "Sexe = 1"),
col=c("black", "red"), lty=1:1)
<- coxph(Surv(T, censure) ~ factor(sexe) + age + dose,
cox_model data = data7)
summary(cox_model)
Call:
coxph(formula = Surv(T, censure) ~ factor(sexe) + age + dose,
data = data7)
n= 150, number of events= 147
coef exp(coef) se(coef) z Pr(>|z|)
factor(sexe)1 0.202349 1.224275 0.172223 1.175 0.2400
age 0.010063 1.010114 0.004726 2.129 0.0332 *
dose -0.036768 0.963900 0.040850 -0.900 0.3681
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
exp(coef) exp(-coef) lower .95 upper .95
factor(sexe)1 1.2243 0.8168 0.8735 1.716
age 1.0101 0.9900 1.0008 1.020
dose 0.9639 1.0375 0.8897 1.044
Concordance= 0.571 (se = 0.026 )
Likelihood ratio test= 7.22 on 3 df, p=0.07
Wald test = 7.33 on 3 df, p=0.06
Score (logrank) test = 7.37 on 3 df, p=0.06
plot(survfit(cox_model),
ylim = c(0,1),
col = "green",
xlab = "Temps (jours)",
ylab = "Fonction de survie",
main = "Fonction de survie")
lines(survfit(Surv(T, censure) ~ 1, data = data7), col = "blue", conf.int = FALSE)
lines(survfit(cox_model, newdata = data.frame(sexe = 0, dose = 5, age = 35)), col = "orange", conf.int = FALSE)
legend("topright",
legend=c("Cox moyen", "Kaplan-Meier", "Cox ajusté (sexe=0, age=35, dose = 5)"),
col=c("green", "blue","orange"), lty=1:1)
5.2 Comparaison de modèles avec un test de rapport de vraisemblance
Log vraisemblance modèle non contraint
<- cox_model$loglik[2] loglik_M1
Log vraisemblance modèle contraint (non prise en compte de dose)
<- coxph(Surv(T, censure) ~ factor(sexe) + age,
cox_contraint data = data7)
summary(cox_contraint)
Call:
coxph(formula = Surv(T, censure) ~ factor(sexe) + age, data = data7)
n= 150, number of events= 147
coef exp(coef) se(coef) z Pr(>|z|)
factor(sexe)1 0.191454 1.211009 0.171542 1.116 0.2644
age 0.010047 1.010098 0.004719 2.129 0.0332 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
exp(coef) exp(-coef) lower .95 upper .95
factor(sexe)1 1.211 0.8258 0.8652 1.695
age 1.010 0.9900 1.0008 1.019
Concordance= 0.557 (se = 0.028 )
Likelihood ratio test= 6.4 on 2 df, p=0.04
Wald test = 6.46 on 2 df, p=0.04
Score (logrank) test = 6.51 on 2 df, p=0.04
# Log vraisemblance modèle contraint
<- cox_contraint$loglik[2] loglik_M0
Test du rapport de vraisemblance
- \(H_0\) : le coefficient associé à la covariable dose vaut 0
- Sous \(H_0\), le rapport de vraisemblance suit une loi du chi2 à m degrés de liberté (où m est le nombre de paramètres de différence entre les deux modèles)
<- 2 * (loglik_M1 - loglik_M0)
LRT 1 - pchisq(LRT, 1)
[1] 0.365318
La p-valeur est très supérieure à 0.05, donc on ne rejette pas \(H_0\).