简体   繁体   中英

Transform data to start-stop / long format

I want to do survival analysis with a cox regression. Therefore, I need to transform my data according to observation times to a start-stop format instead of just one time observation.

Example dataset:

  • userid indicates user identifier

  • day indicates days since first event

  • status indicates if the event of interest happened this day (1 = yes, 0 = no)

da1 <- data.frame(userid = c(1,1,1,2,2,2,3,3,3), day= c(1,2,3,1,2,3,1,2,3), status = c(0,0,1,1,0,0,0,1,1))

da1
  userid day status
1      1   1      0
2      1   2      0
3      1   3      1
4      2   1      1
5      2   2      0
6      2   3      0
7      3   1      0
8      3   2      1
9      3   3      1

I want to have my data this format:

da2 <- data.frame(userid = c(1,1,1,2,2,2,3,3,3), startday= c(0,1,2,0,1,2,0,1,2), endday = c(1,2,3,1,2,3,1,2,3), status = c(0,0,1,1,0,0,0,1,1))

da2
  userid startday endday status
1      1        0      1      0
2      1        1      2      0
3      1        2      3      1
4      2        0      1      1
5      2        1      2      0
6      2        2      3      0
7      3        0      1      0
8      3        1      2      1
9      3        2      3      1

It would be great, if I would also have some code to aggregate the observations if more than one day occurs without an event in a row.

da3 <- data.frame(userid = c(1,1,2,2,3,3,3), startday= c(0,2,0,2,0,1,2), endday = c(2,3,1,3,1,2,3), status = c(0,1,1,0,0,1,1))

da3
  userid startday endday status
1      1        0      2      0
2      1        2      3      1
3      2        0      1      1
4      2        2      3      0
5      3        0      1      0
6      3        1      2      1
7      3        2      3      1

I have tried the following code, but it gives wrong results:

for (i in 1:max(da$userid)){
  obst<-sort(unique(da$day))
  stpT<-obst[1:which(obst==da$day[i])]
  id<-rep(i,length(stpT))
  stat<-c(rep(0,length(stpT)-1),da$status[i])                            
  strT<-lag(stpT,1);strT[1]=0 
  iln<-stpT-strT

  df<-data.frame(userid=id,Start=strT,Stop=stpT,Status=stat,ILen=iln)
  if(i==1){data_obs=df}
  else{data_obs=rbind(data_obs,df)}
}

data_obs<-merge(data_obs,data[,c('userid','X')],by='userid')
dim(data_obs)

We can group_by userid and create a sequence for startday from 0 to max value of day in group and endday from 1 to max(day) .

library(dplyr)

da1 %>%
  group_by(userid) %>%
  mutate(startday = seq(0, max(day) - 1), 
         endday = seq(max(day))) %>%
  select(-day)

#  userid status startday endday
#   <dbl>  <dbl>    <int>  <int>
#1      1      0        0      1
#2      1      0        1      2
#3      1      1        2      3
#4      2      1        0      1
#5      2      0        1      2
#6      2      0        2      3
#7      3      0        0      1
#8      3      1        1      2
#9      3      1        2      3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM