Giới thiệu
Bài này muốn giới thiệu các bước xử lí data để chuẩn bị cho phân tích survival.
Khi phân tích survival hàm survival chính thường là:
f1 <- survfit(Surv(time, status) ~ 1, data = lung)
Trong đó dataset là “lung”, biến số biến cố sống, chết là “status” và thời gian theo dõi của mỗi bệnh nhân từ khi khởi đầu điều trị cho đến khi có biến cố hoặc lần tiếp xúc cuối cùng của nghiên cứu là “time”.
Tuy nhiên, trong thực tế phân tích dữ liệu nghiên cứu, biến số time không có sẳn như data mẫu. Các bước xử lí data thu thập từ phiếu nghiên cứu để đi đến biến số time không hề đơn giản.
Dưới đây là bảng excel dữ liệu thời gian của các lần khám (visit) được ghi nhận theo định dạng sau. Mỗi bệnh nhân có số lần khám không đồng đều nhau. Tôi sẽ xử lí bảng excel này để cho ra các biến số ID bệnh nhân, thời gian theo dõi (time) và tình trạng sống còn (event). Mỗi row là dữ liệu của một bệnh nhân.

Tải data
library(tidyverse)
# Survival data
df <- read_excel("E:/Statistics/R/R Writings/survdat.xlsx")
df
NA
Trong bảng excel ở trên có những bệnh nhân có biến cố (event = 1) và những bệnh nhân không có biến cố (event = 0). Trong phân tích survival, biến số thời gian (time) được tính từ lúc vào nghiên cứu cho đến khi có biến cố hoặc đến khi hết theo dõi nếu bệnh nhân không có biến cố.
Như vậy, mỗi bệnh nhân, ta phải chọn ra 2 thời điểm. Thời điểm thứ nhất là lần khám 1, vừa vào nghiên cứu và thời điểm thứ 2 là ngày có biến cố (event = 1) hoặc ngày cuối cùng đối với bệnh nhân không có biến cố.
Xử lí data
Đánh dấu các lần khám của mỗi bệnh nhân như sau. Chú ý vào lần khám đầu tiên, lần khám có biến cố và lần khám cuối cùng đối với bệnh nhân không có biến cố.
df2 <- df %>% arrange(ID, visit) %>%
group_by(ID) %>%
dplyr::mutate(numb = dplyr::row_number()) %>% # Create numbering variable
filter(numb == 1 | event == 1 | (event == 0 & numb == max(numb)))
df2
Trong bảng kết quả trên, bệnh nhân B và E không có biến cố, chúng ta sẽ chọn ra thời điểm đầu và cuối của họ. Những bệnh nhân A, C và D chúng ta chọn thời điểm vào nghiên cứu và lúc có biến cố (event =1). Vì vậy chúng ta phải loại lần khám cuối cùng của họ (A, C và D) như sau.
df2 <- df2 %>% group_by(ID) %>%
dplyr::mutate(rank = row_number()) %>%
filter(rank == 1 | rank == 2)
df2
NA
Đến đây đã có data như mình muốn. Chúng ta làm gọn lại, chỉ chọn những biến số cần thiết mà thôi. Sau đó để tính được khoảng thời gian giữa 2 thời điểm ta biến chúng thành 2 biến số T1 và T2.
df.s <- select(df2, ID,date,event,rank)
# as.factor(c(df.s$event, df.s$rank))
dat <- spread(df.s, rank, date)
colnames(dat) <- c("ID", "event", "t1", "t2")
dat
Mỗi bệnh nhân vẫn có 2 rows và những bệnh nhân có biến cố thì t1 và t2 không cùng nằm trong một dòng. Ta phải sắp xếp lại lần nữa.
for (i in 1:nrow(dat)) {
if (dat$event[i] == 1) {
dat$t1[i] <- dat$t1[i-1]
}
}
dat <- dat %>% drop_na()
dat
NA
Tới thời điểm này chúng ta đã có bộ data như mình mong muốn. Để tính time cho mỗi bệnh nhân, ta tính khoảng thời gian giữa 2 thời điểm t1 và t2 ở trên.
Package “lubridate” giúp chúng ta xử lí biến số thời gian.
# date process
library(lubridate)
dat <- dat %>%
mutate(
t.first = ymd(t1),
t.last = ymd(t2)
)
dat <- dat %>%
mutate(
time =
as.numeric(
difftime(t.last,
t.first,
units = "days")) / 365.25
)
dat
NA
Đến đây chúng ta đã có các biến số cần thiết để phân tích survival là event (status) và time.
Cám ơn các bạn đã đọc bài viết này.
LS0tDQp0aXRsZTogIlN1cnZpdmFsIERhdGEgTWFuaXB1bGF0aW9uIg0KYXV0aG9yOiAiVGhpZXUgTmd1eWVuIg0KZGF0ZTogIjEwLzEyLzIwMjEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQojIyBHaeG7m2kgdGhp4buHdQ0KDQpCw6BpIG7DoHkgbXXhu5FuIGdp4bubaSB0aGnhu4d1IGPDoWMgYsaw4bubYyB44butIGzDrSBkYXRhIMSR4buDIGNodeG6qW4gYuG7iyBjaG8gcGjDom4gdMOtY2ggc3Vydml2YWwuDQoNCktoaSBwaMOibiB0w61jaCBzdXJ2aXZhbCBow6BtIHN1cnZpdmFsIGNow61uaCB0aMaw4budbmcgbMOgOg0KDQogICAgZjEgPC0gc3VydmZpdChTdXJ2KHRpbWUsIHN0YXR1cykgfiAxLCBkYXRhID0gbHVuZykNCg0KVHJvbmcgxJHDsyBkYXRhc2V0IGzDoCAibHVuZyIsIGJp4bq/biBz4buRIGJp4bq/biBj4buRIHPhu5FuZywgY2jhur90IGzDoCAic3RhdHVzIiB2w6AgdGjhu51pIGdpYW4gdGhlbyBkw7VpIGPhu6dhIG3hu5dpIGLhu4duaCBuaMOibiB04burIGtoaSBraOG7n2kgxJHhuqd1IMSRaeG7gXUgdHLhu4sgY2hvIMSR4bq/biBraGkgY8OzIGJp4bq/biBj4buRIGhv4bq3YyBs4bqnbiB0aeG6v3AgeMO6YyBjdeG7kWkgY8O5bmcgY+G7p2EgbmdoacOqbiBj4bupdSBsw6AgInRpbWUiLg0KDQpUdXkgbmhpw6puLCB0cm9uZyB0aOG7sWMgdOG6vyBwaMOibiB0w61jaCBk4buvIGxp4buHdSBuZ2hpw6puIGPhu6l1LCBiaeG6v24gc+G7kSB0aW1lIGtow7RuZyBjw7Mgc+G6s24gbmjGsCBkYXRhIG3huqt1LiBDw6FjIGLGsOG7m2MgeOG7rSBsw60gZGF0YSB0aHUgdGjhuq1wIHThu6sgcGhp4bq/dSBuZ2hpw6puIGPhu6l1IMSR4buDIMSRaSDEkeG6v24gYmnhur9uIHPhu5EgdGltZSBraMO0bmcgaOG7gSDEkcahbiBnaeG6o24uDQoNCkTGsOG7m2kgxJHDonkgbMOgIGLhuqNuZyBleGNlbCBk4buvIGxp4buHdSB0aOG7nWkgZ2lhbiBj4bunYSBjw6FjIGzhuqduIGtow6FtICh2aXNpdCkgxJHGsOG7o2MgZ2hpIG5o4bqtbiB0aGVvIMSR4buLbmggZOG6oW5nIHNhdS4gTeG7l2kgYuG7h25oIG5ow6JuIGPDsyBz4buRIGzhuqduIGtow6FtIGtow7RuZyDEkeG7k25nIMSR4buBdSBuaGF1LiBUw7RpIHPhur0geOG7rSBsw60gYuG6o25nIGV4Y2VsIG7DoHkgxJHhu4MgY2hvIHJhIGPDoWMgYmnhur9uIHPhu5EgSUQgYuG7h25oIG5ow6JuLCB0aOG7nWkgZ2lhbiB0aGVvIGTDtWkgKHRpbWUpIHbDoCB0w6xuaCB0cuG6oW5nIHPhu5FuZyBjw7JuIChldmVudCkuIE3hu5dpIHJvdyBsw6AgZOG7ryBsaeG7h3UgY+G7p2EgbeG7mXQgYuG7h25oIG5ow6JuLg0KDQohW10oQzovVXNlcnMvVEhJRVUvQXBwRGF0YS9Mb2NhbC9SU3R1ZGlvL3RtcC9wYXN0ZS0wMjlDNzFCNy5wbmcpDQoNCiMjIFThuqNpIGRhdGENCg0KYGBge3J9DQoNCmxpYnJhcnkodGlkeXZlcnNlKQ0KIyBTdXJ2aXZhbCBkYXRhDQpkZiA8LSByZWFkX2V4Y2VsKCJFOi9TdGF0aXN0aWNzL1IvUiBXcml0aW5ncy9zdXJ2ZGF0Lnhsc3giKQ0KZGYNCg0KYGBgDQoNClRyb25nIGLhuqNuZyBleGNlbCDhu58gdHLDqm4gY8OzIG5o4buvbmcgYuG7h25oIG5ow6JuIGPDsyBiaeG6v24gY+G7kSAoZXZlbnQgPSAxKSB2w6Agbmjhu69uZyBi4buHbmggbmjDom4ga2jDtG5nIGPDsyBiaeG6v24gY+G7kSAoZXZlbnQgPSAwKS4gVHJvbmcgcGjDom4gdMOtY2ggc3Vydml2YWwsIGJp4bq/biBz4buRIHRo4budaSBnaWFuICh0aW1lKSDEkcaw4bujYyB0w61uaCB04burIGzDumMgdsOgbyBuZ2hpw6puIGPhu6l1IGNobyDEkeG6v24ga2hpIGPDsyBiaeG6v24gY+G7kSBob+G6t2MgxJHhur9uIGtoaSBo4bq/dCB0aGVvIGTDtWkgbuG6v3UgYuG7h25oIG5ow6JuIGtow7RuZyBjw7MgYmnhur9uIGPhu5EuDQoNCk5oxrAgduG6rXksIG3hu5dpIGLhu4duaCBuaMOibiwgdGEgcGjhuqNpIGNo4buNbiByYSAyIHRo4budaSDEkWnhu4NtLiBUaOG7nWkgxJFp4buDbSB0aOG7qSBuaOG6pXQgbMOgIGzhuqduIGtow6FtIDEsIHbhu6thIHbDoG8gbmdoacOqbiBj4bupdSB2w6AgdGjhu51pIMSRaeG7g20gdGjhu6kgMiBsw6AgbmfDoHkgY8OzIGJp4bq/biBj4buRIChldmVudCA9IDEpIGhv4bq3YyBuZ8OgeSBjdeG7kWkgY8O5bmcgxJHhu5FpIHbhu5tpIGLhu4duaCBuaMOibiBraMO0bmcgY8OzIGJp4bq/biBj4buRLg0KDQojIyBY4butIGzDrSBkYXRhDQoNCsSQw6FuaCBk4bqldSBjw6FjIGzhuqduIGtow6FtIGPhu6dhIG3hu5dpIGLhu4duaCBuaMOibiBuaMawIHNhdS4gQ2jDuiDDvSB2w6BvIGzhuqduIGtow6FtIMSR4bqndSB0acOqbiwgbOG6p24ga2jDoW0gY8OzIGJp4bq/biBj4buRIHbDoCBs4bqnbiBraMOhbSBjdeG7kWkgY8O5bmcgxJHhu5FpIHbhu5tpIGLhu4duaCBuaMOibiBraMO0bmcgY8OzIGJp4bq/biBj4buRLg0KDQpgYGB7cn0NCg0KZGYyIDwtIGRmICU+JSBhcnJhbmdlKElELCB2aXNpdCkgJT4lIA0KICBncm91cF9ieShJRCkgJT4lICANCiAgZHBseXI6Om11dGF0ZShudW1iID0gZHBseXI6OnJvd19udW1iZXIoKSkgJT4lICMgQ3JlYXRlIG51bWJlcmluZyB2YXJpYWJsZQ0KICBmaWx0ZXIobnVtYiA9PSAxIHwgZXZlbnQgPT0gMSB8IChldmVudCA9PSAwICYgbnVtYiA9PSBtYXgobnVtYikpKQ0KZGYyDQpgYGANCg0KVHJvbmcgYuG6o25nIGvhur90IHF14bqjIHRyw6puLCBi4buHbmggbmjDom4gQiB2w6AgRSBraMO0bmcgY8OzIGJp4bq/biBj4buRLCBjaMO6bmcgdGEgc+G6vSBjaOG7jW4gcmEgdGjhu51pIMSRaeG7g20gxJHhuqd1IHbDoCBjdeG7kWkgY+G7p2EgaOG7jS4gTmjhu69uZyBi4buHbmggbmjDom4gQSwgQyB2w6AgRCBjaMO6bmcgdGEgY2jhu41uIHRo4budaSDEkWnhu4NtIHbDoG8gbmdoacOqbiBj4bupdSB2w6AgbMO6YyBjw7MgYmnhur9uIGPhu5EgKGV2ZW50ID0xKS4gVsOsIHbhuq15IGNow7puZyB0YSBwaOG6o2kgbG/huqFpIGzhuqduIGtow6FtIGN14buRaSBjw7luZyBj4bunYSBo4buNIChBLCBDIHbDoCBEKSBuaMawIHNhdS4NCg0KYGBge3J9DQpkZjIgPC0gZGYyICU+JSBncm91cF9ieShJRCkgJT4lDQogIGRwbHlyOjptdXRhdGUocmFuayA9IHJvd19udW1iZXIoKSkgJT4lDQogIGZpbHRlcihyYW5rID09IDEgfCByYW5rID09IDIpDQpkZjINCg0KYGBgDQoNCsSQ4bq/biDEkcOieSDEkcOjIGPDsyBkYXRhIG5oxrAgbcOsbmggbXXhu5FuLiBDaMO6bmcgdGEgbMOgbSBn4buNbiBs4bqhaSwgY2jhu4kgY2jhu41uIG5o4buvbmcgYmnhur9uIHPhu5EgY+G6p24gdGhp4bq/dCBtw6AgdGjDtGkuIFNhdSDEkcOzIMSR4buDIHTDrW5oIMSRxrDhu6NjIGtob+G6o25nIHRo4budaSBnaWFuIGdp4buvYSAyIHRo4budaSDEkWnhu4NtIHRhIGJp4bq/biBjaMO6bmcgdGjDoG5oIDIgYmnhur9uIHPhu5EgVDEgdsOgIFQyLg0KDQpgYGB7ciB9DQpkZi5zIDwtIHNlbGVjdChkZjIsIElELGRhdGUsZXZlbnQscmFuaykNCg0KIyBhcy5mYWN0b3IoYyhkZi5zJGV2ZW50LCBkZi5zJHJhbmspKQ0KZGF0IDwtIHNwcmVhZChkZi5zLCByYW5rLCBkYXRlKSANCg0KY29sbmFtZXMoZGF0KSA8LSBjKCJJRCIsICJldmVudCIsICJ0MSIsICJ0MiIpDQpkYXQNCmBgYA0KDQpN4buXaSBi4buHbmggbmjDom4gduG6q24gY8OzIDIgcm93cyB2w6Agbmjhu69uZyBi4buHbmggbmjDom4gY8OzIGJp4bq/biBj4buRIHRow6wgdDEgdsOgIHQyIGtow7RuZyBjw7luZyBu4bqxbSB0cm9uZyBt4buZdCBkw7JuZy4gVGEgcGjhuqNpIHPhuq9wIHjhur9wIGzhuqFpIGzhuqduIG7hu69hLg0KDQpgYGB7cn0NCiMgbOG6pXkgZOG7ryBsaeG7h3UgdGjhu51pIGdpYW4gY+G7p2EgZMOybmcgdHLDqm4gxJFp4buBbiB2w6BvIGTDsm5nIGTGsOG7m2kgY2hvIGPDuW5nIG3hu5l0IGLhu4duaCBuaMOibg0KZm9yIChpIGluIDE6bnJvdyhkYXQpKSB7DQogIGlmIChkYXQkZXZlbnRbaV0gPT0gMSkgew0KICAgIGRhdCR0MVtpXSA8LSBkYXQkdDFbaS0xXQ0KICB9DQp9DQoNCmRhdCA8LSBkYXQgJT4lIGRyb3BfbmEoKQ0KZGF0DQoNCmBgYA0KDQpU4bubaSB0aOG7nWkgxJFp4buDbSBuw6B5IGNow7puZyB0YSDEkcOjIGPDsyBi4buZIGRhdGEgbmjGsCBtw6xuaCBtb25nIG114buRbi4gxJDhu4MgdMOtbmggdGltZSBjaG8gbeG7l2kgYuG7h25oIG5ow6JuLCB0YSB0w61uaCBraG/huqNuZyB0aOG7nWkgZ2lhbiBnaeG7r2EgMiB0aOG7nWkgxJFp4buDbSB0MSB2w6AgdDIg4bufIHRyw6puLg0KDQpQYWNrYWdlICJsdWJyaWRhdGUiIGdpw7pwIGNow7puZyB0YSB44butIGzDrSBiaeG6v24gc+G7kSB0aOG7nWkgZ2lhbi4NCg0KYGBge3J9DQojIGRhdGUgcHJvY2Vzcw0KbGlicmFyeShsdWJyaWRhdGUpDQoNCmRhdCA8LSBkYXQgJT4lIA0KICBtdXRhdGUoDQogICAgdC5maXJzdCA9IHltZCh0MSksIA0KICAgIHQubGFzdCA9IHltZCh0MikNCiAgKQ0KDQpkYXQgPC0gZGF0ICU+JSANCiAgbXV0YXRlKA0KICAgIHRpbWUgPSANCiAgICAgIGFzLm51bWVyaWMoDQogICAgICAgIGRpZmZ0aW1lKHQubGFzdCwgDQogICAgICAgICAgICAgICAgIHQuZmlyc3QsIA0KICAgICAgICAgICAgICAgICB1bml0cyA9ICJkYXlzIikpIC8gMzY1LjI1DQogICkNCg0KZGF0DQoNCmBgYA0KDQrEkOG6v24gxJHDonkgY2jDum5nIHRhIMSRw6MgY8OzIGPDoWMgYmnhur9uIHPhu5EgY+G6p24gdGhp4bq/dCDEkeG7gyBwaMOibiB0w61jaCBzdXJ2aXZhbCBsw6AgZXZlbnQgKHN0YXR1cykgdsOgIHRpbWUuDQoNCkPDoW0gxqFuIGPDoWMgYuG6oW4gxJHDoyDEkeG7jWMgYsOgaSB2aeG6v3QgbsOgeS4NCg==