Coeficientes dependentes do tempo em R - como fazê-lo?

17

Atualização : desculpe por outra atualização, mas encontrei algumas soluções possíveis com polinômios fracionários e o pacote de risco concorrente com o qual preciso de ajuda.


O problema

Não consigo encontrar uma maneira fácil de fazer uma análise de coeficiente dependente do tempo em R. Quero poder pegar o coeficiente de minhas variáveis ​​e transformá-lo em um coeficiente dependente de tempo (não variável) e, em seguida, plotar a variação contra o tempo:

βmy_variable=β0+β1t+β2t2...

Soluções possíveis

1) Dividindo o conjunto de dados

Analisei este exemplo (veja a parte 2 da sessão de laboratório), mas a criação de um conjunto de dados separado parece complicada, onerosa e computacionalmente pouco intuitiva ...

2) Modelos com classificação reduzida - o pacote coxvc

O pacote coxvc fornece uma maneira elegante de lidar com o problema - aqui está um manual . O problema é que o autor não está mais desenvolvendo o pacote (a última versão é desde 23/05/2007), após algumas conversas por e-mail, consegui que o pacote funcionasse, mas uma execução levou 5 horas no meu conjunto de dados (140 000 entradas) e fornece estimativas extremas no final do período. Você pode encontrar um pacote ligeiramente atualizado aqui - eu apenas atualizei a função plot.

Pode ser apenas uma questão de ajustes, mas como o software não fornece facilmente intervalos de confiança e o processo é tão demorado, agora estou procurando outras soluções.

3) O pacote timereg

O impressionante pacote timereg também aborda o problema, mas não tenho certeza de como usá-lo e não me fornece uma trama suave.

4) Modelo de tempo polinomial fracionário (FPT)

Encontrei a excelente dissertação de Anika Buchholz sobre "Avaliação dos efeitos de longo prazo de terapias e fatores prognósticos que variam no tempo", que faz um excelente trabalho cobrindo diferentes modelos. Ela conclui que o TPF proposto por Sauerbrei et al parece ser o mais apropriado para os coeficientes dependentes do tempo:

O FPT é muito bom na detecção de efeitos que variam no tempo, enquanto a abordagem Classificação Reduz resulta em modelos muito complexos, pois não inclui a seleção de efeitos que variam no tempo.

A pesquisa parece muito completa, mas está um pouco fora do meu alcance. Também estou me perguntando, já que ela trabalha com Sauerbrei. Parece bom e acho que a análise poderia ser feita com o pacote mfp, mas não sei como.

5) O pacote cmprsk

Eu estava pensando em fazer minha análise de risco concorrente, mas os cálculos foram demorados, então mudei para a regressão cox regular. O crr tem uma opção para covariáveis ​​dependentes do 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
....

Há o exemplo quadrático, mas não sou muito fiel ao local onde a hora realmente aparece e não tenho certeza de como exibi-la. Eu também olhei para o arquivo test.R, mas o exemplo é basicamente o mesmo ...

Meu código de exemplo

Aqui está um exemplo que eu uso para testar as diferentes possibilidades

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

O código resulta nos seguintes gráficos: Comparação de configurações diferentes para coxvc e dos gráficos coxvc e timecox . Acho que os resultados estão bons, mas acho que não vou conseguir explicar o gráfico da timecox - parece complexo ...

Minhas perguntas (atuais)

  • Como faço a análise do FPT em R?
  • Como uso a covariável de tempo no cmprsk?
  • Como plotar o resultado (de preferência com intervalos de confiança)?
Max Gordon
fonte
3
O exemplo no link é sobre covariáveis ​​variáveis ​​no tempo, não coeficientes variáveis ​​no tempo. Essas são coisas muito diferentes. Para obter parâmetros variáveis ​​no tempo, da maneira que você descreveu, use interações, ou seja, em vez do modelo , ajuste o modelo . Em R, as fórmulas teriam aparência e (também é possível escrever para a última). y=xβmyy=xβ0+xtβ1+xt2β2y~xy~x*(t+t^2)-ty~x+x:t+x:t^2
mpiktas
Pensei que a segunda parte: "2. Modele covariáveis ​​determinísticas e dependentes do tempo para verificar a suposição de PH" seria a parte que lida com a minha pergunta. Eu estava esperando fazer algo da fórmula que você descreve, mas quando tentei, recebi um erro ou uma variável de tempo separada ... Porém, obtive um valor p baixo para o tempo:
Max Gordon
@ max-gordon, sua variável de resposta é uma quantidade ou o tempo decorrido até a ocorrência de um par? Porque a maioria dos métodos que você cita são especificamente para dados de tempo até o evento.
F1r3br4nd
@ f1r3br4nd: É uma quantidade (Idade em meu estudo) em que o risco é proporcional, ou seja, varia ao longo do tempo no meu modelo de tempo até o evento. No final, eu decidi dividir em dois diferentes períodos de tempo, como eu não estava feliz fazendo um gráfico 3-D - que nunca passaram os revisores ...
Max Gordon
Há uma diferença entre preditores dependentes / variáveis ​​do tempo e interação do tempo. A maioria das variáveis ​​depende do tempo (o sexo é uma exceção). Se você tiver uma observação por pessoa, terá pouca ou nenhuma chance de realizar uma análise dependente do tempo / variável. O método de Anderson-Gill é o mais frequentemente usado para análise de sobrevivência dependente do tempo. A vantagem dos métodos dependentes do tempo é que os valores durante o acompanhamento podem ser mais preditivos de experiência de sobrevivência do que os valores basais. A segunda situação, preditores que interagem com o tempo, são simplesmente testes da suposição de PH.
Adam Robinsson

Respostas:

8

O @mpiktas chegou perto de oferecer um modelo viável, no entanto, o termo que precisa ser usado para o quadrático no tempo = t seria I(t^2)). Isso ocorre porque em R a interpretação da fórmula de "^" cria interações e não realiza exponenciação; portanto, a interação de "t" com "t" é apenas "t". (Isso não deve ser migrado para o SO com uma tag [r]?)

Para alternativas a esse processo, que me parece um tanto duvidoso para fins de inferência e que provavelmente se encaixa no seu interesse em usar as funções de suporte nos pacotes rms / Hmisc da Harrell, consulte "Estratégias de modelagem de regressão" da Harrell. Ele menciona (mas apenas de passagem, embora cite alguns de seus próprios artigos) a construção de ajustes de spline na escala de tempo para modelar riscos em forma de banheira. Seu capítulo sobre modelos de sobrevivência paramétricos descreve uma variedade de técnicas de plotagem para verificar pressupostos de riscos proporcionais e para examinar a linearidade dos efeitos estimados de riscos log na escala de tempo.

Editar: Uma opção adicional é usar coxpho parâmetro 's' tt 'descrito como uma "lista opcional de funções de transformação no tempo".

DWin
fonte
Concordo que isso provavelmente deve ser movido para a marca SO [r].
Zach
+1 em sua resposta, eu não sabia que seria uma resposta tão difícil. Parece um problema comum, talvez a pergunta seja mais uma questão de codificação e você possa estar certo sobre SO ser uma escolha melhor. Eu tentei sua fórmula, parece que vf + I (vf log (time)) tem um ajuste excelente, tentei apenas vf time e vf * time ^ 2, mas o log deu por tarifa o menor valor p. Tentei executá-lo com a função CPH () para obter o AIC mas deu um erro :( Você tem alguma idéia de como fazer um enredo sobre a estimativa?
Max Gordon
Eu pensei que, check <- cox.zph(fit1); print(check); plot(check, resid=F)como na sua configuração, fornecemos gráficos informativos do tempo "efeito". Você quis dizer cph (), que é do pacote rms ou coxph, da sobrevivência?
Dwin
Sim, os resíduos de Schoenfeld dão uma boa idéia da variação de tempo, mas acho que as pessoas podem ter dificuldade em entender. O gráfico fornece, como eu o entendo, a variação residual não explicada pelo meu modelo. Gostaria de um gráfico em que eu tenha o efeito variável completo no eixo y e o tempo no eixo x, acredito que isso seria mais fácil de interpretar, pois você não precisa olhar para a tabela nem para o gráfico para obter o perigo em um ponto específico no tempo ... Sim eu quis dizer CPH () e não a coxph (), uma vez que não funciona com o AIC ()
Max Gordon
Também estou um pouco confuso com o motivo de ter encontrado todos os métodos complexos descritos na minha pergunta, enquanto esse I (variável * tempo) parece muito direto e intuitivo - como não estatístico, estou pensando - o que perdi ?
Max Gordon
5

Alterei a resposta para isso, pois nem as respostas do @ DWin nem do @ Zach respondem totalmente a como modelar coeficientes variáveis ​​no tempo. Eu escrevi recentemente um post sobre isso. Aqui está a essência disso.

O conceito central no modelo de regressão de Cox é a função de risco , . É definido como:h(t)

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

Onde é o risco de ocorrer um evento a qualquer momento, enquanto é a probabilidade de sobreviver a essa tarifa. O número é, portanto, uma fração com um intervalo teórico de a .f(t)S(t)0

Uma característica interessante da função de risco é que podemos incluir observações em outros momentos além dotime0S(t)

Ao permitir que os sujeitos entrem em outros momentos, devemos alterar Survde de Surv(time, status)para Surv(start_time, end_time, status). Enquanto o end_timeestá fortemente correlacionado com o resultado, start_timeagora está disponível como um termo de interação (como sugerido nas sugestões originais). Em um ambiente regular, o valor start_timeé 0, exceto em alguns assuntos que aparecem mais tarde, mas, como dividimos cada observação em vários períodos, de repente temos muitos horários de início diferentes de zero. A única diferença é que cada observação ocorre várias vezes, onde todas, exceto a última, têm a opção de um resultado não censurado.

Divisão de tempo na prática

Acabei de publicar no CRAN o pacote Greg que facilita essa divisão do tempo . Primeiro começamos com algumas observações 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 isso graficamente com * sendo um indicador de evento:

insira a descrição da imagem aqui

Se aplicarmos o timeSplitterseguinte:

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

Temos o seguinte:

insira a descrição da imagem aqui

Como você pode ver, cada objeto foi dividido em vários eventos, nos quais o último período contém o status real do evento. Isso nos permite criar modelos que têm :termos simples de interação (não use o *que ele expande time + var + time:vare não estamos interessados ​​no tempo em si). Não há necessidade de usar a I()função, embora se você deseja verificar a não linearidade com o tempo, muitas vezes crio uma variável de interação com o tempo separada à qual adiciono um spline e exibo usando rms::contrast. De qualquer forma, sua chamada de regressão agora deve ficar assim:

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

Usando a ttfunção do pacote de sobrevivência

Também existe uma maneira de modelar coeficientes dependentes do tempo diretamente no pacote de sobrevivência usando a ttfunção O Prof. Therneau fornece uma introdução completa ao assunto em sua vinheta . Infelizmente, em grandes conjuntos de dados, isso é difícil de executar devido a limitações de memória. Parece que a ttfunção divide o tempo em partes muito finas, gerando no processo uma enorme matriz.

Max Gordon
fonte
2

Você pode usar a função apply.rolling no PerformanceAnalytics para executar uma regressão linear através de uma janela contínua, o que permitirá que seus coeficientes variem ao longo do tempo.

Por exemplo:

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

Isso funciona com outras funções também.

Zach
fonte
Obrigado por sua resposta, acho que uma janela de tempo em movimento deve funcionar tão bem quanto minhas abordagens. Porém, não consigo executar o seu exemplo. Você poderia dar um exemplo com base no meu exemplo sTRACE para que eu saiba exatamente como implementá-lo?
Max Gordon