Стратифицированный лог-ранговый тест в R для подсчета данных формы процесса?

avatar
neal
1 апреля 2019 в 16:55
852
1
3

Предпосылки : через полгода наблюдения в течение 4 лет пациенты могут переключиться на другую группу лекарств. Чтобы учесть это, я преобразовал данные о выживаемости в форму процесса подсчета. Я хочу сравнить кривые выживаемости для групп лекарств A, B и C. Я использую расширенную модель Кокса, но хочу провести попарные сравнения каждой функции риска или провести стратифицированные лог-ранговые тесты. pairwise_survdiff выдает ошибку из-за формы моих данных, я думаю.

Пример данных :

x<-data.frame(tstart=rep(seq(0,18,6),3),tstop=rep(seq(6,24,6),3), rx = rep(c("A","B","C"),4), death=c(rep(0,11),1))
x

Проблема :

При использовании survdiff в пакете survival,

survdiff(Surv(tstart,tstop,death) ~ rx, data = x)

Я получаю сообщение об ошибке:

Error in survdiff(Surv(tstart, tstop, death) ~ rx, data = x) : 
  Right censored data only

Я думаю, что это связано с формой процесса подсчета, поскольку я не могу найти в Интернете пример, в котором сравниваются кривые выживаемости для изменяющихся во времени ковариат.

Вопрос : есть ли быстрое решение этой проблемы? Или есть альтернативный пакет / функция с такой же универсальностью для сравнения кривых выживаемости, а именно с использованием разных методов? Как я могу реализовать стратифицированные тесты ранжирования журнала с использованием survidff для подсчета данных формы процесса?

ПРИМЕЧАНИЕ : это было помечено как известная проблема в пакете Survminer, см. Проблему с github здесь, но обновление Survminer не решило мою проблему, и при использовании одного временного интервала tstop-tstart не сработает. правильно, так как это оставит, например многократные записи через 6 месяцев, а не за пределы фактического интервала риска.

Источник
adibender
1 апреля 2019 в 17:26
0

Концептуально проблема в том, что когда у вас есть зависящие от времени ковариаты, у вас может быть большое количество потенциальных парных сравнений: A, A, B, C, против A, B, C, A против .... хотите сравнения A, A, A, A с B, B, B, B и C, C, C, C, но в этих профилях лечения нет ничего особенного, и если эти профили лечения не отображаются в ваших данных, эти конкретные сравнения были бы скорее гипотетическими. Может быть более полезно подобрать модель и провести многократное сравнение оценочных коэффициентов для каждой пары эффектов лечения?

neal
1 апреля 2019 в 17:36
0

Понятно, спасибо за ответ. Будет ли реализация этого соответствовать разделению данных на группу, в которой появляется группа лекарств A, созданию модели Кокса, а затем ее сравнению, например, с помощью Anova, с моделью Кокса, регрессированной в группе B? Что-то вроде aov(fitA, fitB) для fitA<-cox(Surv(tstart,tstop,death) ~ rx=='A, data = x')? Я не думаю, что survival может расслоить таким образом, но я мог бы разделить фрейм данных x.

adibender
1 апреля 2019 в 20:18
0

Я думаю, вы сможете просто заменить survdiff на coxph и соответствовать модели. если ваши данные имеют формат x выше, это уже в правильном формате.

adibender
1 апреля 2019 в 20:19
0

Я постараюсь опубликовать пример того, как сделать несколько сравнений для коэффициентов чуть позже.

neal
1 апреля 2019 в 21:10
0

Отлично, спасибо вам большое! Я изо всех сил пытался найти хороший ответ. Я был частично сбит с толку, потому что позже я пробовал что-то вроде, cox.fit<-coxph(Surv(tstart, tstop, death) ~ age + strata(rx), которое исключает каждую группу лекарств из соотношения рисков. Затем мне стало интересно, как можно сравнить функции риска для каждой группы, A, B, C. Нет ничего лучше cox.fitA<-coxph(Surv(tstart, tstop, death) ~ age + strata(rx)==A, верно? В любом случае, функция coxph действительно работает в той форме, которая у меня есть, но я хотел обсудить различия между группами лекарств.

adibender
1 апреля 2019 в 22:02
0

Когда вы используете страты, каждая группа получает свой собственный базовый риск, что, на мой взгляд, не имеет смысла для зависящих от времени ковариат.

Ответы (1)

avatar
adibender
1 апреля 2019 в 21:59
0

Итак, вот пример подгонки модели и выполнения множественных сравнений с использованием пакета multcomp. Обратите внимание, что это неявно предполагает, что введение препаратов A-C является случайным. В зависимости от предположений о процессе, возможно, лучше будет соответствовать модели с несколькими состояниями с переходами от лечения к результату.

library(purrr)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(survival)
library(multcomp)
#> Loading required package: mvtnorm
#> Loading required package: TH.data
#> Loading required package: MASS
#> 
#> Attaching package: 'MASS'
#> The following object is masked from 'package:dplyr':
#> 
#>     select
#> 
#> Attaching package: 'TH.data'
#> The following object is masked from 'package:MASS':
#> 
#>     geyser
# simulate survival data
set.seed(123)
n <- 200
df <- data.frame(
  id = rep(1:n, each = 8),
  start = rep(seq(0, 42, by = 6), times = 8),
  stop = rep(seq(6, 48, by = 6), times = 8),
  rx = sample(LETTERS[1:3], n * 8, replace = T))
df$hazard <- exp(-3.5  -1 * (df$rx == "A") + .5 * (df$rx == "B") +
  .5 * (df$rx == "C"))

df_surv <- data.frame(id = 1:n)
df_surv$time <- split(df, f = df$id) %>%
  map_dbl(~msm::rpexp(n = 1, rate = .x$hazard, t = .x$start))

df <- df %>% left_join(df_surv)
#> Joining, by = "id"
df <- df %>%
  mutate(status = 1L * (time <= stop)) %>%
  filter(start <= time)
df %>% head()
#>   id start stop rx     hazard     time status
#> 1  1     0    6  A 0.01110900 13.78217      0
#> 2  1     6   12  C 0.04978707 13.78217      0
#> 3  1    12   18  B 0.04978707 13.78217      1
#> 4  2     0    6  B 0.04978707 22.37251      0
#> 5  2     6   12  B 0.04978707 22.37251      0
#> 6  2    12   18  C 0.04978707 22.37251      0

# fit the model 
model <- coxph(Surv(start, stop, status)~rx, data = df)

# define pairwise comparison
glht_rx <- multcomp::glht(model, linfct=multcomp::mcp(rx="Tukey"))
glht_rx
#> 
#>   General Linear Hypotheses
#> 
#> Multiple Comparisons of Means: Tukey Contrasts
#> 
#> 
#> Linear Hypotheses:
#>            Estimate
#> B - A == 0  1.68722
#> C - A == 0  1.60902
#> C - B == 0 -0.07819

# perform multiple comparisons 
# (adjusts for multiple comparisons + takes into account correlation of coefficients -> more power than e.g. bonferroni)
smry_rx <- summary(glht_rx)
smry_rx # -> B and C different to A, but not from each other
#> 
#>   Simultaneous Tests for General Linear Hypotheses
#> 
#> Multiple Comparisons of Means: Tukey Contrasts
#> 
#> 
#> Fit: coxph(formula = Surv(start, stop, status) ~ rx, data = df)
#> 
#> Linear Hypotheses:
#>            Estimate Std. Error z value Pr(>|z|)    
#> B - A == 0  1.68722    0.28315   5.959   <1e-05 ***
#> C - A == 0  1.60902    0.28405   5.665   <1e-05 ***
#> C - B == 0 -0.07819    0.16509  -0.474     0.88    
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> (Adjusted p values reported -- single-step method)
# confidence intervals
plot(smry_rx)

Создано 2019-04-01 с помощью пакета REPEX (v0.2.1)

neal
2 апреля 2019 в 01:03
0

Это очень полезно и очень тщательно! Большое спасибо - именно то, что мне было нужно.