El análisis de sobrevivencia es un conjunto de técnicas estadísticas en las que la variable respuesta es el tiempo que transcurre entre el comienzo de seguimiento del individuo en el estudio y la aparición del evento de interés (tolerancia a la leche, muerte, etc.).
En el análisis de sobrevivencia, la variable respuesta, es generalmente, el tiempo hasta la ocurrencia de un evento de interés.
Ejemplo: En estudios de cáncer es usual el registro de fechas correspondientes al diágnostico de la enfermedad, a la remisión (después del tratamiento, el paciente queda libre de los síntomas de la enfermedad), a la recurrencia de la enfermedad (recaída) y hasta la muerte del paciente.
Asumamos que estamos interesados en el tiempo hasta que ocurra un cierto evento de interés.
Es necesario definir los siguientes elementos: El tiempo de inicio del estudio debe ser definido de forma precisa, de forma que las observaciones puedan ser comparables en el origen del estudio.
Indican que todos los individuos en el estudio fallaron o el tiempo de falla de cada individuo es conocido. Por lo tanto asumimos informaciones completas.
Los estudios que involucran una respuesta temporal usualmente son de una “larga” duraci ́on. Sin embargo, a pesar de ser largos en duración, muchos estudios clínicos terminan antes de que todos los individuos dentro del estudio “fallen”.
De esta forma, tenemos observaciones “incompletas” dentro de nuestro estudio. Estas observaciones llamadas censuras, pueden ocurrir por una variedad de razones.
Siendo algunas de ellas:
Nota: Los tiempos de censura, deben ser incorporados en el análisis porque traen información sobre un individuo o componente.
Para efecto del desarrollo de este documento se trabajará sólo con censura a la derecha.
Existen tres mecanismos de censura a la derecha.
La truncación ocurre cuando parte de la población no puede ser observada.
Es caracterizado por una condición que excluye ciertos individuos del estudio. En estos estudios, los pacientes no son acompañados a partir del tiempo inicial, pero solo después de experimentar un cierto evento.
La v.a. no negativa T, usualmente continua, que representa el tiempo de falla, es generalmente representada por su función de sobrevivencia o por la función de tasa de falla (o de riesgo).
La función de sobrevivencia es definada como la probabilidad de una observación no fallar hasta un cierto tiempo t, es decir, la probabilidad de una observación sobrevivir hasta un cierto tiempo t. En terminos probabilísticos, esto es descrito como:
\[\begin{equation} S(t) = P(T > t) = 1 − P(T < t) \end{equation}\]Propiedades
\(S(t) = 0\), cuando \(t \to \infty\).
\(S(t) = 1\), cuando \(t \to 0\).
Función de riesgo o tasa de falla: Es la tasa de falla instantánea en el tiempo t condicional a que la observación sobrevivió hasta el tiempo t.
\[\begin{equation} h(t) = \lim_{\Delta t \to 0} \frac{P(t \leq T < t + \Delta t \mid T \geq t)}{\Delta t} \end{equation}\]Propiedades
\(h(t) \to 0\), cuando \(t \to \infty\).
\(h(t)\) es una tasa y no una probabilidad.
Función de riesgo acumulada:
\[\begin{equation} H(t) = \int_{0}^{t} h(u) \, du \end{equation}\]El área bajo la curva de sobrevivencia es definida como el tiempo medio, es decir,
\[\begin{equation} tm = \int_{0}^{\infty} S(t) \, dt \end{equation}\]donde \(S(t)\) es la función de sobrevivencia. Además, se define el \(vmr(t)\) como:
\[\begin{equation} vmr(t) = \int_{t}^{\infty} (u - t) f(u) \, du \end{equation}\]y finalmente, otra expresión para \(S(t)\) en términos de \(S(u)\):
\[\begin{equation} S(t) = \int_{t}^{\infty} S(u) \, du \end{equation}\]Tabla 1
\[ \begin{array}{c|c} \hline \text{Función requerida} & \text{Función dada} \\ \hline f(t) & S(t) \\ - \int_{t}^{\infty} f(u) \, du & - \frac{dS(t)}{dt} \\ h(t) \exp \left( - \int_{0}^{t} h(u) \, du \right) & H(t) \\ \frac{dH(t)}{dt} & \exp \{ -H(t) \} \\ \hline \end{array} \]
Este manual fue realizado utilizando la versión 4.2.1 (2022-06-23 ucrt) de R.
Las librerías se instalan por una única vez y se cargan antes de iniciar cualquier análisis. La instalación y las librerías utilizadas se realizan en el siguiente script:
#install.packages('tinytex')
#install.packages("survival")
#install.packages("KMsurv")
#install.packages("survMisc")
#install.packages("survminer")
#install.packages("flexsurv")
#install.packages("actuar")
#install.packages("dplyr")
La carga de las librerías se realiza con la función library():
suppressPackageStartupMessages({
library(survival)
library(KMsurv)
library(survMisc)
library(survminer)
library(flexsurv)
library(actuar)
library(dplyr)
library(tinytex)
})
Al menos que se indique lo contrarío las bases de datos utilizadas son extraídas de Klein and Moeschberger (1997), Survival Analysis, Techniques for Censored and Truncated Data, Springer obtenidas a través de la librería KMSurv.
Las bases de da tos de Klein and Moeschberger se pueden accesar utilizando la función data(name), en donde name toma el nombre de la base de datos que se desea extraer, esta función crea una variable del mismo nombre que contiene la base de datos.
Ejemplo de la base de datos.
library(survival)
data("ovarian")
head(ovarian)
## futime fustat age resid.ds rx ecog.ps
## 1 59 1 72.3315 2 1 1
## 2 115 1 74.4932 2 1 1
## 3 156 1 66.4658 2 1 2
## 4 421 0 53.3644 2 2 1
## 5 431 1 50.3397 2 1 1
## 6 448 0 56.4301 1 1 2
R utiliza el directorio de trabajo para leer y escribir archivos. Para saber cuál es este directorio puede utilizar el comando getwd(). Se recomienda cambiar el directorio de trabajo utilizando la función setwd() por ejemplo, setwd(“C:/data”) o setwd(“/home/R”).
Es necesario proporcionar la dirección completa del archivo si este no se encuentra en el directorio de trabajo, para efectos del desarrollo del presente documento se trabajaran sólo con bases de datos que están presentes en el directorio.
Antes de iniciar con los análisis se requiere un pre-procesamiento de los datos, estos deberán tener el siguiente formato:
Este proceso se puede realizar en un software de hojas de cálculo y posteriormente guardar el archivo en formato csv.
La mayoría de las funciones utilizan un objeto tipo Surv como argumento, un objeto Surv no es más que la combinación de información entre los tiempos y su censura. Existen varios tipos de censura, sin embargo, en esta oportunidad solo se ejemplificarán con datos con censura por la derecha.
La creación de un objetivo Surv se realiza con la función Surv(Time,Event), que toma como argumentos: Time como el tiempo hasta la observación y Event un indicador en donde es 1 si se observó el evento y 0 si es censura.
Por ejemplo:
Surv(5, 1) #Observación del evento
## [1] 5
Surv(5, 0) #Observación Censurada
## [1] 5+
Surv(c(1, 2, 3, 4), c(1, 0, 1, 0))
## [1] 1 2+ 3 4+
Los tiempos censurados se caracterizan por tener el símbolo + acompañado a su derecha.
Como se verá posteriormente, Surv(Time,Event) en combinación de otras funciones tomará como argumento el Nombre de la columna que hace referencia tanto a los tiempos de observación, así como su censura.
Los estimadores de Kaplan-Meier para la función de sobrevivencia es obtenido a través paquete estadístico survival mediante la función survfit(). Esta función en su forma más sencilla, solo requiere un objeto de sobrevivencia creado por la función Surv(). Los argumentos de la función survfit() son los siguientes:
y ~ x, que
debe tener un objeto Surv como variable respuesta a la
izquierda del ~ y, si se desea, el nombre de las
covariables por la derecha. Uno de los términos puede ser un objeto
strata. Para una sola curva de sobrevivencia del lado
derecho se coloca ~ 1.data.frame donde están
los datos."kaplan-meier".Ejemplo:
La base de datos tongue con tiene un total de 80 observaciones de 3 variables:
library(KMsurv)
data("tongue")
head(tongue)
## type time delta
## 1 1 1 1
## 2 1 3 1
## 3 1 3 1
## 4 1 4 1
## 5 1 10 1
## 6 1 13 1
#Guardando el Objeto Surv
tongue.surv <- Surv(tongue$time, tongue$delta) #Objeto tipo Surv
tongue.km <- survfit(tongue.surv ~ 1, data = tongue,
type = "kaplan-meier") #Estimación KM
#Sin Guardar el Objeto Surv
tongue.km <- survfit(Surv(time, delta) ~ 1, data = tongue, type = "kaplan-meier")
La estimación de la función de sobrevivencia se lleva a cabo con la función summary().
summary(tongue.km)
La estimación devuelve los siguientes valores:
La función survfit() devuelve un resumen de la estimación, la información se puede acceder agregando el símbolo “$” seguido del nombre del elemento de la lista.
Una mejor manera de extraer la información es utilizando la función fortify() sobre el objeto survfit, esta función devuelve un data.frame con la información. Al tener presencia de covariables se anexa la columna llamada strata.
Ejemplo, utilizando la variable delta como covariable.
tongue.km <- survfit(Surv(time, delta) ~ type, data = tongue, type = "kaplan-meier") #Estimación KM por grupos
summary(tongue.km) #Resumen estadístico
tongue.km[2]$surv #Elementos columna surv delta=1
library(broom)
tongue_ovarian <- tidy(tongue.km)
#fortify(tongue.km)
Tanto como la desviación estándar y los Intervalos de confianza de la curva de sobrevivencia es estimada mediante la función survfit() con los siguientes argumentos:
Ejemplo
tongue.km <- survfit(Surv(time, delta) ~ 1, data = tongue, type = "kaplan-meier",
error = "tsiatis", conf.type = "log-log", conf.int = 0.99)
summary(tongue.km)
La curva de sobrevivencia estimada se gráfica con la paquetería survminer, está gráfica esta hecha utilizando la librería ggplot2 y contiene un numero grande de parámetros, por lo que solamente ilustraremos los más importantes.
Ejemplo
library(survminer)
ggsurvplot(fit = tongue.km, data = tongue, conf.int = TRUE,
title = "Curva de Sobrevivencia",
xlab = "Tiempo",
ylab = "Probabilidad de sobrevivencia",
legend.title = "Estimación",)
La estimación de la función de riesgo acumulado se puede estimar de dos formas, la primera es por Máxima Verosimilitud: tomando el menos logaritmo de la función de sobrevivencia y el segundo es utilizando el estimador Nelson-Aalen.
La información del Tiempo y Probabilidad de sobrevivencia es extraída del objeto survfit, se calcula el riesgo acumulado utilizando mutate y finalmente se guarda en la variable R.
Las funciones %>%, group_by, mutate, pertenecen a la librería dplyr, una librería para la gramática de manipulación de datos.
tongue.km <- survfit(Surv(time, delta) ~ type, data = tongue)
#R <- tongue.km %>% fortify %>% mutate(CumHaz = cumsum(n.event/n.risk))
#Convertir el objeto survfit a un dataframe
tongue_ovarian <- tidy(tongue.km)
#Variable CumHaz
R <- tongue_ovarian %>%
mutate(CumHaz = cumsum(estimate))
R
## # A tibble: 69 × 10
## time n.risk n.event n.censor estimate std.error conf.high conf.low strata
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 1 52 1 0 0.981 0.0194 1 0.944 type=1
## 2 3 51 2 0 0.942 0.0343 1 0.881 type=1
## 3 4 49 1 0 0.923 0.0400 0.998 0.853 type=1
## 4 10 48 1 0 0.904 0.0452 0.988 0.827 type=1
## 5 13 47 2 0 0.865 0.0547 0.963 0.777 type=1
## 6 16 45 2 0 0.827 0.0634 0.936 0.730 type=1
## 7 24 43 1 0 0.808 0.0677 0.922 0.707 type=1
## 8 26 42 1 0 0.788 0.0718 0.908 0.685 type=1
## 9 27 41 1 0 0.769 0.0760 0.893 0.663 type=1
## 10 28 40 1 0 0.75 0.0801 0.877 0.641 type=1
## # ℹ 59 more rows
## # ℹ 1 more variable: CumHaz <dbl>
tongue_ovarian <- tidy(tongue.km)
#Variable CumHaz agrupado por estratos
R <- tongue_ovarian %>%
group_by(strata) %>%
mutate(CumHaz = cumsum(n.event / n.risk))
print(R, 60)
## # A tibble: 69 × 10
## # Groups: strata [2]
## time n.risk n.event n.censor estimate std.error
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 52 1 0 0.981 0.0194
## 2 3 51 2 0 0.942 0.0343
## 3 4 49 1 0 0.923 0.0400
## 4 10 48 1 0 0.904 0.0452
## 5 13 47 2 0 0.865 0.0547
## 6 16 45 2 0 0.827 0.0634
## 7 24 43 1 0 0.808 0.0677
## 8 26 42 1 0 0.788 0.0718
## 9 27 41 1 0 0.769 0.0760
## 10 28 40 1 0 0.75 0.0801
## # ℹ 59 more rows
## # ℹ 4 more variables: conf.high <dbl>, conf.low <dbl>,
## # strata <chr>, CumHaz <dbl>
La estimación queda guardada en la variable R, y se puede graficar directamente usando el objeto survfit utilizando plot() o ggsurvplot.
plot(tongue.km, fun = "cumhaz", conf.int = F, main = "Riesgo Acumulado", col = 1:2,
xlab = "Tiempo", ylab = "Riesgo Acumulado")
ggsurvplot(tongue.km, fun = "cumhaz", xlab = "Tiempo", censor = T,
ylab = "Riesgo Acumulado", title = "Riesgo Acumulado",
legend.title = "Perfil de ADN tumoral",
legend.labs = c("Aneuploide", "Diploide"))
La información es extraída de la misma manera que la Estimación Máxima Verosimilitud, con la diferencia que se calcula la suma acumulada del número de eventos entre las personas en riesgo.
La gráfica de riesgo acumulado se realiza manualmente utilizando la función qplot.
tongue_ovarian <- tidy(tongue.km)
#Crear variable CumHaz (
R <- tongue_ovarian %>%
mutate(CumHaz = cumsum(n.event / n.risk))
R
## # A tibble: 69 × 10
## time n.risk n.event n.censor estimate std.error conf.high conf.low strata
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 1 52 1 0 0.981 0.0194 1 0.944 type=1
## 2 3 51 2 0 0.942 0.0343 1 0.881 type=1
## 3 4 49 1 0 0.923 0.0400 0.998 0.853 type=1
## 4 10 48 1 0 0.904 0.0452 0.988 0.827 type=1
## 5 13 47 2 0 0.865 0.0547 0.963 0.777 type=1
## 6 16 45 2 0 0.827 0.0634 0.936 0.730 type=1
## 7 24 43 1 0 0.808 0.0677 0.922 0.707 type=1
## 8 26 42 1 0 0.788 0.0718 0.908 0.685 type=1
## 9 27 41 1 0 0.769 0.0760 0.893 0.663 type=1
## 10 28 40 1 0 0.75 0.0801 0.877 0.641 type=1
## # ℹ 59 more rows
## # ℹ 1 more variable: CumHaz <dbl>
qplot(time, CumHaz, data = R, geom = "step", xlab = "Tiempo (Semanas)", ylab = "Riesgo Acumulado",
main = "Riesgo Acumulado")
## Warning: `qplot()` was deprecated in ggplot2 3.4.0.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
tongue_ovarian <- tidy(tongue.km)
# Crear la variable CumHaz (Hazard acumulado) agrupando por estratos
R <- tongue_ovarian %>%
group_by(strata) %>%
mutate(CumHaz = cumsum(n.event / n.risk))
R
## # A tibble: 69 × 10
## # Groups: strata [2]
## time n.risk n.event n.censor estimate std.error conf.high conf.low strata
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 1 52 1 0 0.981 0.0194 1 0.944 type=1
## 2 3 51 2 0 0.942 0.0343 1 0.881 type=1
## 3 4 49 1 0 0.923 0.0400 0.998 0.853 type=1
## 4 10 48 1 0 0.904 0.0452 0.988 0.827 type=1
## 5 13 47 2 0 0.865 0.0547 0.963 0.777 type=1
## 6 16 45 2 0 0.827 0.0634 0.936 0.730 type=1
## 7 24 43 1 0 0.808 0.0677 0.922 0.707 type=1
## 8 26 42 1 0 0.788 0.0718 0.908 0.685 type=1
## 9 27 41 1 0 0.769 0.0760 0.893 0.663 type=1
## 10 28 40 1 0 0.75 0.0801 0.877 0.641 type=1
## # ℹ 59 more rows
## # ℹ 1 more variable: CumHaz <dbl>
qplot(time, CumHaz, col = strata, data = R, geom = "step", xlab = "Tiempo (Semanas)",
ylab = "Riesgo Acumulado", main = "Riesgo Acumulado")
Si solo se desea ver la estimación del riesgo acumulado en un gráfico, la función plot() o ggsurvplot bajo el argumento fun=“cumhaz” hace esto posible, esta estimación utiliza el método Máxima Verosimilitud.
La estimación de la media se realiza integrando la función sobrevivencia estimada hasta un valor t. En R la estimación se realiza con la función print() usando como argumento una estimación survfit, bajo los siguientes argumentos:
Ejemplo:
print(tongue.km, print.rmean = TRUE)
## Call: survfit(formula = Surv(time, delta) ~ type, data = tongue)
##
## n events rmean* se(rmean) median 0.95LCL 0.95UCL
## type=1 52 31 146.6 27.7 93 67 NA
## type=2 28 22 86.8 24.0 42 23 112
## * restricted mean with upper limit = 400
Tanto como para la estimación de la mediana, tanto como los percentiles se utiliza la función quantile(), los argumentos de la función son los siguientes:
NOTA: La estimación del intervalo de confianza se utiliza en el mismo nivel de confianza que se usó en el survfit.
Ejemplo:
quantile(tongue.km, c(0.05, 0.5, 0.95))
## $quantile
## 5 50 95
## type=1 3 93 NA
## type=2 3 42 NA
##
## $lower
## 5 50 95
## type=1 1 67 NA
## type=2 1 23 181
##
## $upper
## 5 50 95
## type=1 16 NA NA
## type=2 12 112 NA
Estas pruebas de hipótesis se realizan en R utilizando la función survdiff() bajo los siguientes argumentos:
y ~ x, que
debe tener un objeto Surv como la respuesta a la izquierda
del ~ y, si se desea, las covariables por la derecha. Uno
de los términos puede ser un objeto strata. Para una sola
curva de sobrevivencia del lado derecho se coloca ~1.data.frame donde están
los datos.rho, se
tienen las siguientes pruebas de hipótesis:
rho = 0, Prueba log-rank (Defecto).rho = 1, Prueba Peto & Peto de la modificación de
la prueba Gehan-Wilcoxon.Ejemplo:
Se utilizará la base de datos “Ovarian” que contiene 26 observaciones de 6 variables, trata la sobrevivencia en un ensayo aleatorizado comparando dos tratamientos para el cáncer de ovario:
library(survival)
data("ovarian")
head(ovarian)
## futime fustat age resid.ds rx ecog.ps
## 1 59 1 72.3315 2 1 1
## 2 115 1 74.4932 2 1 1
## 3 156 1 66.4658 2 1 2
## 4 421 0 53.3644 2 2 1
## 5 431 1 50.3397 2 1 1
## 6 448 0 56.4301 1 1 2
Utilizando esta información se compara si existe alguna diferencia de las curvas de sobrevivencia entre los estados del deceso.
survdiff(Surv(futime, fustat) ~ resid.ds, data = ovarian, rho = 0) #Prueba log-rank
## Call:
## survdiff(formula = Surv(futime, fustat) ~ resid.ds, data = ovarian,
## rho = 0)
##
## N Observed Expected (O-E)^2/E (O-E)^2/V
## resid.ds=1 11 3 6.26 1.70 3.62
## resid.ds=2 15 9 5.74 1.85 3.62
##
## Chisq= 3.6 on 1 degrees of freedom, p= 0.06
survdiff(Surv(futime, fustat) ~ resid.ds, data = ovarian, rho = 1) #Prueba Peto & Peto
## Call:
## survdiff(formula = Surv(futime, fustat) ~ resid.ds, data = ovarian,
## rho = 1)
##
## N Observed Expected (O-E)^2/E (O-E)^2/V
## resid.ds=1 11 1.95 4.79 1.68 4.31
## resid.ds=2 15 7.45 4.61 1.75 4.31
##
## Chisq= 4.3 on 1 degrees of freedom, p= 0.04
Las combinaciones o pruebas posibles se realizan con la función pairwise_survdiff(), esta devuelve una matriz con los p-valores de las comparaciones a pares. Es importante asegurar que la covariable a evaluar sea de tipo factor.
Los argumentos son los siguientes:
y ~ x, que
debe tener un objeto Surv como la respuesta a la izquierda
del ~ y, la covariable por la derecha.data.frame donde están
los datos."holm", "hochberg",
"hommel", "bonferroni", "BH",
"BY", "fdr", "none". Si no se
desea ajustar el p-valor (Práctica no recomendada), use
p.adjust.method = "none".Ejemplo:
En la base de datos ovarian, la covariable resid.ds no es de tipo factor por lo que se tiene que convertir en factor() antes de utilizar la prueba.
class(ovarian$resid.ds) #Tipo Numérico
## [1] "numeric"
ovarian$resid.ds <- factor(ovarian$resid.ds)
class(ovarian$resid.ds) #Tipo factor
## [1] "factor"
pairwise_survdiff(Surv(futime, fustat) ~ resid.ds, data = ovarian, p.adjust.method = "bonferroni",
rho = 1)
##
## Pairwise comparisons using Peto & Peto test
##
## data: ovarian and resid.ds
##
## 1
## 2 0.038
##
## P value adjustment method: bonferroni
La prueba estratificada se hace similarmente a la anterior con la distinción que se le agrega +strata(estrato) en la formula.
Ejemplo:
Para nuestro ejemplo utilizaremos la base de datos ovarian y crearemos una nueva variable llamada GrupoEdad en donde se agrupe a las personas en 3 tipos de edades: 39-54, 54-60, 60+ utilizando la función cut(), esta variable será utilizada como estrato.
ovarian$GrupoEdad <- cut(ovarian$age, breaks = c(39, 54, 60, 90)) #Nueva variable
survdiff(Surv(futime, fustat) ~ resid.ds + strata(GrupoEdad), data = ovarian, rho = 1)
## Call:
## survdiff(formula = Surv(futime, fustat) ~ resid.ds + strata(GrupoEdad),
## data = ovarian, rho = 1)
##
## n=25, 1 observation deleted due to missingness.
##
## N Observed Expected (O-E)^2/E (O-E)^2/V
## resid.ds=1 11 1.71 3.48 0.893 2.14
## resid.ds=2 14 7.17 5.41 0.574 2.14
##
## Chisq= 2.1 on 1 degrees of freedom, p= 0.1
La función comp() de la librería survMisc realiza comparaciones entre curvas de sobrevivencia con diferentes métodos. Cuando el número de grupos es mayor a 2, esta función realiza la prueba de tendencia. Los argumentos de la función son los siguientes:
Los argumentos p y q pueden ser ignorados, el argumento scores si no se le es indicado toma como valores un vector 1 hasta n, donde n es el numero de grupos.
La función devuelve como valores dos tablas, la primera una serie de pruebas de hipótesis de igualdad de curvas mientras que la segunda una serie de pruebas de hipótesis de tendencia de curvas.
Ejemplo:
library(survMisc)
model <- ten(Surv(futime, fustat) ~ resid.ds, data = ovarian)
comp(model, scores = c(1, 2, 3, 4))
## Q Var Z pNorm
## 1 3.2607e+00 2.9343e+00 1.9035 5
## n 7.2000e+01 1.1610e+03 2.1131 1
## sqrtN 1.5321e+01 5.6551e+01 2.0374 4
## S1 2.7303e+00 1.7227e+00 2.0802 3
## S2 2.6122e+00 1.5615e+00 2.0904 2
## FH_p=1_q=1 3.5717e-01 8.3477e-02 1.2362 6
## maxAbsZ Var Q pSupBr
## 1 3.9577e+00 2.9343e+00 2.3104 5
## n 8.0000e+01 1.1610e+03 2.3479 4
## sqrtN 1.7682e+01 5.6551e+01 2.3513 3
## S1 3.1070e+00 1.7227e+00 2.3672 2
## S2 2.9587e+00 1.5615e+00 2.3677 1
## FH_p=1_q=1 5.2755e-01 8.3477e-02 1.8259 6
La función de sobrevivencia puede ser estimada por medio de distribuciones paramétricas con la función flexsurvreg() de la paquetería flexsurv. Los parámetros son estimados por máxima verosimilitud utilizando los algoritmos disponibles en la función de optim() de R.
Los parámetros definidos como positivos son estimados en la escala logarítmica. Los intervalos de confianza se calculan a partir de la matriz Hessiana, y se transforman de nuevo a la escala original de los parámetros.
formula: Un objeto fórmula y ~ 1, que debe tener un objeto Surv como variable respuesta y a la izquierda del ” ~” y del lado derecho se coloca ~1.
Tabla 2
| Nombre de la distribución | Función | Número de parámetros |
|---|---|---|
| Gamma generalizada (estable) | gengamma |
3 |
| Gamma generalizada (original) | gengamma.orig |
3 |
| F generalizada (estable) | genf |
4 |
| F generalizada (original) | genf.orig |
4 |
| Weibull | weibull |
2 |
| Gamma | gamma |
2 |
| Exponencial | exp |
1 |
| Log-logística | llogis |
2 |
| Log-normal | lnorm |
2 |
| Gompertz | gompertz |
2 |
Las distribuciones tal como la Weibull, Gamma, Exponencial, etc. en su gran mayoría distribuciones pro- gramadas en R cuentan con sus respectivas funciones para calcular su densidad, su función de distribución, su función de cuantiles y la generación aleatoria de acuerdo a su distribución.
Estas funciones tienen como nombre la distribución y se le agrega al inicio la letra según la función deseada.
Ejemplo:
pgamma(10, shape = 5, scale = 4) #Función de Distribucion Gamma
## [1] 0.108822
dweibull(1, shape = 0.5, scale = 2) #Función de Densidad Weibull
## [1] 0.1743261
qlogis(0.5, location = 1, scale = 3) #Función Cuantil de log-Logística
## [1] 1
rgompertz(n = 10, shape = 1, rate = 1/50) #Función de Gompertz
## [1] 1.7467062 4.4651631 4.0142776 4.2894442 4.9889105 0.8915778 3.0524591
## [8] 4.8136235 3.6007778 2.8415390
Retomando la base de datos anterior “ovarian”.
library(survival)
data("ovarian")
## Warning in data("ovarian"): data set 'ovarian' not found
head(ovarian)
## futime fustat age resid.ds rx ecog.ps GrupoEdad
## 1 59 1 72.3315 2 1 1 (60,90]
## 2 115 1 74.4932 2 1 1 (60,90]
## 3 156 1 66.4658 2 1 2 (60,90]
## 4 421 0 53.3644 2 2 1 (39,54]
## 5 431 1 50.3397 2 1 1 (39,54]
## 6 448 0 56.4301 1 1 2 (54,60]
flex <- flexsurvreg(Surv(futime, fustat) ~ 1, data = ovarian, dist = "exp") #Ajuste exponencial
flex
## Call:
## flexsurvreg(formula = Surv(futime, fustat) ~ 1, data = ovarian,
## dist = "exp")
##
## Estimates:
## est L95% U95% se
## rate 0.000770 0.000437 0.001356 0.000222
##
## N = 26, Events: 12, Censored: 14
## Total time at risk: 15588
## Log-likelihood = -98.0322, df = 1
## AIC = 198.0644
La salida de la función son las siguientes:
Se puede comparar el ajuste paramétrico con el ajuste no-paramétrico utilizando la función plot(), con los siguientes argumentos:
Ejemplo:
plot(flex, type = "cumhaz", ci = F, main = "Riesgo Acumulado", conf.int = F,
col = 3, col.obs = 4, xlab = "Tiempo", ylab = "Riesgo Acumulado")
plot(flex, type = "survival", ci = F, main = "Probabilidad de sobrevivencia",
conf.int = F, col = 1, col.obs = 2,
xlab = "Tiempo", ylab = "Probabilidad de sobrevivencia")
Por el momento no se tiene implementando ningún código para visualizar este gráfico en ggplot2, sin embargo, con el siguiente script para realizar la comparación entre el ajuste paramétrico y ajuste no-paramétrico en la Curva de sobrevivencia y Riesgo Acumulado.
El script calcula las estimaciones de la probabilidad de sobrevivencia (O Riesgo Acumulado) mediante la función summary() (Paramétrico) y fortify() o tidy() (No Paramétrico) en caso de no funcionar fortify según la versión de R utilizada y los gráfica mediante geom_line() y geom_step() respectivamente.
Los cambios que se realizan en el script son los argumentos de la función flexsurvreg, survfit.
library(survival) # Para survfit y Surv
library(flexsurv) # Para flexsurvreg
library(broom) # Para tidy
library(ggplot2) # Para graficar
library(dplyr) # Para manipulación de datos
#Ajuste modelo paramétrico
flexgg <- flexsurvreg(Surv(futime, fustat) ~ 1, data = ovarian, dist = "exp") %>%
summary(type = "survival") %>%
as.data.frame()
#Renombrar columnas para asegurar compatibilidad con ggplot
names(flexgg) <- c("time", "est", "lower", "upper")
#Ajuste del modelo no paramétrico y conversión con tidy
kmgg <- survfit(Surv(futime, fustat) ~ 1, data = ovarian) %>%
tidy()
#Comprobar nombres de columnas
print(names(flexgg))
## [1] "time" "est" "lower" "upper"
print(names(kmgg))
## [1] "time" "n.risk" "n.event" "n.censor" "estimate" "std.error"
## [7] "conf.high" "conf.low"
#
kmgg <- survfit(Surv(futime, fustat) ~ 1, data = ovarian) %>% tidy()
#
if (!"surv" %in% names(kmgg)) {
kmgg$surv <- kmgg$estimate # Asumiendo que 'estimate' es el equivalente a 'surv'
}
#
ggplot() +
geom_line(aes(x = time, y = est, col = "Paramétrico"), data = flexgg) +
geom_step(aes(x = time, y = surv, col = "No Paramétrico"), data = kmgg) +
labs(x = "Time",
y = "Probabilidad de Sobrevivencia",
colour = "Ajustes",
title = "Comparación entre curvas de Sobrevivencia") +
scale_color_manual(values = c("Paramétrico" = "blue", "No Paramétrico" = "red")) +
theme_minimal()
La gráfica de riesgo acumulado se realiza utilizando el mismo script utilizando y=−log(Sest(t))
library(survival) # Para survfit y Surv
library(flexsurv) # Para flexsurvreg
library(broom) # Para tidy
library(ggplot2) # Para graficar
library(dplyr) # Para manipulación de datos
#Ajuste del modelo paramétrico
flexgg <- flexsurvreg(Surv(futime, fustat) ~ 1,
data = ovarian, dist = "exp") %>%
summary(type = "survival") %>%
as.data.frame()
#Renombrar columnas para asegurar compatibilidad con ggplot
names(flexgg) <- c("time", "est", "lower", "upper")
#Ajuste del modelo no paramétrico y conversión con tidy
kmgg <- survfit(Surv(futime, fustat) ~ 1, data = ovarian) %>%
tidy()
#Nombres de columnas
print(names(flexgg))
## [1] "time" "est" "lower" "upper"
print(names(kmgg))
## [1] "time" "n.risk" "n.event" "n.censor" "estimate" "std.error"
## [7] "conf.high" "conf.low"
#
kmgg <- survfit(Surv(futime, fustat) ~ 1, data = ovarian) %>% tidy()
#
if (!"surv" %in% names(kmgg)) {
kmgg$surv <- kmgg$estimate
}
#
ggplot() +
geom_line(aes(x = time, y = -log(est), col = "Paramétrico"), data = flexgg) +
geom_step(aes(x = time, y = -log(surv), col = "No Paramétrico"), data = kmgg) +
labs(x = "Time",
y = "Probabilidad de Sobrevivencia",
colour = "Ajustes",
title = "Comparación entre curvas de Sobrevivencia") +
scale_color_manual(values = c("Paramétrico" = "blue", "No Paramétrico" = "red")) +
theme_minimal()
Dados dos o más grupos, la comparación entre las curvas paramétricas se realiza mediante la función flex- survreg indicando el nombre de la columna de los grupos igualada a un nivel del mismo en el argumento subset.
Ejemplo:
flex <- flexsurvreg(Surv(futime, fustat) ~ 1, data = ovarian, dist = "exp", subset = ecog.ps ==
1)
flex
## Call:
## flexsurvreg(formula = Surv(futime, fustat) ~ 1, data = ovarian,
## subset = ecog.ps == 1, dist = "exp")
##
## Estimates:
## est L95% U95% se
## rate 0.000600 0.000250 0.001442 0.000268
##
## N = 14, Events: 5, Censored: 9
## Total time at risk: 8332
## Log-likelihood = -42.0921, df = 1
## AIC = 86.18421
Bajo este método, el análisis se realiza individualmente para cada nivel de la variable. Otro método para analizar es ajustar una misma distribución a cada grupo. Se deja el siguiente script con los siguientes parámetros modificables:
data.frame que contiene los
datos.El script funciona agrupando la base de datos (ovarian)
por la covariable (ecog.ps) y aplicando a cada grupo un
ajuste paramétrico (gompertz), guardando los resultados en
la variable model.
head(ovarian)
## futime fustat age resid.ds rx ecog.ps GrupoEdad
## 1 59 1 72.3315 2 1 1 (60,90]
## 2 115 1 74.4932 2 1 1 (60,90]
## 3 156 1 66.4658 2 1 2 (60,90]
## 4 421 0 53.3644 2 2 1 (39,54]
## 5 431 1 50.3397 2 1 1 (39,54]
## 6 448 0 56.4301 1 1 2 (54,60]
model <- ovarian %>% group_by(resid.ds) %>% do(flex = flexsurvreg(Surv(futime, fustat) ~
1, data = ., dist = "gompertz"))
model
## # A tibble: 2 × 2
## # Rowwise:
## resid.ds flex
## <fct> <list>
## 1 1 <flxsrvrg>
## 2 2 <flxsrvrg>
model$flex
## [[1]]
## Call:
## flexsurvreg(formula = Surv(futime, fustat) ~ 1, data = ., dist = "gompertz")
##
## Estimates:
## est L95% U95% se
## shape 9.00e-04 -2.14e-03 3.94e-03 1.55e-03
## rate 2.38e-04 2.72e-05 2.07e-03 2.62e-04
##
## N = 11, Events: 3, Censored: 8
## Total time at risk: 8243
## Log-likelihood = -26.63719, df = 2
## AIC = 57.27437
##
##
## [[2]]
## Call:
## flexsurvreg(formula = Surv(futime, fustat) ~ 1, data = ., dist = "gompertz")
##
## Estimates:
## est L95% U95% se
## shape -0.000743 -0.003359 0.001874 0.001335
## rate 0.001555 0.000565 0.004281 0.000803
##
## N = 15, Events: 9, Censored: 6
## Total time at risk: 7345
## Log-likelihood = -69.17407, df = 2
## AIC = 142.3481
Se utilizar model$flex[[]] para acceder a los ajustes individuales.
Ejemplo:
model$flex[[1]]
## Call:
## flexsurvreg(formula = Surv(futime, fustat) ~ 1, data = ., dist = "gompertz")
##
## Estimates:
## est L95% U95% se
## shape 9.00e-04 -2.14e-03 3.94e-03 1.55e-03
## rate 2.38e-04 2.72e-05 2.07e-03 2.62e-04
##
## N = 11, Events: 3, Censored: 8
## Total time at risk: 8243
## Log-likelihood = -26.63719, df = 2
## AIC = 57.27437
El siguiente script gráfica las curvas no paramétricas con las curvas paramétricas. Únicamente se tiene que realizar primero el ajuste no paramétrico en la variable KM.
Este script se modifica la variable KM de acuerdo a los parámetros deseados.
#Ajuste Curva de Sobrevivencia No-Paramétrica con KM
KM <- survfit(Surv(futime, fustat) ~ rx, data = ovarian)
#Ajuste modelos paramétricos para cada grupo en 'rx'
models_flex <- lapply(unique(ovarian$rx), function(x) {
data_subset <- ovarian[ovarian$rx == x, ]
flexsurvreg(Surv(futime, fustat) ~ 1, data = data_subset, dist = "exp")
})
#
plot(KM, col = 1:length(models_flex), main = "Comparación Paramétrica",
xlab = "Tiempo",ylab = "Probabilidad de Sobrevivencia")
#Líneas para cada modelo paramétrico
for (i in 1:length(models_flex)) {
curve_data <- summary(models_flex[[i]], type = "survival")
print(curve_data)
}
#Ajuste del modelo Kaplan-Meier con estratificación por 'rx'
KM <- survfit(Surv(futime, fustat) ~ rx, data = ovarian)
#
plot(KM, col = 1:length(KM$strata), main = "Comparación Paramétrica", xlab = "Tiempo",
ylab = "Riesgo Acumulado", fun = "cumhaz")
#Verificar estructura KM
print(KM)
## Call: survfit(formula = Surv(futime, fustat) ~ rx, data = ovarian)
##
## n events median 0.95LCL 0.95UCL
## rx=1 13 7 638 268 NA
## rx=2 13 5 NA 475 NA
#
Para realizar la gráfica en ggplot2 se deja el siguiente script, los parámetros a modificar son survfit de la variable KM y ejecutar previamente el script de comparación entre curvas.
El script extrae de la lista los valores estimados de la curva de sobrevivencia.
KM <- survfit(Surv(futime, fustat) ~ resid.ds, data = ovarian)
plot(KM, col = 1:length(model$flex), main = "Comparación Paramétrica", xlab = "Tiempo",
ylab = "Probabilidad de Sobrevivencia")
for (i in 1:length(model$flex)) lines(model$flex[[i]], ci = F, col = i)
KM <- survfit(Surv(futime, fustat) ~ resid.ds, data = ovarian)
plot(KM, col = 1:length(model$flex), main = "Comparación Paramétrica", xlab = "Tiempo",
ylab = "Riesgo Acumulado", fun = "cumhaz")
for (i in 1:length(model$flex)) lines(model$flex[[i]], ci = F, col = i, type = "cumhaz")
La comparación entre los modelos ajustados se puede realizar visualmente entre la curva de sobrevivencia Kaplan-Meier y las curvas paramétricas ajustadas o mediante el índice AIC.
La comparación gráfica se realiza con el siguiente script, únicamente se debe definir en la variable Dist las distribuciones que se desean comparar, el objeto tipo Surv en la variable data.Surv y guardar la base de datos como datosflex, si se desea utilizar por grupos se debe utilizar el argumento subset en la función flexsurvreg o filtrar los datos antes de ejecutar.
datosflex <- ovarian
Dist <- c("exp", "weibull", "llogis", "gompertz")
data.Surv <- Surv(datosflex$futime, datosflex$fustat)
model <- sapply(Dist, function(x) flexsurvreg(data.Surv ~ 1, dist = x), USE.NAMES = T,
simplify = F)
model
## $exp
## Call:
## flexsurvreg(formula = data.Surv ~ 1, dist = x)
##
## Estimates:
## est L95% U95% se
## rate 0.000770 0.000437 0.001356 0.000222
##
## N = 26, Events: 12, Censored: 14
## Total time at risk: 15588
## Log-likelihood = -98.0322, df = 1
## AIC = 198.0644
##
##
## $weibull
## Call:
## flexsurvreg(formula = data.Surv ~ 1, dist = x)
##
## Estimates:
## est L95% U95% se
## shape 1.108 0.674 1.822 0.281
## scale 1225.419 690.421 2174.979 358.714
##
## N = 26, Events: 12, Censored: 14
## Total time at risk: 15588
## Log-likelihood = -97.9539, df = 2
## AIC = 199.9078
##
##
## $llogis
## Call:
## flexsurvreg(formula = data.Surv ~ 1, dist = x)
##
## Estimates:
## est L95% U95% se
## shape 1.376 0.842 2.249 0.345
## scale 837.753 470.311 1492.268 246.769
##
## N = 26, Events: 12, Censored: 14
## Total time at risk: 15588
## Log-likelihood = -97.3547, df = 2
## AIC = 198.7094
##
##
## $gompertz
## Call:
## flexsurvreg(formula = data.Surv ~ 1, dist = x)
##
## Estimates:
## est L95% U95% se
## shape -0.000509 -0.002568 0.001550 0.001050
## rate 0.000930 0.000371 0.002330 0.000436
##
## N = 26, Events: 12, Censored: 14
## Total time at risk: 15588
## Log-likelihood = -97.90959, df = 2
## AIC = 199.8192
Cada modelo se puede acceder de manera individual utilizado $ sobre la variable model.
model$gompertz
## Call:
## flexsurvreg(formula = data.Surv ~ 1, dist = x)
##
## Estimates:
## est L95% U95% se
## shape -0.000509 -0.002568 0.001550 0.001050
## rate 0.000930 0.000371 0.002330 0.000436
##
## N = 26, Events: 12, Censored: 14
## Total time at risk: 15588
## Log-likelihood = -97.90959, df = 2
## AIC = 199.8192
El siguiente script realiza la comparación gráfica utilizando los gráficos bases de R.
#Curva de sobrevivencia
plot(model[[1]], ci = F, conf.int = F, lty = 2, main = "Ajuste Paramétrico",
xlab = "Time", ylab = "Probabilidad de sobrevivencia")
for (i in 2:length(Dist)) plot(model[[i]], ci = F, conf.int = F, add = T, col = i +
1, lty = i)
legend("topright", c("KM", Dist), lty = 1:(length(Dist) + 1), col = 1:(length(Dist) +
1))
#Riesgo Acumulado
plot(model[[1]], ci = F, conf.int = F, lty = 2, main = "Ajuste Paramétrico",
xlab = "Time", ylab = "Riesgo Acumulado", type = "cumhaz")
for (i in 2:length(Dist)) plot(model[[i]], ci = F, conf.int = F, add = T, col = i +
1, lty = i, type = "cumhaz")
legend("topright", c("KM", Dist), lty = 1:(length(Dist) + 1), col = 1:(length(Dist) +
1))
Los índices AIC, BIC y Log-verosimilitud, se extrae utilizando las funciones: AIC(), BIC() y logLik() tomando como único argumento un objeto flexsurvreg.
model <- flexsurvreg(Surv(futime, fustat) ~ 1, data = ovarian, dist = "lnorm")
AIC(model)
## [1] 198.2435
BIC(model)
## [1] 200.7597
logLik(model)
## 'log Lik.' -97.12174 (df=2)
Cuando se realiza una comparación entre modelos se puede utilizar el siguiente script para generar una tabla con los respectivos índices para cada distribución. Los parámetros a modificar son los datos datosflex así como data.Surv y las distribuciones a comparar en Dist.
datosflex <- ovarian
data.Surv <- Surv(datosflex$futime, datosflex$fustat)
Dist <- c("exp", "weibull", "llogis", "gompertz")
#Inicio Script
model <- sapply(Dist, function(x) flexsurvreg(data.Surv ~ 1, data = datosflex,
dist = x), USE.NAMES = T, simplify = F)
AIC.model <- sapply(model, function(x) c(AIC = AIC(x), BIC = BIC(x), LogLik = logLik(x)),
simplify = T)
AIC.model
## exp weibull llogis gompertz
## AIC 198.0644 199.9078 198.7094 199.81919
## BIC 199.3225 202.4240 201.2256 202.33538
## LogLik -98.0322 -97.9539 -97.3547 -97.90959
#Ordenados por menor AIC
AIC.model[, order(AIC.model["AIC", ])]
## exp llogis gompertz weibull
## AIC 198.0644 198.7094 199.81919 199.9078
## BIC 199.3225 201.2256 202.33538 202.4240
## LogLik -98.0322 -97.3547 -97.90959 -97.9539
Se compara mediante una serie de transformaciones si la estimación no-paramétrica puede ser razonablemente estimada por algún modelo paramétrico. Los argumentos de la función son los siguientes:
Distribución y sus códigos:
Tabla 3
Tabla de Distribuciones
| Distribución | Función |
|---|---|
| Exponencial | exp |
| Weibull | weibull |
| Gumbel | gumbel |
| Log-Normal | lnorm |
| Gamma | gamma |
| Normal | norm |
| Logística | logis |
| Log-logística | llogis |
| Pareto | pareto |
La función es un objeto ggplot2 y se le puede agregar títulos y valor a los ejes con labs().
Ejemplo:
#Ajuste no paramétrico con Kaplan-Meier
KM <- survfit(Surv(futime, fustat) ~ 1, data = ovarian)
plot(KM)
#Ajuste paramétrico con una distribución de Weibull
parametric_model <- flexsurvreg(Surv(futime, fustat) ~ 1,
data = ovarian, dist = "weibull")
plot(parametric_model)
El gráfico de bondad de ajuste se realiza mediante un gráfico de dispersión entre \(1 - S_{KM}(t_i)\) y \(F_{EMV}(t_i; \hat{\theta})\), donde \(S_{KM}(t_i)\) es la estimación no paramétrica de la curva de sobrevivencia y \(F_{EMV}(t_i; \hat{\theta})\) es la estimación de Máxima Verosimilitud suponiendo una distribución específica.
El script extrae estos valores, guardándolos en las variables
F_est y KM_est y los gráfica utilizando la
función plot() o qplot().
Los parámetros modificables de este script son los argumentos de las
funciones flexsurvreg() y survfit().
flex <- flexsurvreg(Surv(futime, fustat) ~ 1,
data = ovarian, dist = "gompertz") # Ajuste Paramétrico
F_est <- 1 - as.data.frame(summary(flex))[, "est"]
KM_est <- survfit(Surv(futime, fustat) ~ 1, ovarian)
#Ajuste no-paramétrico
KM_est <- 1 - KM_est$surv
plot(F_est, KM_est)
qplot(F_est, KM_est)
El gráfico de probabilidad estabilizado se realiza utilizando el
anterior script, anexando las transformaciones en ambos ejes: \(2\pi \sin^{-1}(\sqrt{F(t_i)})\) en las
funciones plot() o qplot().
plot((2/pi) * asin(sqrt(KM_est)), (2/pi) * asin(sqrt(F_est)), xlab = "F-km-stab",
ylab = "F-emv-stab", main = "Gráfica de Probabilidad Estabilizada")
qplot((2/pi) * asin(sqrt(KM_est)), (2/pi) * asin(sqrt(F_est))) + labs(x = "F-km-stab",
y = "F-emv-stab", title = "Gráfica de Probabilidad Estabilizada")
Supongamos que en un estudio que consiste en la comparación de los tiempos de falla de dos grupos. Los pacientes fueron seleccionados aleatoriamente para recibir el tratamiento estándar (grupo 0) y un nuevo tratamiento (grupo 1). La función de tasa de falla del primer grupo será representada por \(h_0(t)\) y la del segundo grupo por \(h_1(t)\). Asumiendo proporcionalidad entre estas funciones, se tiene que:
\[ \frac{h_1(t)}{h_0(t)} = K \]
Dónde \(K\) es la razón de tasa de falla o riesgo relativo, constante para todo tiempo \(t\) de acompañamiento del estudio. Si \(X\) es la variable indicadora del grupo, dónde
\[ X = \begin{cases} 0 & \text{si es del grupo 0} \\ 1 & \text{si es del grupo 1} \end{cases} \]
Si \(K = \exp(\beta x)\), entonces
\[ h(t) = h_0(t) \exp(\beta x) \]
esto es,
\[ h(t) = \begin{cases} h_1(t) = h_0(t) \exp(\beta) & \text{si } x = 1 \\ h_0(t) & \text{si } x = 0 \end{cases} \]
De una forma genérica consideremos \(p\) covariables de modo que \(x\) es un vector con los componentes \(x = (x_1, \ldots, x_p)\). Así que la expresión general del modelo de regresión de Cox será:
\[ h(t) = h_0(t) g(x^\top \beta) \]
Dónde \(g\) es una función que debe ser especificada, tal que \(g(0) = 1\). El componente no paramétrico, \(h_0(t)\), no es especificado y es una función no negativa del tiempo. El componente paramétrico es frecuentemente usado de la siguiente forma multiplicativa:
\[ g(x^\top \beta) = \exp(x^\top \beta) = \exp(\beta_1 x_1 + \cdots + \beta_p x_p) \]
En que \(\beta\) es el vector de parámetros asociado a las covariables. Esta forma garantiza que \(h(t)\) será siempre positiva. Este modelo es también llamado modelo de riesgos proporcionales, esto debido a que la razón de las tasas de falla de dos individuos diferentes es constante en el tiempo. Esto es, la razón de las tasas de falla para dos individuos diferentes, \(i\) y \(j\), es:
\[ \frac{h_i(t)}{h_j(t)} = \frac{h_0(t) \exp(x_i \beta)}{h_0(t) \exp(x_j \beta)} \]
que no depende del tiempo. La suposición básica para el uso del modelo de regresión de Cox, por tanto, es que las tasas de falla sean proporcionales.
El modelo de regresión de Cox utiliza coeficientes β para medir los efectos de las covariables en la tasa de falla. Para determinar el modelo, estos coeficientes deben estimarse a partir de datos muestrales.
A menudo se usa el método de máxima verosimilitud; sin embargo, la inclusión de un componente no paramétrico h0(t) en la función de verosimilitud hace que este método no sea el más adecuado.
Cox propuso una solución en su trabajo original, y la formalizó más adelante en 1975, el método de máxima verosimilitud parcial, que condiciona la verosimilitud para excluir el componente perturbador.
Consideremos una muestra de \(n\) individuos donde existen \(k \leq n\) fallas distintas en los tiempos \(t_1 \leq t_2 \leq \ldots \leq t_k\). Además, considerando el siguiente argumento condicional: la probabilidad condicional de que la i-ésima observación venga a fallar en el tiempo \(t_i\) dado las observaciones que están en riesgo en \(t_i\) es
\[ \frac{h_i(t)}{\sum_{j \in R(t_i)} h_j(t)} = \frac{h_0(t) \exp\{x_i \beta\}}{\sum_{j \in R(t_i)} h_0(t) \exp\{x_j \beta\}} = \frac{\exp\{x_i \beta\}}{\sum_{j \in R(t_i)} \exp\{x_j \beta\}} \]
donde \(R(t_i)\) es el conjunto de índices de las observaciones sobre el riesgo en el tiempo \(t_i\).
La función de verosimilitud a ser utilizada para hacer inferencias en el modelo, es entonces, formada por el producto de todos los términos representados de la ecuación anterior asociados a los tiempos diferentes de falla, esto es,
\[ L(\beta) = \prod_{i=1}^{k} \left( \frac{\exp\{x_i \beta\}}{\sum_{j \in R(t_i)} \exp\{x_j \beta\}} \right)^{\delta_i} \]
con \(\delta_i\) el indicador de falla.
Los valores de \(\beta\) que maximizan \(L(\beta)\) son obtenidos resolviendo el sistema de ecuaciones \(U(\beta) = 0\), donde \(U(\beta)\) es el vector de escore de las primeras derivadas de la función \(l(\beta) = \log(L(\beta))\).
A partir del modelo general de regresión de Cox, se puede observar que el efecto de las covariables es de acelerar o desacelerar la función de riesgo. Sin embargo, la propiedad de riesgos proporcionales del modelo debe ser usada para interpretar los coeficientes estimados. Tomando la razón de tasas de falla de dos individuos (i y j) que tienen los mismos valores para las covariables con excepción de la l-ésima, se tiene:
\[ \frac{h_i(t)}{h_j(t)} = \exp\{\beta_l (x_{il} - x_{jl})\} \]
que puede ser interpretado como la razón de riesgos o de riesgo relativo instantáneo en el tiempo t. Sin embargo, como esta razón es constante para todo el acompañamiento, se puede suprimir la palabra “instantánea” de la interpretación.
Por ejemplo, suponga que \(x_l\) sea una covariable dicotómica indicando pacientes hipertensos. El riesgo de muerte entre los hipertensos es \(\exp\{\beta_l\}\) veces el riesgo de pacientes con presión normal, manteniendo fijas las otras covariables.
\[ H_0(t) = \int_{0}^{t} h_0(u) \, du \]
y la correspondiente función de sobrevivencia
\[ S_0(t) = \exp(-H_0(t)) \]
Una estimación para \(H_0(t)\) es la propuesta por Breslow (1972), es una función escalonada con saltos en tiempos diferentes de falla y expresada por:
\[ H_0(t_i) = \sum_{j : t_j \leq t} \frac{d_j}{\sum_{l \in R_j} \exp(x_l \beta)} \]
con \(d_j\) el número de fallas en \(t_j\).
Consecuentemente, las funciones de sobrevivencia \(S_0(t)\) y \(S(t)\) pueden ser estimadas por:
\[ S(t) = \exp[-H_0(t)] \]
y
\[ S(t) = [S_0(t)]^{\exp(x \beta)} \]
Tanto \(S_0(t)\) como \(S(t)\) son funciones escalonadas decrecientes en el tiempo. Notemos que en la ausencia de covariables, la expresión de \(H_0(t_i)\) se reduce a
\[ H_0(t_i) = \sum_{j : t_j \leq t} \frac{d_j}{n_j} \]
que es el estimador de Nelson-Aalen. Notemos que por ese hecho, el estimador \(H_0(t_i)\) es también referenciado en la literatura como estimador de Nelson-Aalen-Breslow.
El modelo de regresión de Cox es bastante flexıble debido a la presencia del componente no paramétrico. Incluso así, el no se ajusta a cualquier situación clínica y como cualquier otro modelo estadístico, requiere de técnicas para validar su elección.
En particular, como mencionado anteriormente, el tiene una suposición básica que es la de riesgos propor- cionales. La violación de esta suposición puede acarriar serios vicios en la estimación de los coeficientes del modelo (Struthers e Kalbfleisch, 1986).
Para verificar la suposición de riesgos proporcionales en el modelo de Cox, un gráfico simple y bastante usado es propuesto para esta finalidad. La obtención de este gráfico consiste, inicialmente, en dividir los datos en m estratos, usualmente de acuerdo con alguna covariable.
Por ejemplo, dividir los datos en dos estratos de acuerdo a la covariable sexo. En seguida, se debe estimar \(H_{0j}(t)\) para cada estrato. Si la suposición fuese válida, las curvas del logaritmo de \(H_{0j}(t)\) versus \(t\), o \(\log(t)\), deben presentar diferencias aproximadamente constantes en el tiempo. Curvas no paralelas significan una contradicción en la suposición de riesgos proporcionales. Es razonable construir este gráfico para cada covariable incluida en el estudio. Si la covariable fuese de naturaleza continua, una sugerencia es agruparla en un pequeño número de categorías.
Una ventaja de esta técnica gráfica es la de indicar la covariable que está generando una violación de la suposición, en caso de que eso ocurra. Una propuesta adicional que viene siendo usada para verificar la suposición de los riesgos proporcionales en el modelo de Cox es analizar los residuos de Schoenfeld (1982).
Para definir los residuos, consideremos que existen \(k \leq n\) tiempos diferentes de falla \(t_1, \ldots, t_k\). Si el individuo \(i\) con vector de covariables \(x_i = (x_{1i}, \ldots, x_{2i}, \ldots, x_{pi})\) falló, entonces se tiene para ese individuo un vector de residuos Schoenfeld \(r_i = (r_{1i}, \ldots, r_{2i}, \ldots, r_{pi})\) en que cada componente \(r_{qi} (q = 1, \ldots, p)\) es definido por:
\[ r_{qi} = x_{qi} - \frac{\sum_{j \in R(t_i)} x_{qj} \exp\{x_j \beta\}}{\sum_{j \in R(t_i)} \exp\{x_j \beta\}} \]
Note que para cada una de las p covariables consideradas en el modelo, se tiene, para el individuo \(i\), un correspondiente residuo Schoenfeld. Como los residuos son definidos en cada falla, el conjunto de residuos Schoenfeld es una matriz con k líneas y p columnas. Cada línea corresponde a un tiempo distinto de falla y cada columna a una de las p covariables consideradas en el modelo. La k-ésima línea de esta matriz es obtenida por la ecuación anterior. Los residuos estandarizados están definidos por:
\[ r_i^* = I(\beta)^{-1} r_i \]
donde \(I(\beta)\) es la matriz de información de Fisher observada.
Para estimar correctamente el modelo de riesgos proporcionales se requiere que las variables a utilizar cumplan con ciertos requisitos dependiendo su tipo.
Se trabajará con la base de datos lung (package=“survival”). Esta trata sobre la sobrevivencia en pacientes con cáncer de pulmón avanzado del Grupo de Tratamiento del Cáncer Centro Norte. Las puntuaciones de rendimiento califican qué tan bien el paciente puede realizar las actividades diarias habituales. La data contiene 228 observaciones y 10 variables.
datos <- lung
str(datos)
## 'data.frame': 228 obs. of 10 variables:
## $ inst : num 3 3 3 5 1 12 7 11 1 7 ...
## $ time : num 306 455 1010 210 883 ...
## $ status : num 2 2 1 2 2 1 2 2 2 2 ...
## $ age : num 74 68 56 57 60 74 68 71 53 61 ...
## $ sex : num 1 1 1 1 1 1 2 2 1 1 ...
## $ ph.ecog : num 1 0 0 1 0 1 2 2 1 2 ...
## $ ph.karno : num 90 90 90 90 100 50 70 60 70 70 ...
## $ pat.karno: num 100 90 90 60 90 80 60 80 80 70 ...
## $ meal.cal : num 1175 1225 NA 1150 NA ...
## $ wt.loss : num NA 15 15 11 0 0 10 1 16 34 ...
head(datos)
## inst time status age sex ph.ecog ph.karno pat.karno meal.cal wt.loss
## 1 3 306 2 74 1 1 90 100 1175 NA
## 2 3 455 2 68 1 0 90 90 1225 15
## 3 3 1010 1 56 1 0 90 90 NA 15
## 4 5 210 2 57 1 1 90 60 1150 11
## 5 1 883 2 60 1 0 100 90 NA 0
## 6 12 1022 1 74 1 1 50 80 513 0
Para el uso de variables numéricas, no se requiere ningún formato en específico, su uso simplemente consiste en agregarla en la fórmula.
coxph(Surv(time, status) ~ age, data = datos)
## Call:
## coxph(formula = Surv(time, status) ~ age, data = datos)
##
## coef exp(coef) se(coef) z p
## age 0.018720 1.018897 0.009199 2.035 0.0419
##
## Likelihood ratio test=4.24 on 1 df, p=0.03946
## n= 228, number of events= 165
Las variables numéricas se pueden aplicar transformaciones en la expresión de la formula tales por ejemplo; log, exp, de manera general se usa la función para realizar estas transformaciones.
coxph(Surv(time, status) ~ log(age) + I(age^2) + I(age > 60), data = datos)
## Call:
## coxph(formula = Surv(time, status) ~ log(age) + I(age^2) + I(age >
## 60), data = datos)
##
## coef exp(coef) se(coef) z p
## log(age) -0.3847904 0.6805933 3.1873225 -0.121 0.904
## I(age^2) 0.0002760 1.0002760 0.0004346 0.635 0.525
## I(age > 60)TRUE -0.1844504 0.8315611 0.2863351 -0.644 0.519
##
## Likelihood ratio test=4.82 on 3 df, p=0.1855
## n= 228, number of events= 165
Para el uso de variables nominales u ordinales se debe codificar cada factor con un numero entero, posteri- ormente de leer los datos se debe indicar las variables que son Nominales u Ordinales.
Este procedimiento se realiza utilizando la función factor() sobre la columna del factor con los siguientes argumentos:
En caso de factores ordenados, las estimaciones en el modelo de Cox se usarán utilizando polinomios ortog- onales, mientras que en factores no ordenado se utilizará variables dummies.
Ejemplo:
En nuestra data lung no tenemos ninguna variable categórica por ello para fines demostrativos transformare- mos la variable ‘sex’ en un factor con etiquetas específicas.
Descripción del Conjunto de Datos
Tabla de Variables
| Variable | Descripción |
|---|---|
| inst | Código de la institución |
| time | Tiempo de sobrevivencia en días |
| status | Estado de censura: 1=censurado, 2=fallecido |
| age | Edad en años |
| sex | Sexo: Masculino=1, Femenino=2 |
| ph.ecog | Puntuación del estado funcional ECOG por el médico: 0=asintomático, 1=sintomático pero completamente ambulatorio |
| ph.karno | Puntuación de desempeño Karnofsky (malo=0-bueno=100) evaluada por el médico |
| pat.karno | Puntuación de desempeño Karnofsky evaluada por el paciente |
| meal.cal | Calorías consumidas en las comidas |
| wt.loss | Pérdida de peso en los últimos seis meses (libras) |
Sexo: 1- Male, 2- Female. ph.ecog: 0=asintomático, 1=sintomático.
datos$sex <- factor(datos$sex, levels = c(1, 2), labels = c("Male", "Female"))
datos$ph.ecog <- factor(datos$ph.ecog, levels = c(0, 1),
labels = c("asintomático", "sintomático."))
head(datos) #Datos tranformados
## inst time status age sex ph.ecog ph.karno pat.karno meal.cal wt.loss
## 1 3 306 2 74 Male sintomático. 90 100 1175 NA
## 2 3 455 2 68 Male asintomático 90 90 1225 15
## 3 3 1010 1 56 Male asintomático 90 90 NA 15
## 4 5 210 2 57 Male sintomático. 90 60 1150 11
## 5 1 883 2 60 Male asintomático 100 90 NA 0
## 6 12 1022 1 74 Male sintomático. 50 80 513 0
coxph(Surv(time, status) ~ sex, data = datos)
## Call:
## coxph(formula = Surv(time, status) ~ sex, data = datos)
##
## coef exp(coef) se(coef) z p
## sexFemale -0.5310 0.5880 0.1672 -3.176 0.00149
##
## Likelihood ratio test=10.63 on 1 df, p=0.001111
## n= 228, number of events= 165
coxph(Surv(time, status) ~ ph.ecog, data = datos)
## Call:
## coxph(formula = Surv(time, status) ~ ph.ecog, data = datos)
##
## coef exp(coef) se(coef) z p
## ph.ecogsintomático. 0.3673 1.4439 0.1987 1.849 0.0645
##
## Likelihood ratio test=3.56 on 1 df, p=0.05912
## n= 176, number of events= 119
## (52 observations deleted due to missingness)
Por defecto se toma como etiqueta base a la etiqueta con código más pequeño. De manera general se puede utilizar la función I( ) para crear las variables dummies, su uso consiste en crear indicadoras.
Ejemplo:
coxph(Surv(time, status) ~ I(sex == "Male") + I(sex == "Female"), data = datos)
## Call:
## coxph(formula = Surv(time, status) ~ I(sex == "Male") + I(sex ==
## "Female"), data = datos)
##
## coef exp(coef) se(coef) z p
## I(sex == "Male")TRUE 0.5310 1.7007 0.1672 3.176 0.00149
## I(sex == "Female")TRUE NA NA 0.0000 NA NA
##
## Likelihood ratio test=10.63 on 1 df, p=0.001111
## n= 228, number of events= 165
Para realizar la interacción con variables categóricas se requiere que estas variables sean codificadas con la función factor, tal como en el procedimiento anterior. Existen 3 formas principales para manejar la interacción en los modelos de regresión, y son mediante el uso de los siguientes operadores:
El operador * agrega las variables principales y
todas las posibles interacciones entre ellas en un modelo.
Por ejemplo, para un modelo de tasa de riesgo donde
\[ \lambda(t \mid X_i) = \lambda_0(t) \exp(\beta_0 \text{Edad} + \beta_1 \text{Sexo} + \beta_3 \text{Edad} \times \text{Sexo}) \]
la fórmula en R de la función podría ser representada de la siguiente manera:
coxph(Surv(time, status) ~ age * sex, data = datos)
## Call:
## coxph(formula = Surv(time, status) ~ age * sex, data = datos)
##
## coef exp(coef) se(coef) z p
## age 0.020343 1.020551 0.011395 1.785 0.0742
## sexFemale 0.095322 1.100013 1.228718 0.078 0.9382
## age:sexFemale -0.009689 0.990358 0.019414 -0.499 0.6177
##
## Likelihood ratio test=14.37 on 3 df, p=0.002441
## n= 228, number of events= 165
Todas las posibles interacciones entre age, sex y ph.ecog:
coxph(Surv(time, status) ~ age * sex * ph.ecog, data = datos)
## Call:
## coxph(formula = Surv(time, status) ~ age * sex * ph.ecog, data = datos)
##
## coef exp(coef) se(coef) z p
## age 0.055106 1.056653 0.026798 2.056 0.0397
## sexFemale -0.176416 0.838269 3.252224 -0.054 0.9567
## ph.ecogsintomático. 3.773425 43.528902 1.976268 1.909 0.0562
## age:sexFemale -0.004511 0.995499 0.051763 -0.087 0.9306
## age:ph.ecogsintomático. -0.052495 0.948859 0.030368 -1.729 0.0839
## sexFemale:ph.ecogsintomático. 0.151380 1.163439 3.634085 0.042 0.9668
## age:sexFemale:ph.ecogsintomático. -0.005490 0.994525 0.058147 -0.094 0.9248
##
## Likelihood ratio test=20.38 on 7 df, p=0.004799
## n= 176, number of events= 119
## (52 observations deleted due to missingness)
: se utiliza para especificar únicamente la
interacción entre variables en un modelo es- tadístico, sin incluir los
efectos principales de las variables involucradas entre sex, age y las
variables principales.coxph(Surv(time, status) ~ age + sex + age:sex, data = datos)
## Call:
## coxph(formula = Surv(time, status) ~ age + sex + age:sex, data = datos)
##
## coef exp(coef) se(coef) z p
## age 0.020343 1.020551 0.011395 1.785 0.0742
## sexFemale 0.095322 1.100013 1.228718 0.078 0.9382
## age:sexFemale -0.009689 0.990358 0.019414 -0.499 0.6177
##
## Likelihood ratio test=14.37 on 3 df, p=0.002441
## n= 228, number of events= 165
Modelo utilizando solo la interacción entre sex y age:
coxph(Surv(time, status) ~ age:sex, data = datos)
## Call:
## coxph(formula = Surv(time, status) ~ age:sex, data = datos)
##
## coef exp(coef) se(coef) z p
## age:sexMale 0.019821 1.020019 0.009191 2.157 0.031
## age:sexFemale 0.011624 1.011692 0.009537 1.219 0.223
##
## Likelihood ratio test=14.37 on 2 df, p=0.0007596
## n= 228, number of events= 165
^ en un modelo estadístico se utiliza para
incluir interacciones entre variables hasta el nivel indicado.Modelo utilizando las variables principales y sus interacciones dobles y triples de las variables age, meal.cal y sex.
coxph(Surv(time, status) ~ (age + meal.cal + sex)^3, data = datos)
## Call:
## coxph(formula = Surv(time, status) ~ (age + meal.cal + sex)^3,
## data = datos)
##
## coef exp(coef) se(coef) z p
## age 1.607e-02 1.016e+00 3.333e-02 0.482 0.630
## meal.cal -2.692e-04 9.997e-01 2.010e-03 -0.134 0.893
## sexFemale -8.997e-01 4.067e-01 3.190e+00 -0.282 0.778
## age:meal.cal 1.171e-06 1.000e+00 3.079e-05 0.038 0.970
## age:sexFemale 3.311e-03 1.003e+00 4.959e-02 0.067 0.947
## meal.cal:sexFemale 8.775e-04 1.001e+00 3.113e-03 0.282 0.778
## age:meal.cal:sexFemale -1.057e-05 1.000e+00 5.043e-05 -0.210 0.834
##
## Likelihood ratio test=11.04 on 7 df, p=0.1369
## n= 181, number of events= 134
## (47 observations deleted due to missingness)
Modelo utilizando las variables principales y las interacciones dobles de las variables age, meal.cal y ph.ecog.
coxph(Surv(time, status) ~ (age + meal.cal + ph.ecog)^2, data = datos)
## Call:
## coxph(formula = Surv(time, status) ~ (age + meal.cal + ph.ecog)^2,
## data = datos)
##
## coef exp(coef) se(coef) z p
## age 5.312e-02 1.055e+00 3.637e-02 1.461 0.144
## meal.cal -3.464e-04 9.997e-01 1.983e-03 -0.175 0.861
## ph.ecogsintomático. 1.763e+00 5.831e+00 1.982e+00 0.889 0.374
## age:meal.cal -5.646e-06 1.000e+00 2.955e-05 -0.191 0.848
## age:ph.ecogsintomático. -3.879e-02 9.620e-01 2.853e-02 -1.359 0.174
## meal.cal:ph.ecogsintomático. 9.362e-04 1.001e+00 6.787e-04 1.379 0.168
##
## Likelihood ratio test=8.17 on 6 df, p=0.2261
## n= 136, number of events= 94
## (92 observations deleted due to missingness)
De manera general se puede utilizar la función I( ) para crear nuevas variables y/o interacciones deseadas.
Los intervalos de confianza y las Pruebas de Significancia se realizan con la función summary() a un modelo previamente ajustado, esta función tiene los siguientes argumentos:
modelo <- coxph(Surv(time, status) ~ age:sex, data = datos)
summary(modelo)
## Call:
## coxph(formula = Surv(time, status) ~ age:sex, data = datos)
##
## n= 228, number of events= 165
##
## coef exp(coef) se(coef) z Pr(>|z|)
## age:sexMale 0.019821 1.020019 0.009191 2.157 0.031 *
## age:sexFemale 0.011624 1.011692 0.009537 1.219 0.223
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## exp(coef) exp(-coef) lower .95 upper .95
## age:sexMale 1.020 0.9804 1.002 1.039
## age:sexFemale 1.012 0.9884 0.993 1.031
##
## Concordance= 0.603 (se = 0.026 )
## Likelihood ratio test= 14.37 on 2 df, p=8e-04
## Wald test = 14.05 on 2 df, p=9e-04
## Score (logrank) test = 14.34 on 2 df, p=8e-04
Los resultados de la función coxph en R proporcionan una
tabla detallada que incluye los coeficientes estimados de \(e^{\beta_i}\), junto con sus respectivos
intervalos de confianza. Este enfoque ayuda a interpretar más
directamente los factores de riesgo en términos de riesgos
relativos.
Adicionalmente, se proporcionan estadísticos de Concordancia y \(R^2\), que son medidas de la calidad del ajuste del modelo. Estas métricas son útiles para evaluar qué tan bien el modelo predice los datos observados.
Los resultados también incluyen estadísticas de pruebas importantes para la validación del modelo:
Cada una de estas pruebas proporciona un valor de p-valor y los grados de libertad asociados, permitiendo determinar la significancia estadística de los hallazgos.
La comparación entre modelos de regresión se puede realizar
utilizando la función anova(), específicamente diseñada
para efectuar la prueba de Razón de Verosimilitud entre dos modelos
ajustados. Esta prueba es útil para determinar si la inclusión de
variables adicionales en un modelo mejora significativamente el
ajuste.
Argumentos de la función anova()
Los modelos ajustados que se desean comparar se pasan como argumentos a la función.
Salida de la función
La función anova() produce una tabla que incluye los
siguientes elementos para cada uno de los modelos comparados:
Ejemplo
modeloCompleto <- coxph(Surv(time, status) ~ age + sex, data = datos)
modeloReducido <- coxph(Surv(time, status) ~ age, data = datos)
anova(modeloCompleto, modeloReducido)
## Analysis of Deviance Table
## Cox model: response is Surv(time, status)
## Model 1: ~ age + sex
## Model 2: ~ age
## loglik Chisq Df Pr(>|Chi|)
## 1 -742.85
## 2 -747.79 9.8822 1 0.001669 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
La validación de los supuestos de proporcionalidad de riesgos en un modelo de regresión de Cox se lleva a cabo mediante el análisis de los residuos de Schoenfeld. Estos residuos son utilizados para examinar si las covariables interactúan con el tiempo de una manera que podría violar el supuesto de proporcionalidad. La función cox.zph() en R facilita esta validación realizando una prueba de correlación entre los residuos de Schoenfeld y alguna transformación del tiempo.
Argumentos de cox.zph(): - fit: Un objeto coxph resultante de ajustar un modelo de regresión de Cox. - transform: Define el tipo de transformación del tiempo a aplicar en el análisis. Los valores posibles incluyen “km” para la transformación Kaplan-Meier de los tiempos de falla, “rank” para el uso de rangos de los tiempos, “identity” que mantiene los tiempos sin cambios, o puede ser una función definida por el usuario que transforme los tiempos.
Salida de la función cox.zph():
La función produce una tabla que incluye los siguientes elementos para cada covariable en el modelo:
Ejemplo
modelo <- coxph(Surv(time, status) ~ log(age) * sex, data = datos)
riesgo <- cox.zph(modelo)
riesgo
## chisq df p
## log(age) 0.138 1 0.71
## sex 2.631 1 0.10
## log(age):sex 2.696 1 0.10
## GLOBAL 3.346 3 0.34
Para realizar una validación gráfica del supuesto de proporcionalidad de riesgos en un modelo de regresión de Cox, la función ggcoxzph() de la librería survminer es una herramienta efectiva. Esta función permite visualizar los residuos de Schoenfeld en contra del tiempo, facilitando la identificación de posibles violaciones del supuesto de proporcionalidad.
Uso de ggcoxzph():
La librería survminer está diseñada específicamente para facilitar la visualización de resultados de análisis de sobrevivencia, incluyendo las pruebas de proporcionalidad de riesgos.
Ejemplo
riesgo
## chisq df p
## log(age) 0.138 1 0.71
## sex 2.631 1 0.10
## log(age):sex 2.696 1 0.10
## GLOBAL 3.346 3 0.34
ggcoxzph(riesgo)
ggcoxzph(riesgo, var = c("log(age)", "sex"))
El análisis residual para modelos de regresión de Cox se puede
facilitar mediante la función ggcoxdiagnostics de la
librería survminer. Esta función proporciona gráficos de
diagnóstico útiles para evaluar la adecuación del modelo ajustado con
coxph. A continuación se describen los argumentos más
relevantes de la función ggcoxdiagnostics:
Argumentos de ggcoxdiagnostics:
coxph de la librería survival."martingale": Residuos de martingala."deviance": Residuos de desviación."score": Residuos de score."schoenfeld": Residuos de Schoenfeld."dfbeta": Residuos DFBETA."dfbetas": Residuos DFBETAS."scaledsch": Schoenfeld escalado."linear.predictions": Predicciones lineales."observation.id": Identificador de la observación."time": Tiempo.Ejemplo
modelo <- coxph(Surv(time, status) ~ log(age) , data = lung)
ggcoxdiagnostics(modelo, type = "schoenfeld", ox.scale = "time")
## Warning: `gather_()` was deprecated in tidyr 1.2.0.
## ℹ Please use `gather()` instead.
## ℹ The deprecated feature was likely used in the survminer package.
## Please report the issue at <https://github.com/kassambara/survminer/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `geom_smooth()` using formula = 'y ~ x'
ggcoxdiagnostics(modelo, type = "dfbetas", ox.scale = "observation.id",
title = "Residuales dfbetas",
subtitle = "dfbetas vs id", caption = "Análisis residual")
## `geom_smooth()` using formula = 'y ~ x'
Al utilizar la función ggcoxdiagnostics para el análisis de residuos en modelos de regresión de Cox, se puede encontrar que por defecto, esta gráfica los residuos para todas las covariables del modelo. Para obtener gráficos individuales por cada covariable o un subconjunto específico de covariables, se puede emplear una función adicional llamada ggcoxdiagnostics_var. Esta función permite filtrar y visualizar los residuos para covariables seleccionadas.
Argumentos de ggcoxdiagnostics_var:
*: Objeto ggplot generado con
ggcoxdiagnostics.Ejemplo
p <- ggcoxdiagnostics(modelo, type = "dfbetas", ox.scale = "observation.id",
title = "Residuales dfbetas", subtitle = "dfbetas vs id", caption = "Análisis residual")
p
## `geom_smooth()` using formula = 'y ~ x'
La función survfit se utiliza en el contexto de la
sobrevivencia para calcular la función de sobrevivencia pronosticada
basándose en un modelo de riesgos proporcionales de Cox ajustado
previamente con la función coxph. A continuación se
describen los argumentos principales de survfit:
Argumentos de survfit:
coxph.newdata."none",
"plain", "log" (predeterminado), y
"log-log".Salida de survfit:*
La salida incluye estimaciones de la función de sobrevivencia que son comparables a las obtenidas mediante el estimador de Kaplan-Meier y los métodos de Fleming-Harrington. Esto incluye:
conf.type.Ejemplo
(modelo <- coxph(Surv(time, status) ~ age + meal.cal, data = datos))
## Call:
## coxph(formula = Surv(time, status) ~ age + meal.cal, data = datos)
##
## coef exp(coef) se(coef) z p
## age 1.892e-02 1.019e+00 1.044e-02 1.813 0.0699
## meal.cal -3.217e-05 1.000e+00 2.349e-04 -0.137 0.8911
##
## Likelihood ratio test=3.67 on 2 df, p=0.1592
## n= 181, number of events= 134
## (47 observations deleted due to missingness)
datosnuevos <- data.frame(age = c(50, 60), meal.cal = c(1500, 2000)) #Datos a Estimar
datosnuevos
## age meal.cal
## 1 50 1500
## 2 60 2000
curva <- survfit(modelo, newdata = datosnuevos)
curva
## Call: survfit(formula = modelo, newdata = datosnuevos)
##
## n events median 0.95LCL 0.95UCL
## 1 181 134 361 291 558
## 2 181 134 329 239 574
Las curvas de sobrevivencia estimadas generadas por la función survfit en R son objetos del tipo Survfit. Estos objetos permiten realizar análisis adicionales, como la estimación de medias y cuantiles de las funciones de sobrevivencia. Se pueden utilizar las funciones print() y quantile() para extraer esta información.
print(curva, print.rmean = T)
## Call: survfit(formula = modelo, newdata = datosnuevos)
##
## n events rmean* se(rmean) median 0.95LCL 0.95UCL
## 1 181 134 436 31.8 361 291 558
## 2 181 134 389 25.2 329 239 574
## * restricted mean with upper limit = 1022
quantile(curva)
## $quantile
## 25 50 75
## 1 199 361 643
## 2 175 329 567
##
## $lower
## 25 50 75
## 1 156 291 477
## 2 118 239 390
##
## $upper
## 25 50 75
## 1 288 558 NA
## 2 301 574 NA
6.1 Graficar la Curva de Sobrevivencia.
La visualización de las curvas de sobrevivencia en R puede realizarse
eficazmente utilizando la función ggsurvplot de la librería
survminer. Esta función es una interfaz avanzada que
utiliza ggplot2 para la creación de gráficos de
sobrevivencia, ofreciendo una amplia gama de opciones para personalizar
la visualización. A continuación, se describen algunos de los parámetros
más importantes:
Parámetros de ggsurvplot:
survfit. Este
objeto contiene las estimaciones de la función de sobrevivencia que se
desean graficar."event": para mostrar los eventos acumulados."cumhaz": para el riesgo acumulado."pct": para representar la curva de sobrevivencia en
porcentaje.TRUE, permite la visualización de los
intervalos de confianza alrededor de las estimaciones de
sobrevivencia.(modelo <- coxph(Surv(time, status) ~ age + meal.cal, data = datos))
## Call:
## coxph(formula = Surv(time, status) ~ age + meal.cal, data = datos)
##
## coef exp(coef) se(coef) z p
## age 1.892e-02 1.019e+00 1.044e-02 1.813 0.0699
## meal.cal -3.217e-05 1.000e+00 2.349e-04 -0.137 0.8911
##
## Likelihood ratio test=3.67 on 2 df, p=0.1592
## n= 181, number of events= 134
## (47 observations deleted due to missingness)
datosnuevos <- data.frame(age = c(50, 60), meal.cal = c(1500, 2000)) #Datos a Estimar
curva <- survfit(modelo, newdata = datosnuevos, conf.type = "log-log")
ggsurvplot(fit = curva, data = datos, conf.int = T, title = "Curva de sobrevivencia",
xlab = "time", ylab = "Probabilidad de sobrevivencia",
legend.labs = c("age=50 y meal.cal=1500",
"age=60 y meal.cal=2000"), legend.title = "Grupos: ")
La estimación de riesgo base representa la particular predicción de la curva de sobrevivencia utilizando las covariables igual a 0.
(modelo <- coxph(Surv(time, status) ~ age + meal.cal, data = datos))
datosnuevo <- data.frame(age = 0, meal.cal = 0)
RiesgoBase <- survfit(modelo, datosnuevo)
summary(RiesgoBase)
cbind(Tiempo = RiesgoBase$time, RiesgoAcumulado = RiesgoBase$cumhaz)