Coeficientes dependientes del tiempo en R: ¿cómo hacerlo?

17

Actualización : Perdón por otra actualización, pero he encontrado algunas posibles soluciones con polinomios fraccionales y el paquete de riesgos de la competencia con el que necesito ayuda.


El problema

No puedo encontrar una manera fácil de hacer un análisis de coeficiente dependiente del tiempo en R. Quiero poder tomar el coeficiente de mis variables y hacerlo en un coeficiente dependiente del tiempo (no variable) y luego trazar la variación en función del tiempo:

βmetroy_ _vunryounsilmi=β0 0+β1t+β2t2...

Soluciones posibles

1) División del conjunto de datos

He mirado este ejemplo (Se parte 2 de la sesión de laboratorio) pero la creación de un conjunto de datos separado parece complicado, computacionalmente costoso y no muy intuitivo ...

2) Modelos de rango reducido: el paquete coxvc

El paquete coxvc proporciona una forma elegante de abordar el problema: aquí hay un manual . El problema es que el autor ya no está desarrollando el paquete (la última versión es desde el 23/05/2007), después de una conversación por correo electrónico he conseguido que el paquete funcione pero una ejecución tardó 5 horas en mi conjunto de datos (140 000 entradas) y proporciona estimaciones extremas al final del período. Puede encontrar un paquete ligeramente actualizado aquí : en su mayoría, acabo de actualizar la función de trazado.

Puede ser solo una cuestión de ajustes, pero dado que el software no proporciona fácilmente intervalos de confianza y el proceso lleva mucho tiempo, estoy buscando otras soluciones en este momento.

3) El paquete timereg

El impresionante paquete timereg también aborda el problema, pero no estoy seguro de cómo usarlo y no me da una trama fluida.

4) Modelo de tiempo fraccional polinómico (FPT)

Encontré la excelente disertación de Anika Buchholz sobre "Evaluación de los efectos a largo plazo de las terapias y los factores pronósticos a largo plazo" que hace un excelente trabajo cubriendo diferentes modelos. Ella concluye que el FPT propuesto por Sauerbrei et al. Parece ser el más apropiado para los coeficientes dependientes del tiempo:

FPT es muy bueno para detectar efectos que varían en el tiempo, mientras que el enfoque de Rango reducido da como resultado modelos demasiado complejos, ya que no incluye la selección de efectos que varían en el tiempo.

La investigación parece muy completa, pero está un poco fuera de mi alcance. También me pregunto un poco ya que ella trabaja con Sauerbrei. Sin embargo, parece sólido y supongo que el análisis podría hacerse con el paquete mfp, pero no estoy seguro de cómo.

5) El paquete cmprsk

He estado pensando en hacer mi análisis de riesgo de la competencia, pero los cálculos han llevado mucho tiempo, así que cambié a la regresión de Cox regular. El crr tiene una opción para las covariables dependientes del tiempo:

....
cov2        matrix of covariates that will be multiplied 
            by functions of time; if used, often these 
            covariates would also appear in cov1 to give 
            a prop hazards effect plus a time interaction
....

Existe el ejemplo cuadrático, pero no entiendo exactamente dónde aparece el tiempo y no estoy seguro de cómo mostrarlo. También he mirado el archivo test.R pero el ejemplo allí es básicamente el mismo ...

Mi código de ejemplo

Aquí hay un ejemplo que uso para probar las diferentes posibilidades

library("survival")
library("timereg")
data(sTRACE)

# Basic cox regression    
surv <- with(sTRACE, Surv(time/365,status==9))
fit1 <- coxph(surv~age+sex+diabetes+chf+vf, data=sTRACE)
check <- cox.zph(fit1)
print(check)
plot(check, resid=F)
# vf seems to be the most time varying

######################################
# Do the analysis with the code from #
# the example that I've found        #
######################################

# Split the dataset according to the splitSurv() from prof. Wesley O. Johnson
# http://anson.ucdavis.edu/~johnson/st222/lab8/splitSurv.ssc
new_split_dataset = splitSuv(sTRACE$time/365, sTRACE$status==9, sTRACE[, grep("(age|sex|diabetes|chf|vf)", names(sTRACE))])

surv2 <- with(new_split_dataset, Surv(start, stop, event))
fit2 <- coxph(surv2~age+sex+diabetes+chf+I(pspline(stop)*vf), data=new_split_dataset)
print(fit2)

######################################
# Do the analysis by just straifying #
######################################
fit3 <- coxph(surv~age+sex+diabetes+chf+strata(vf), data=sTRACE)
print(fit3)

# High computational cost!
# The price for 259 events
sum((sTRACE$status==9)*1)
# ~240 times larger dataset!
NROW(new_split_dataset)/NROW(sTRACE)

########################################
# Do the analysis with the coxvc and   #
# the timecox from the timereg library #
########################################
Ft_1 <- cbind(rep(1,nrow(sTRACE)),bs(sTRACE$time/365,df=3))
fit_coxvc1 <- coxvc(surv~vf+sex, Ft_1, rank=2, data=sTRACE)

fit_coxvc2 <- coxvc(surv~vf+sex, Ft_1, rank=1, data=sTRACE)

Ft_3 <- cbind(rep(1,nrow(sTRACE)),bs(sTRACE$time/365,df=5))
fit_coxvc3 <- coxvc(surv~vf+sex, Ft_3, rank=2, data=sTRACE)

layout(matrix(1:3, ncol=1))
my_plotcoxvc <- function(fit, fun="effects"){
    plotcoxvc(fit,fun=fun,xlab='time in years', ylim=c(-1,1), legend_x=.010)
    abline(0,0, lty=2, col=rgb(.5,.5,.5,.5))
    title(paste("B-spline =", NCOL(fit$Ftime)-1, "df and rank =", fit$rank))
}
my_plotcoxvc(fit_coxvc1)
my_plotcoxvc(fit_coxvc2)
my_plotcoxvc(fit_coxvc3)

# Next group
my_plotcoxvc(fit_coxvc1)

fit_timecox1<-timecox(surv~sex + vf, data=sTRACE)
plot(fit_timecox1, xlab="time in years", specific.comps=c(2,3))

El código da como resultado estos gráficos: Comparación de diferentes configuraciones para coxvc y de los gráficos de coxvc y timecox . Supongo que los resultados están bien, pero no creo que pueda explicar el gráfico de timecox, parece complejo ...

Mis preguntas (actuales)

  • ¿Cómo hago el análisis FPT en R?
  • ¿Cómo uso la covariable de tiempo en cmprsk?
  • ¿Cómo trazo el resultado (preferiblemente con intervalos de confianza)?
Max Gordon
fuente
3
y=Xβmetroyy=Xβ0 0+Xtβ1+Xt2β2y~xy~x*(t+t^2)-ty~x+x:t+x:t^2
Pensé que la segunda parte: "2. Modelo de covariables deterministas dependientes del tiempo para verificar el supuesto de PH" sería la parte que trata con mi pregunta. Tenía la esperanza de hacer algo de la fórmula que usted describe, pero cuando lo probé recibí un error o una variable de tiempo separada ... Sin embargo, obtuve un valor p bajo por tiempo :-D
Max Gordon
@ max-gordon, ¿su variable de respuesta es una cantidad o el tiempo transcurrido hasta que ocurra un par? Porque la mayoría de los métodos que cita son específicamente para datos de tiempo hasta el evento.
f1r3br4nd
@ f1r3br4nd: es una cantidad (Edad en mi estudio) donde el peligro no es proporcional, es decir, varía con el tiempo en mi modelo de tiempo hasta el evento. Al final decidí dividirme en dos marcos de tiempo diferentes, ya que no me entusiasmó hacer un gráfico tridimensional, que nunca hubiera pasado los revisores ...
Max Gordon
Hay una diferencia entre los predictores dependientes / variables del tiempo y la interacción del tiempo. La mayoría de las variables dependen del tiempo (el sexo es una excepción). Si tiene una observación por persona, tendrá poca o ninguna posibilidad de realizar un análisis dependiente del tiempo / variable. El método de Anderson-Gill es el más utilizado para el análisis de supervivencia dependiente del tiempo. La ventaja de los métodos dependientes del tiempo es que los valores durante el seguimiento podrían ser más predictivos de la experiencia de supervivencia que los valores iniciales. La segunda situación, los predictores que interactúan en el tiempo son simplemente pruebas de la suposición de PH.
Adam Robinsson

Respuestas:

8

@mpiktas estuvo cerca de ofrecer un modelo factible, sin embargo, el término que debe usarse para la cuadrática en el tiempo = t sería I(t^2)). Esto es así porque en R la interpretación de la fórmula de "^" crea interacciones y no realiza exponenciación, por lo que la interacción de "t" con "t" es simplemente "t". (¿No debería migrarse esto a SO con una etiqueta [r]?)

Para alternativas a este proceso, que me parece dudoso para fines de inferencia, y uno que probablemente se ajuste a su interés en usar las funciones de apoyo en los paquetes rms / Hmisc de Harrell, consulte "Estrategias de modelado de regresión" de Harrell. Menciona (pero solo de pasada, aunque cita algunos de sus propios documentos) la construcción de splines ajustados a la escala de tiempo para modelar peligros en forma de bañera. Su capítulo sobre modelos de supervivencia paramétricos describe una variedad de técnicas de trazado para verificar los supuestos de riesgos proporcionales y para examinar la linealidad de los efectos estimados de riesgo logarítmico en la escala de tiempo.

Editar: una opción adicional es usar coxphel parámetro 's' tt 'descrito como una "lista opcional de funciones de transformación de tiempo".

DWin
fuente
Estoy de acuerdo en que esto probablemente debería trasladarse a la etiqueta SO [r].
Zach
+1 por su respuesta, no sabía que sería una respuesta tan difícil. Parece un problema común, tal vez la pregunta es más una cuestión de codificación que, y es posible que tenga razón acerca de que SO sea una mejor opción. Probé su fórmula, parece que vf + I (vf log (time)) tiene un ajuste excelente, probé solo vf time y vf * time ^ 2 pero el registro dio por tarifa el valor p más bajo. Traté de ejecutarlo con la función cph () para obtener el AIC pero me dio un error :( ¿Tienes alguna idea de cómo hacer un gráfico en la estimación?
Max Gordon
Pensé que check <- cox.zph(fit1); print(check); plot(check, resid=F)como en su configuración dio parcelas informativas del tiempo "efecto". ¿Quiso decir cph () que es del paquete rms o coxph de supervivencia?
DWin
Sí, los residuos de Schoenfeld dan una buena idea de la variación de tiempo, pero creo que la gente podría tener dificultades para entenderlo. La trama da, según tengo entendido, la variación residual no explicada por mi modelo. A pesar de que quisiera un diagrama donde tengo el efecto variable completo en el eje yy el tiempo en el eje x, creo que esto sería más fácil de interpretar ya que no tienes que mirar tanto la tabla como el diagrama para obtener el peligro en un punto específico en el tiempo ... Sí, quise decir cph () y no el coxph () ya que ese no funciona con el AIC ()
Max Gordon
También estoy un poco confundido sobre por qué he encontrado todos los métodos complejos descritos en mi pregunta, mientras que esto (variable * tiempo) parece muy sencillo e intuitivo, como no estadístico, estoy pensando, ¿qué me he perdido? ?
Max Gordon
5

He cambiado la respuesta a esto, ya que ni las respuestas de @ DWin ni las de @ Zach responden completamente a cómo modelar coeficientes que varían en el tiempo. Recientemente escribí una publicación sobre esto. Aquí está la esencia de esto.

h(t)

h(t)=F(t)S(t)

F(t)S(t)0 0

tyometromi0 0S(t)

Al permitir que los sujetos ingresen en otros puntos de tiempo, debemos cambiar el Survde Surv(time, status)a Surv(start_time, end_time, status). Si bien end_timeestá fuertemente correlacionado con el resultado, start_timeahora está disponible como un término de interacción (tal como se insinuó en las sugerencias originales). En un entorno regular, el valor start_timees 0, excepto por unos pocos temas que aparecen más tarde, pero si dividimos cada observación en varios períodos, de repente tenemos muchas horas de inicio que no son cero. La única diferencia es que cada observación se produce varias veces donde todas, excepto la última observación, tienen la opción de un resultado no censurado.

Tiempo dividido en la práctica

Acabo de publicar en CRAN el paquete Greg que hace que esta división de tiempo sea fácil. Primero comenzamos con algunas observaciones teóricas:

library(Greg)
test_data <- data.frame(
  id = 1:4,
  time = c(4, 3.5, 1, 5),
  event = c("censored", "dead", "alive", "dead"),
  age = c(62.2, 55.3, 73.7, 46.3),
  date = as.Date(
    c("2003-01-01", 
      "2010-04-01", 
      "2013-09-20",
      "2002-02-23"))
)

Podemos mostrar esto gráficamente con * ser un indicador de evento:

ingrese la descripción de la imagen aquí

Si aplicamos lo timeSplittersiguiente:

library(dplyr)
split_data <- 
  test_data %>% 
  select(id, event, time, age, date) %>% 
  timeSplitter(by = 2, # The time that we want to split by
               event_var = "event",
               time_var = "time",
               event_start_status = "alive",
               time_related_vars = c("age", "date"))

Obtenemos lo siguiente:

ingrese la descripción de la imagen aquí

Como puede ver, cada objeto se ha dividido en múltiples eventos donde el último intervalo de tiempo contiene el estado real del evento. Esto nos permite ahora construir modelos que tienen :términos de interacción simples (no use el *ya que esto se expande time + var + time:vary no estamos interesados ​​en el tiempo per se). No es necesario usar la I()función, aunque si desea verificar la no linealidad con el tiempo, a menudo creo una variable de interacción de tiempo separada a la que agrego una spline y luego la visualizo usando rms::contrast. De todos modos, su llamada de regresión ahora debería verse así:

coxp(Surv(start_time, end_time, event) ~ var1 + var2 + var2:time, 
     data = time_split_data)

Usando la ttfunción del paquete de supervivencia

También hay una manera de modelar coeficientes dependientes del tiempo directamente en el paquete de supervivencia utilizando la ttfunción. El Prof. Therneau ofrece una introducción completa al tema en su viñeta . Desafortunadamente, en grandes conjuntos de datos esto es difícil de hacer debido a las limitaciones de memoria. Parece que la ttfunción divide el tiempo en piezas muy finas generando en el proceso una matriz enorme.

Max Gordon
fuente
2

Puede usar la función apply.rolling en PerformanceAnalytics para ejecutar una regresión lineal a través de una ventana móvil, lo que permitirá que sus coeficientes varíen con el tiempo.

Por ejemplo:

library(PerformanceAnalytics)
library(quantmod)
getSymbols(c('AAPL','SPY'), from='01-01-1900')
chart.RollingRegression(Cl(AAPL),Cl(SPY), width=252, attribute='Beta')
#Note: Alpha=y-intercept, Beta=regression coeffient

Esto funciona con otras funciones también.

Zach
fuente
Gracias por su respuesta, supongo que una ventana de tiempo en movimiento debería funcionar tan bien como mis enfoques. Sin embargo, no puedo ejecutar su ejemplo, ¿podría dar un ejemplo basado en mi ejemplo sTRACE para que sepa exactamente cómo implementarlo?
Max Gordon