我正在尝试在R中开发一个随时间变化的Cox比例风险(CPH)模型,并且想知道是否有人生成了任何代码来帮助格式化用于时变/时间相关CPH模型的计数结构的数据。 / p>
为了使问题可重现且更简单,我提取了前100行数据,其中包含4个变量(id
,date
,y
和{{1} })。 x
是唯一的主题标识符。 id
是每个date
观察0到n天的整数序列。 id
是危害分析的状态或结果,y
是随时间变化的协变量。在此示例中,一旦x
= 1发生,每个主题的数据将被审查,理想输出数据帧中不应包含其他数据。
数据的结构使得每个主题有1行,对应于每天的观察。
y
但是,据我所知,R中的head(test)
id date y x
1 0 0 0
1 1 0 1
1 2 0 1
1 3 0 1
1 4 0 1
1 5 0 0
函数要求时变协变量的构造方式需要将cph
和start
变量重新编码为3对于上面end
代码块中的数据,间隔为(0,1)和(1,5)和(5,6)的行。
可以使用以下代码重建前100行数据:
head(test)
理想情况下,我正在尝试重新编码这些数据,以便输出为:
dput(test)
structure(list(id = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9,
9, 9, 9), date = c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2,
3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
0, 1, 2, 3, 4, 5, 6, 7, 8), y = c(0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0), x = c(0L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L,
1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L,
0L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L,
0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L,
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L,
0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L,
0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 0L)), .Names = c("id",
"date", "y", "x"), row.names = c(NA, -100L), class = "data.frame")
我已手动完成此操作以创建上面的head(ideal_output)
id start end y x
1 0 1 0 0
1 1 5 0 1
1 5 6 0 0
1 6 7 0 1
1 7 9 0 0
1 9 11 0 1
1 11 20 0 0
2 0 8 0 0
3 0 1 0 0
3 1 3 0 1
3 3 4 0 0
3 4 6 0 1
3 6 7 1 1
4 0 2 0 0
4 2 4 0 1
4 4 7 0 0
5 0 9 0 0
6 0 7 0 0
7 0 1 0 0
7 1 2 0 1
7 2 3 0 0
7 3 4 1 0
8 0 3 0 0
8 3 4 1 1
9 0 2 0 0
9 2 5 0 1
9 5 6 1 1
,但这是一个容易出错的过程,对于我需要评估的数百个ideal_output
和几个协变量而言难以维持。因此,在开发处理此数据格式化挑战的自动方式时,将非常感谢任何帮助。谢谢!
答案 0 :(得分:1)
我认为Survsplit()函数可以解决您的问题。
看看: http://www.rdocumentation.org/packages/eha/functions/SurvSplit
或者,尝试谷歌:第5章扩展和分层考克斯 - nus.edu.sg
答案 1 :(得分:1)
正如@Ham建议你可以使用tmerge
。这是一个例子
> #####
> # `dat` is the data.frame you provided
> library(survival)
>
> # make baseline data.frame for tmerge
> baseline <- by(dat, dat$id, function(x){
+ n <- nrow(x)
+ # avoid slow data.frame call
+ structure(list(
+ id = x$id[1], start = x$date[1], x = x$x[1], end = x$date[n],
+ dummy = 0),
+ row.names = 1L, class = "data.frame")
+ })
> baseline <- do.call(rbind, baseline)
> baseline # show baseline data
id start x end dummy
1 1 0 0 19 0
2 2 0 0 7 0
3 3 0 0 12 0
4 4 0 0 6 0
5 5 0 0 8 0
6 6 0 0 6 0
7 7 0 0 11 0
8 8 0 0 14 0
9 9 0 0 8 0
>
> # use tmerge
> final_dat <- tmerge(baseline, baseline, id = id, y = event(end, dummy))
> final_dat <- tmerge(
+ final_dat, dat, id = id, y = cumtdc(date, y), x = tdc(date, x))
> final_dat[final_dat$id == 3, ] # look at one example
id start x end dummy tstart tstop y
27 3 0 0 12 0 0 1 0
28 3 0 1 12 0 1 2 0
29 3 0 1 12 0 2 3 0
30 3 0 0 12 0 3 4 0
31 3 0 1 12 0 4 5 0
32 3 0 1 12 0 5 6 0
33 3 0 1 12 0 6 7 1
34 3 0 1 12 0 7 8 1
35 3 0 1 12 0 8 9 1
36 3 0 1 12 0 9 10 1
37 3 0 1 12 0 10 11 1
38 3 0 0 12 0 11 12 1
>
> # remove values where y is not zero or y is not the first non-zero value
> final_dat <- within(final_dat, ycum <- unlist(tapply(y, id, cumsum)))
> final_dat <- final_dat[final_dat$ycum < 2, ]
> final_dat$ycum <- NULL
> final_dat[final_dat$id == 3, ]
id start x end dummy tstart tstop y
27 3 0 0 12 0 0 1 0
28 3 0 1 12 0 1 2 0
29 3 0 1 12 0 2 3 0
30 3 0 0 12 0 3 4 0
31 3 0 1 12 0 4 5 0
32 3 0 1 12 0 5 6 0
33 3 0 1 12 0 6 7 1
>
> # remove x row where the previous x value do match. But
> # * keep those where y = 1
> # * update tstop for the last row where the last row may be removed
> final_dat <- within(
+ final_dat,
+ max_t <- unlist(tapply(tstop, id, function(z) rep(max(z), length(z)))))
> final_dat <- within(
+ final_dat,
+ keep <- unlist(tapply(x, id, function(z)
+ c(TRUE, z[-1] != z[-length(z)]))))
>
> final_dat <- final_dat[final_dat$keep | final_dat$y, ]
>
> final_dat <- within(
+ final_dat, is_last <- unlist(tapply(id, id, function(z)
+ seq_along(z) == length(z))))
>
> needs_update <- final_dat$is_last & !final_dat$y
> final_dat[needs_update, "tstop"] <-
+ final_dat[needs_update, "max_t"] + 1
>
> # have to update the tstop column
> final_dat <- within(final_dat, tstop <- unlist(by(
+ cbind(tstart, tstop), id, function(z) {
+ n <- nrow(z)
+ c(z$tstart[-1], z$tstop[n])
+ })))
>
> # show final data.frame
> final_dat[, c("id", "tstart", "tstop", "y", "x")]
id tstart tstop y x
1 1 0 1 0 0
2 1 1 5 0 1
6 1 5 6 0 0
7 1 6 7 0 1
8 1 7 9 0 0
10 1 9 11 0 1
12 1 11 20 0 0
20 2 0 8 0 0
27 3 0 1 0 0
28 3 1 3 0 1
30 3 3 4 0 0
31 3 4 6 0 1
33 3 6 7 1 1
39 4 0 2 0 0
41 4 2 4 0 1
43 4 4 7 0 0
45 5 0 9 0 0
53 6 0 7 0 0
59 7 0 1 0 0
60 7 1 2 0 1
61 7 2 3 0 0
62 7 3 4 1 0
70 8 0 3 0 0
73 8 3 4 1 1
84 9 0 2 0 0
86 9 2 5 0 1
89 9 5 6 1 1
使用tmerge
或dplyr
可以更快地完成data.table
之后的代码。如果您的列数不仅仅是x
,那么我建议您:1)存储dat
的列索引,并在tmerge
函数的tdc
中使用该列而不是x
。然后将表格与merge
合并。此外,您需要更新生成keep
指标的行。否则代码应该是相同的。
答案 2 :(得分:0)
我认为tmerge()函数是你问题的答案。
看看:https://cran.r-project.org/web/packages/survival/vignettes/timedep.pdf