Is there a way to isolate multiple index points in a dataset and isolate a time window around that index point in R?

Viewed 46

I have a dataset with patients who were under observation for 72 hours. Patient's oxygen levels were measured every 4 seconds but some observations had to be removed due to issues with accuracy of the data. As a result, patients have a varying number of observations.

While patients were observed, they underwent various interventions. The objective of my analysis is to assess whether interventions affected the patient's oxygen levels or not. Therefore, I am doing a comparison of the oxygen levels pre-intervention, during intervention and post-intervention.

While the actual analysis isn't too difficult, I am having a hard time subsetting the data. For example, I only want observations 300 seconds prior to the start of an intervention and 300 seconds post intervention. I have to take into account the fact that an individual may have multiple interventions over the course of the time window and there are multiple subjects.

I have provided some sample code below to generate a dataset but please let me know if I'm missing anything.

id <- rep(c(1,2,3), each = 1000)
intervention <- c(rep(0,200), rep(1,10), rep(0,153), rep(0,5), rep(0,284), rep(0,20), rep(0,159), rep(0,23), rep(0,146),
                  rep(0,123), rep(1,23), rep(0,356), rep(1,8), rep(0,234), rep(1,23), rep(0,233),
                  rep(0,345), rep(1,12), rep(0,48), rep(1,15), rep(0,74), rep(1,4), rep(0,233), rep(1,82), rep(0,187))
final <- data.frame(id, intervention)
final <- final %>%
  group_by(id) %>%
  mutate(time = row_number() * 4) 

So far, I have tried this method but I was only able to isolate single observations 5 mins pre and post an intervention and not all observations between those time windows (ie, the single observation 5mins prior to start of an intervention and the single observation 5 mins post an intervention but not all the observations in between these three points)

data <- final4 %>%
  filter(intervention == 1) %>%
  mutate(five_mins_after = time + 300, #5 mins after intervention
         five_mins_before = time - 300) %>% #5 mins before intervention %>%
  filter(id == "1")

data2 <- final4 %>%
  filter(intervention == 0,
        id == "1")

data_after <- data %>%
  dplyr::select(five_mins_after)

data_before <- data %>%
  dplyr::select(five_mins_before)

data3 <- merge(data2, data_after, by.x = "time", by.y = "five_mins_after")
data4 <- merge(data2, data_before, by.x = "time", by.y = "five_mins_before")

final <- final %>%
  dplyr::bind_rows(data3) %>%
  dplyr::bind_rows(data4)
  

Please let me know if you need any additional information and thanks for your time!

PS: Apologies if I missed anything, first time asking for help here

1 Answers

Here is the answer. Although long, it worked fine for gathering times 300 seconds before and 300 after the beggining of an intervention.

Let me know if you'd like further explanation or if I have misunderstood anything.

library(magrittr)
library(tidyverse)

### Sample code
id <- rep(c(1,2,3), each = 1000)
intervention <- c(rep(0,200), rep(1,10), rep(0,153), rep(0,5), rep(0,284), rep(0,20), rep(0,159), rep(0,23), rep(0,146),
                  rep(0,123), rep(1,23), rep(0,356), rep(1,8), rep(0,234), rep(1,23), rep(0,233),
                  rep(0,345), rep(1,12), rep(0,48), rep(1,15), rep(0,74), rep(1,4), rep(0,233), rep(1,82), rep(0,187))
final <- data.frame(id, intervention)
final <- final %>%
  group_by(id) %>%
  mutate(time = row_number() * 4) 

### Start of data processing to get wanted observations

# Order it by id and time
final %<>% arrange(id, time)

# Loop over the unique ids
obs_to_keep <- list()
for(i in unique(final$id)) {
  
  # Get starts of treatment
  time_zero_intervention <- final %>% 
    filter(id == i & intervention == 0) %>% 
    select(time)
  
  # Obtain all times after zero interventions, that could be intervention == 1
  time_plus_4 <- time_zero_intervention$time + 4
  
  # Where in the times after 0 intervention there is a 1 intervention
  starts_of_interventions <- final %>% 
    filter(id == i & time %in% time_plus_4) %>% 
    filter(intervention == 1)
  
  # Loop over each one of the times where intervention starts
  all_times <- list()
  for(n in 1:length(starts_of_interventions$time)) {
    # Gather 300 secs prior and post
    time_300_before <- starts_of_interventions$time[n] - 300
    time_300_after <- starts_of_interventions$time[n] + 300
    
    # Filter for observations in this interval
    all_times[[n]] <- final %>%
      filter(id == i) %>%
      filter(time >= time_300_before & time <= time_300_after)
  }
  if(length(all_times) == 1){
    obs_to_keep[[i]] <- as.data.frame(all_times)
  }
  else {
    obs_to_keep[[i]] <- do.call(rbind, all_times)
  }
}

# Make a data frame from the list
df <- do.call(rbind, obs_to_keep)

# Order it by id and time
df %<>% arrange(id, time)
Related