Coefficienti dipendenti dal tempo in R - come si fa?


17

Aggiornamento : mi scuso per un altro aggiornamento, ma ho trovato alcune possibili soluzioni con polinomi frazionari e il pacchetto di rischi della concorrenza di cui ho bisogno di aiuto.


Il problema

Non riesco a trovare un modo semplice per fare un'analisi del coefficiente dipendente dal tempo è in R. Voglio essere in grado di prendere il mio coefficiente di variabili e farlo in un coefficiente dipendente dal tempo (non variabile) e quindi tracciare la variazione rispetto al tempo:

βmy_vun'rioun'Ble=β0+β1*t+β2*t2...

Possibili soluzioni

1) Suddivisione del set di dati

Ho visto questo esempio (vedi parte 2 della sessione di laboratorio) ma la creazione di un set di dati separato sembra complicata, computazionalmente costosa e non molto intuitiva ...

2) Modelli a rango ridotto - Il pacchetto coxvc

Il pacchetto coxvc fornisce un modo elegante per affrontare il problema: ecco un manuale . Il problema è che l'autore non sta più sviluppando il pacchetto (l'ultima versione è dal 23/05/2007), dopo alcune conversazioni via e-mail ho fatto funzionare il pacchetto ma una corsa ha richiesto 5 ore sul mio set di dati (140.000 voci) e fornisce stime estreme alla fine del periodo. Puoi trovare un pacchetto leggermente aggiornato qui - ho principalmente aggiornato la funzione di trama.

Potrebbe essere solo una questione di messa a punto, ma poiché il software non fornisce facilmente intervalli di confidenza e il processo richiede così tanto tempo, sto cercando ora altre soluzioni.

3) Il pacchetto timereg

Anche l'impressionante pacchetto timereg risolve il problema, ma non sono sicuro di come usarlo e non mi dà una trama fluida.

4) Modello di tempo polinomiale frazionario (FPT)

Ho trovato l'eccellente tesi di Anika Buchholz su "Valutazione degli effetti a lungo termine di terapie e fattori prognostici variabili nel tempo" che svolge un eccellente lavoro su diversi modelli. Conclude che l'FPT proposto da Sauerbrei et al sembra essere il più appropriato per i coefficienti dipendenti dal tempo:

FPT è molto bravo a rilevare effetti che variano nel tempo, mentre l'approccio del Rango Ridotto produce modelli troppo complessi, poiché non include la selezione di effetti che variano nel tempo.

La ricerca sembra molto completa ma per me è leggermente fuori portata. Mi chiedo anche un po 'dal momento che lei lavora con Sauerbrei. Sembra comunque sano e suppongo che l'analisi potrebbe essere fatta con il pacchetto mfp ma non sono sicuro di come.

5) Il pacchetto cmprsk

Ho pensato di fare la mia analisi del rischio concorrente, ma i calcoli sono stati dispendiosi in termini di tempo, quindi sono passato alla regressione normale del cox. Il crr ha anche un'opzione per le covariate dipendenti dal tempo:

....
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
....

C'è un esempio quadratico, ma non seguo esattamente dove appare il tempo e non sono sicuro di come visualizzarlo. Ho anche guardato il file test.R ma l'esempio è sostanzialmente lo stesso ...

Il mio codice di esempio

Ecco un esempio che utilizzo per testare le diverse possibilità

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))

I risultati di codice in questi grafici: Confronto tra diverse impostazioni per coxvc e della coxvc e le timecox trame. Immagino che i risultati siano ok ma non credo che sarò in grado di spiegare il grafico di timecox - sembra complesso ...

Le mie (attuali) domande

  • Come faccio l'analisi FPT in R?
  • Come posso usare la covariata del tempo in cmprsk?
  • Come posso tracciare il risultato (preferibilmente con intervalli di confidenza)?

3
y=Xβmyy=Xβ0+Xtβ1+Xt2β2y~xy~x*(t+t^2)-ty~x+x:t+x:t^2

Ho pensato che la seconda parte: "2. Covariate dipendenti dal tempo deterministiche del modello per controllare l'assunzione di PH" sarebbe la parte che affronta la mia domanda. Speravo di fare qualcosa della formula che descrivi, ma quando l'ho provato ho avuto un errore o una variabile temporale separata ... Ho avuto un valore p basso per il tempo però :-D
Max Gordon

@ max-gordon, la tua variabile di risposta è una quantità o il tempo è trascorso fino a quando si verifica un errore? Perché la maggior parte dei metodi citati sono specifici per i dati time-to-event.
f1r3br4nd

@ f1r3br4nd: è una quantità (Età nel mio studio) in cui il rischio non è proporzionale, cioè varia nel tempo nel mio modello time-to-event. Alla fine ho deciso di dividere in due diversi intervalli di tempo poiché non ero elettrizzato facendo un grafico 3D - che non avrebbe mai superato i revisori ...
Max Gordon,

C'è una differenza tra predittori dipendenti dal tempo / variabili e interazione temporale. La maggior parte delle variabili dipende dal tempo (il sesso è un'eccezione). Se hai un'osservazione per persona, avrai poche o nessuna possibilità di eseguire un'analisi dipendente dal tempo / variabile. Il metodo di Anderson-Gill è il metodo più frequentemente utilizzato per l'analisi della sopravvivenza dipendente dal tempo. Il vantaggio dei metodi dipendenti dal tempo è che i valori durante il follow-up potrebbero essere più prevedibili dell'esperienza di sopravvivenza rispetto ai valori basali. La seconda situazione, i predittori che interagiscono nel tempo sono semplicemente test dell'assunzione di PH.
Adam Robinsson,

Risposte:


8

@mpiktas si avvicinò offrendo un modello fattibile, tuttavia il termine che deve essere usato per la quadratica in tempo = t sarebbe I(t^2)). Questo perché in R l'interpretazione della formula di "^" crea interazioni e non esegue esponenziazione, quindi l'interazione di "t" con "t" è solo "t". (Non dovrebbe essere migrato su SO con un tag [r]?)

Per alternative a questo processo, che mi sembra alquanto dubbio per scopi di inferenza, e che probabilmente soddisfa il tuo interesse nell'uso delle funzioni di supporto nei pacchetti rms / Hmisc di Harrell, vedi le "Strategie di modellizzazione della regressione" di Harrell. Menziona (ma solo di sfuggita, sebbene citi alcuni dei suoi documenti), costruendo una spline adatta alla scala temporale per modellare i rischi a forma di vasca. Il suo capitolo sui modelli di sopravvivenza parametrica descrive una varietà di tecniche di tracciamento per il controllo delle ipotesi di rischi proporzionali e per l'esame della linearità degli effetti stimati del rischio di log sulla scala temporale.

Modifica: un'opzione aggiuntiva consiste nell'utilizzare coxphil parametro 't' t 'descritto come un "elenco opzionale di funzioni di trasformazione del tempo".


Sono d'accordo che questo dovrebbe probabilmente essere spostato nel tag SO [r].
Zach,

+1 per la tua risposta, non sapevo che sarebbe stata una risposta così difficile. Sembra un problema comune, forse la domanda è più una questione di codifica che e potresti avere ragione sul fatto che SO sia una scelta migliore. Ho provato la tua formula sembra che vf + I (vf log (time)) abbia una misura eccellente, ho provato solo vf time e vf * time ^ 2 ma il log ha dato per tariffa il valore p più basso. Ho provato a eseguirlo con la funzione cph () per ottenere l'AIC ma mi ha dato un errore :( Hai idea di come fare un diagramma sul preventivo?
Max Gordon,

Pensavo che, check <- cox.zph(fit1); print(check); plot(check, resid=F)come nel tuo set up, fornissi trame informative del "effetto" temporale. Intendevi cph () che proviene dal pacchetto rms o coxph da sopravvivenza?
DWin,

Sì, i residui di Schoenfeld danno una buona idea della variazione del tempo, ma penso che le persone potrebbero avere difficoltà a capirlo. La trama dà come ho capito la variazione residua non spiegata dal mio modello. Vorrei però una trama in cui ho l'effetto variabile completo sull'asse ye il tempo sull'asse x, credo che questo sarebbe più facile da interpretare poiché non devi guardare sia la tabella che la trama per ottenere il rischio in un determinato momento ... Sì, intendevo cph () e non il coxph () poiché quello non funziona con l'AIC ()
Max Gordon,

Sono anche un po 'confuso sul perché ho trovato tutti i metodi complessi descritti nella mia domanda, mentre questo io (tempo variabile *) sembra molto semplice e intuitivo - come sto pensando di non statistico - cosa mi sono perso ?
Max Gordon,

5

Ho cambiato la risposta a questo dato che né le risposte di @ DWin né di @ Zach rispondono pienamente a come modellare i coefficienti variabili nel tempo. Di recente ho scritto un post su questo. Ecco il senso.

h(t)

h(t)=f(t)S(t)

f(t)S(t)0

tiome0S(t)

Quando si consentono ai soggetti di accedere ad altri punti temporali, è necessario modificare il Survda Surv(time, status)a Surv(start_time, end_time, status). Mentre end_timeè fortemente correlato con il risultato, start_timeè ora disponibile come termine di interazione (come suggerito nei suggerimenti originali). In un'impostazione regolare start_timeè 0 tranne per alcuni soggetti che compaiono in seguito ma se dividiamo ogni osservazione in diversi periodi improvvisamente abbiamo molti orari di inizio diversi da zero. L'unica differenza è che ogni osservazione si verifica più volte in cui tutte, tranne l'ultima, hanno l'opzione di un risultato non censurato.

Praticare il tempo in pratica

Ho appena pubblicato su CRAN il pacchetto Greg che semplifica questa suddivisione del tempo . Innanzitutto iniziamo con alcune osservazioni teoriche:

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"))
)

Possiamo mostrarlo graficamente con * che è un indicatore di evento:

inserisci qui la descrizione dell'immagine

Se applichiamo timeSplitterquanto segue:

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"))

Otteniamo quanto segue:

inserisci qui la descrizione dell'immagine

Come puoi vedere, ogni oggetto è stato suddiviso in più eventi in cui l'ultimo intervallo di tempo contiene lo stato effettivo dell'evento. Questo ci consente ora di costruire modelli che hanno :termini di interazione semplici (non usare *come si espande time + var + time:vare non siamo interessati al tempo in sé). Non è necessario utilizzare la I()funzione, sebbene se si desidera verificare la non linearità con il tempo, spesso creo una variabile di interazione temporale separata a cui aggiungo una spline e che quindi visualizzo utilizzando rms::contrast. Ad ogni modo, la tua chiamata di regressione dovrebbe apparire così:

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

Usando la ttfunzione del pacchetto di sopravvivenza

C'è anche un modo per modellare i coefficienti dipendenti dal tempo direttamente nel pacchetto di sopravvivenza usando la ttfunzione. Il Prof. Therneau fornisce un'introduzione approfondita all'argomento nella sua vignetta . Sfortunatamente in grandi set di dati questo è difficile da fare a causa delle limitazioni della memoria. Sembra che la ttfunzione divida il tempo in pezzi molto fini generando nel processo una matrice enorme.


2

È possibile utilizzare la funzione apply.rolling in PerformanceAnalytics per eseguire una regressione lineare attraverso una finestra , che consentirà ai coefficienti di variare nel tempo.

Per esempio:

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

Funziona anche con altre funzioni.


Grazie per la tua risposta, immagino che una finestra temporale mobile dovrebbe funzionare esattamente come i miei approcci. Non riesco a far funzionare il tuo esempio, potresti per favore dare un esempio basato sul mio esempio sTRACE in modo che io sappia esattamente come implementarlo?
Max Gordon,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.