R изменение формы/расширение набора данных с использованием survSplit для получения переменной во времени для регрессии Кокса

Я видел другие вопросы, подобные этому, но они не отвечают на мой вопрос. Я хочу расширить свой набор данных, так как мне нужно создать изменяющуюся во времени переменную для анализа выживания и использовать команду survSplit (пакет survival), но мои данные уже частично в длинном формате. Пример данных:

data1<-structure(list(id = c(1, 1, 1, 1, 5, 5, 5, 5, 5, 7, 7, 7, 7, 
7, 7), start = c(0, 183, 210, 241, 0, 183, 187, 212, 244, 0, 
118, 139, 188, 212, 237), no_days = c(NA, 28L, 28L, 28L, NA, 
7L, 28L, 28L, 28L, NA, 28L, 28L, 28L, 28L, 28L), stop = c(NA, 
211, 238, 269, NA, 190, 215, 240, 272, NA, 146, 167, 216, 240, 
265), drug = c(0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1), 
    dead = c(0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1)), .Names = c("id", 
"start", "no_days", "stop", "drug", "dead"), row.names = c(NA, 
15L), class = "data.frame")

> head(data1,15)
   id start no_days stop drug dead
1   1     0      NA   NA    0    0
2   1   183      28  211    1    0
3   1   210      28  238    1    0
4   1   241      28  269    1    1
5   5     0      NA   NA    0    0
6   5   183       7  190    1    0
7   5   187      28  215    1    0
8   5   212      28  240    1    0
9   5   244      28  272    1    1
10  7     0      NA   NA    0    0
11  7   118      28  146    1    0
12  7   139      28  167    1    0
13  7   188      28  216    1    0
14  7   212      28  240    1    0
15  7   237      28  265    1    1

Start — это день, когда лекарство было назначено, no_days — как долго был назначен рецепт, drug указывает, принимал ли человек лекарство в течение заданного периода времени (это переменная, которую мне нужно сделать изменяющейся во времени), dead указывает, когда было назначено лекарство. человек умер. На данный момент набор данных содержит только время, когда человек принимал наркотик, поэтому окончательный набор данных, который я хочу, должен выглядеть так:

 head(data1,18)
   id start no_days stop drug dead
1   1     0      NA  182    0    0
2   1   183      28  211    1    0
3   1   210      28  238    1    0
4   1   239      NA  240    0    0
5   1   241      28  269    1    1
6   5     0      NA  182    0    0
7   5   183       7  190    1    0
8   5   187      28  215    1    0
9   5   212      28  240    1    0
10  5   241      NA  243    0    0
11  5   244      28  272    1    1
12  7     0      NA  117    0    0
13  7   118      28  146    1    0
14  7   139      28  167    1    0
15  7   168      NA  187    0    0
16  7   188      28  216    1    0
17  7   212      28  240    1    0
18  7   237      28  265    1    1

Может быть, это должна быть стандартная проблема манипулирования данными, когда мне нужно добавить больше строк на основе определенных критериев, но, учитывая, что это данные о выживании, и survSplit был разработан для этого, хотя для начала немного другая структура данных, мне было интересно, есть ли простой способ использовать survSplit для решения моей проблемы. Если нет, есть ли у кого-нибудь простое предложение по расширению фрейма данных.

Мой последний шаг - подогнать модель Кокса примерно так:

coxph(Surv(data$start,data$stop,data$dead)~covariates + drug +cluster(id),data=data1) 

Спасибо за любые предложения.


person user63230    schedule 30.01.2017    source источник


Ответы (1)


Рассмотрим следующую обработку данных с базой R, где, по сути, вы merge смещаете кадр данных на одну строку, чтобы выровнять текущую и следующую запись, а затем transform для вычислений start и stop.

Примечание. merge вызовет предупреждение (не ошибку) о дублирующемся столбце nextidcnt. Либо проигнорируйте, либо создайте второй data1 для слияния, используя id и idcnt (сдвинутый на один в новом df) в качестве ключей соединения.

# OBTAIN GROUP COUNT (FOR MERGE IDs)
data1$idcnt <- sapply(1:nrow(data1), function(i) sum(data1[1:i, c("id")] == data1$id[i]))
data1$nextidcnt <- data1$idcnt + 1

# MERGE
dfm <- merge(data1, data1, by.x=c("id", "nextidcnt"), by.y=c("id", "idcnt"))

# CALCULATE NEW COLUMNS
dfm <- transform(dfm,
                 start = ifelse(is.na(stop.x), start.x, stop.x + 1),
                 no_days = no_days.x,
                 stop = start.y - 1,
                 drug = 0,
                 dead = dead.x)  

# ROW BIND ORIGINAL SUBSET WITH NEW ROWS
finaldf <- rbind(data1[data1$start != 0, c(1:6)],
                 dfm[dfm$start < dfm$stop,
                     c("id", "start", "no_days", "stop", "drug", "dead")])

finaldf <- finaldf[with(finaldf, order(id, start, stop)),]  # ORDER BY ID, START, STOP
rownames(finaldf) <- NULL                                   # RESET ROW NAMES

Вывод

finaldf

#    id start no_days stop drug dead
# 1   1     0      NA  182    0    0
# 2   1   183      28  211    1    0
# 3   1   210      28  238    1    0
# 4   1   239      28  240    0    0
# 5   1   241      28  269    1    1
# 6   5     0      NA  182    0    0
# 7   5   183       7  190    1    0
# 8   5   187      28  215    1    0
# 9   5   212      28  240    1    0
# 10  5   241      28  243    0    0
# 11  5   244      28  272    1    1
# 12  7     0      NA  117    0    0
# 13  7   118      28  146    1    0
# 14  7   139      28  167    1    0
# 15  7   168      28  187    0    0
# 16  7   188      28  216    1    0
# 17  7   212      28  240    1    0
# 18  7   237      28  265    1    1
person Parfait    schedule 31.01.2017
comment
Очень умно получилось, спасибо. Интересно, вернется ли кто-нибудь с решением survSplit. - person user63230; 31.01.2017