Simulation des données de survie

Transcription

Simulation des données de survie
Simulation des données de survie
Michel Cucherat
18 août 2010
La simulation des processus de survie tel qu’on les analysent à l’aide des
techniques d’analyse de survie peuvent se simuler de différentes façons. Ces
simulations reposent toutes sur le modèle du risque instantané.
1
Simulation de la survenue d’un événement
Pour simuler ces processus de survie nous avons besoin d’un outil pouvant
simuler la survenu d’un événement ayant une probabilité p de survenir (loi de
Bernouilli). Ce dispositif de simulation s’obtient facilement avec un générateur
de nombre aléatoire produisant des nombres entre 0 et 1, distribués de façon
strictement uniforme entre ces 2 bornes. Pour simuler un évènement de probabilité p il suffit de générer un nombre aléatoire et de regarder si celui-ci est
inférieur ou supérieur à p. S’il est inférieur, l’événement survient. Dans le cas
contraire il n’y a pas d’événement. Avec cet algorithme la probabilité de survenu
de l’événement simulé est bien de p puise que un nombre aléatoire va se situer
entre et 0 et p dans p% des cas (par définition).
Vérifions cela sur une série de 1000 simulation d’un évènement ayant une
probabilité de survenu de 0.2.
>
>
>
>
p <- 0.2
x <- runif(1000)
ev <- x <= p
print(sum(ev)/length(ev))
[1] 0.189
> print(table(ev)/length(ev))
ev
FALSE TRUE
0.811 0.189
2
Simulation du moment de survenu d’un événement
Avec le modèle du risque instantané, un événement à une probabilité h de
survenir durant un espace de temps court ∆t, par exemple une journée. Pour
faire la simulation, il suffit de simuler chaque jour en commençant par le 1er jour
1
du suivi et de voir si l’évènement survient. Si pour un jour donné, l’événement
ne survient pas on passe à la simulation du jour suivant.
En fait il est plus simple de simuler tous les jours simultanément et de prendre
comme date de survenu de l’évènement le 1er jour où survient un événement.
Considérons un événement dont la probabilité de survenu est 0.01 par jour (le
risque instantané est de 1% par jour). Le temps de suivi est de 365 jours.
>
>
>
+
+
+
+
+
+
>
h <- 0.01
e <- runif(365) <= h
if (any(e)) {
d <- min(which(e))
ev <- T
} else {
d <- length(e)
ev <- F
}
print(d)
[1] 300
> print(ev)
[1] TRUE
which est une fonction qui ramène les rangs d’un vecteur de booléen où se
trouve les valeurs TRUE. L’application de la fonction min sur ce vecteur de rangs
ramène donc le numéro (le rang) du premier jour où survient un événement. Si
aucun événement ne survient, any(e) est égal à FALSE et donc ce patient est
censuré vivant à la date de fin de suivi (length(e) qui est égal à 365).
L’encapsulation de tout cela dans une fonction permet de simuler le suivi
d’un patient.
> suivi.patient <- function(h, t.max = 365) {
+
e <- runif(t.max) <= h
+
if (any(e)) {
+
d <- min(which(e))
+
ev <- 1
+
}
+
else {
+
d <- t.max
+
ev <- 0
+
}
+
c(d, ev)
+ }
> replicate(5, suivi.patient(0.01))
[1,]
[2,]
[,1] [,2] [,3] [,4] [,5]
35 168
95
41
45
1
1
1
1
1
L’analyse des courbes de survie se fait à l’aide du package survival dans R.
2
>
>
>
>
>
>
library(survival)
d <- replicate(80, suivi.patient(0.01))
t <- d[1, ]
ev <- d[2, ]
r <- survfit(Surv(t, ev) ~ 1)
print(r)
Call: survfit(formula = Surv(t, ev) ~ 1)
records
80
n.max n.start
80
80
events
79
median 0.95LCL 0.95UCL
69
52
89
0.0
0.2
0.4
survie
0.6
0.8
1.0
> plot(r, xlab = "temps (jours)", ylab = "survie")
0
50
100
150
200
250
300
350
temps (jours)
Et voici la simulation de la survie de 80 patients dont le risque instantané
est de 0.01.
3
Faisons appel à la théorie
Dans la section précédente nous effectuons une simulation de bas niveau,
se situant au plus près du modèle. Le temps de calcul est important puisque
chaque jours du suivi de chaque patient est simulé. La connaissance de la théorie
permet de réduire dramatiquement ce temps de calcul. En effet, quand le risque
instantanée est constant h(t) = cte, les temps de survenu sont distribué suivant
une loi exponentielle. la simulation devient alors
> t <- rexp(80, 0.01)
> ev <- t < 365
3
> t[!ev] <- 365
> r <- survfit(Surv(t, ev) ~ 1)
> print(r)
Call: survfit(formula = Surv(t, ev) ~ 1)
records
80.0
n.max n.start
80.0
80.0
events
75.0
median 0.95LCL 0.95UCL
87.1
74.3
101.4
0.0
0.2
0.4
survie
0.6
0.8
1.0
> plot(r, xlab = "temps (jours)", ylab = "survie")
0
50
100
150
200
250
300
350
temps (jours)
Même résultat mais un besoin en calcul bien inférieur. Cela illustre parfaitement un principe de la simulation : inutile de simuler le plus bas niveau si cela
n’apporte rien par rapport à la simulation de propriété parfaitement connue par
la théorie. ici inutile de simuler chaque jours étant donné que l’on connaı̂t parfaitement la distribution des temps de survie dans cette situation où le hazard
est constant.
4
Simulation d’un effet thérapeutique sur la survie
A partir de ces éléments il est facile de simuler un essai clinique où le traitement se caractérise par un hr de 0.6 avec un hazard sans traitement de 1%.
> n.group <- 80
> h0 <- 0.01
4
>
>
>
+
>
>
>
>
>
>
hr <- 0.6
h1 <- h0 * hr
trt <- c(rep("studied treatment", n.group), rep("control treatment",
n.group))
trt <- factor(trt)
t <- c(rexp(n.group, h1), rexp(n.group, h0))
ev <- t < 365
t[!ev] <- 365
r <- survfit(Surv(t, ev) ~ trt)
print(r)
Call: survfit(formula = Surv(t, ev) ~ trt)
trt=control treatment
trt=studied treatment
records n.max n.start events median 0.95LCL 0.95UCL
80
80
80
74
64.1
43.0
105
80
80
80
76 101.4
71.6
123
1.0
> plot(r, xlab = "temps (jours)", ylab = "survie", col = c(1, 2),
+
lty = c(1, 2))
> legend("topright", levels(trt), col = 1:2, lty = 1:2, bty = "n")
0.0
0.2
0.4
survie
0.6
0.8
control treatment
studied treatment
0
50
100
150
200
250
300
350
temps (jours)
Il est aussi possible de calculer le logrank et d’estimer le hazard ratio observé
à l’aide d’un modèle de cox.
> r2 <- survdiff(Surv(t, ev) ~ trt)
> print(r2)
Call:
survdiff(formula = Surv(t, ev) ~ trt)
5
N Observed Expected (O-E)^2/E (O-E)^2/V
trt=control treatment 80
78
71.1
0.666
1.27
trt=studied treatment 80
73
79.9
0.593
1.27
Chisq= 1.3
on 1 degrees of freedom, p= 0.261
> r3 <- coxph(Surv(t, ev) ~ trt)
> print(r3)
Call:
coxph(formula = Surv(t, ev) ~ trt)
coef exp(coef) se(coef)
z
p
trtstudied treatment -0.183
0.832
0.163 -1.12 0.26
Likelihood ratio test=1.26
5
on 1 df, p=0.261
n= 160
Etude par simulation du processus d’estimation du hazard ratio par un cox
Pour cela il faut construire une fonction qui simule un essai à partir d’un
vrai hazard ratio et qui retourne le hazard ratio estimé par le Cox à partir des
données simulées
> simuler.essai <- function(hr, h0 = 0.01, n.group = 80, t.max = 365) {
+
n.group <- 80
+
h0 <- 0.01
+
hr <- 0.6
+
h1 <- h0 * hr
+
trt <- c(rep(1, n.group), rep(0, n.group))
+
trt <- factor(trt)
+
t <- c(rexp(n.group, h1), rexp(n.group, h0))
+
ev <- t < t.max
+
t[!ev] <- t.max
+
r <- coxph(Surv(t, ev) ~ trt)
+
hr <- exp(r$coefficients)
+
hr
+ }
> simuler.essai(0.5, 0.01, 80)
trt1
0.7662047
En répliquant la simulation d’essais on peut ainsi vérifier que le modèle de
Cox estime sans biais le hazard ratio dans le cas d’un hazard ratio constant.
> hr.true <- 0.6
> hr <- replicate(1000, simuler.essai(hr.true, 0.01, 80))
> print(mean(hr))
6
[1] 0.6010576
> biais <- hr.true - mean(hr)
> print(biais)
[1] -0.001057600
> print(summary(hr))
Min. 1st Qu.
0.2526 0.5285
Median
0.5907
Mean 3rd Qu.
0.6011 0.6640
1.0
> boxplot(hr)
●
●
0.4
0.6
0.8
●
●
●
●
●
●
●
●
7
Max.
1.0210

Documents pareils