Dropping subsequent observations after the occurrence of an event in a longitudinal data set

Viewed 47

I got longitudinal data set where I want to drop observations after the event of interest have happend. This means I want to drop all observations after the dummy-variable indicating the event of interest has happened (i.e., event == 1). The data looks something like this:

id <- c(1,1,1,2,2,2,3,3,3,4,4,4,5,5,5)
time <-  c(1,2,3,1,2,3,1,2,3,1,2,3,1,2,3) 
event <- c(0,1,0,1,0,0,0,0,0,0,1,0,1,0,0)

df <- cbind(id,time,event)

      id time event
 [1,]  1    1     0
 [2,]  1    2     1
 [3,]  1    3     0
 [4,]  2    1     1
 [5,]  2    2     0
 [6,]  2    3     0
 [7,]  3    1     0
 [8,]  3    2     0
 [9,]  3    3     0
[10,]  4    1     0
[11,]  4    2     1
[12,]  4    3     0
[13,]  5    1     1
[14,]  5    2     0
[15,]  5    3     0

I want to drop all subsequent observations after the event has happened (for clarity: event == 1)for an id. Leading to a data set that looks like this:

     id time event
[1,]  1    1     0
[2,]  1    2     1
[3,]  2    1     1
[4,]  3    1     0
[5,]  3    2     0
[6,]  3    3     0
[7,]  4    1     0
[8,]  4    2     1
[9,]  5    1     1

My biggest issue is how to condition the removal of subsequent observation on the time variable.

Thanks in advance! :D

2 Answers

If the data is constructed as a data.frame, then we could use a group by operation in dplyr i.e. grouped by 'id', get the position index of first occurence of 1 in the event if there is any and get the sequence, or else return the row sequence

library(dplyr)
df %>%
  arrange(id, time) %>%
  group_by(id) %>%
  slice(if(1 %in% event) seq(match(1, event)) else row_number()) %>%
  ungroup

-output

# A tibble: 9 x 3
#     id  time event
#  <dbl> <dbl> <dbl>
#1     1     1     0
#2     1     2     1
#3     2     1     1
#4     3     1     0
#5     3     2     0
#6     3     3     0
#7     4     1     0
#8     4     2     1
#9     5     1     1

Or can make it shorter without the if/else if we specify the nomatch as the number of rows (n())

df %>%
    arrange(id, time) %>%
    group_by(id) %>%
    slice(seq(match(1, event, nomatch = n())))

data

df <- data.frame(id, time, event)

A solution with seq_len()

library(dplyr)
df %>%
arrange(id, time)  %>%
  group_by(id) %>%
  slice(seq_len(min(which(event == 1), n())))

data

id <- c(1,1,1,2,2,2,3,3,3,4,4,4,5,5,5)
time <-  c(1,2,3,1,2,3,1,2,3,1,2,3,1,2,3) 
event <- c(0,1,0,1,0,0,0,0,0,0,1,0,1,0,0)

df <- data.frame(id,time,event)

# output:
# Groups:   id [5]
     id  time event
  <dbl> <dbl> <dbl>
1     1     1     0
2     1     2     1
3     2     1     1
4     3     1     0
5     3     2     0
6     3     3     0
7     4     1     0
8     4     2     1
9     5     1     1
Related