How can I conditionally expand rows in my R dataframe?

Viewed 28

I have a dataframe that I would like to expand based on a few conditions. If the Activity is "Repetitive" I would like to explode the rows to twice as long as the duration, filling in a new dataframe with a row for each 0.5 second event. The rest of the information would stay the same, except that the rows that have been expanded will alternate between the given object in the original dataframe (e.g. "Toy") and "Nothing."

Location <- c("Kitchen", "Living Room", "Living Room", "Garage")
Object <- c("Food", "Toy", "Clothes", "Floor")
Duration <- c(6,3,2,5)
CumDuration <- c(6,9,11,16)
Activity <- c("Repetitive", "Constant", "Constant", "Repetitive")

df <- data.frame(Location, Object, Duration, CumDuration, Activity)

So it looks like this:

| Location    | Object   | Duration | CumDuration | Activity   |
| ----------- | -------- | -------- | ----------- | ---------- |
| Kitchen     | Food     | 6        | 6           | Repetitive |
| Living Room | Toy      | 3        | 9           | Constant   |
| Living Room | Clothes  | 2        | 11          | Constant   |
| Garage      | Floor    | 5        | 16          | Repetitive |

And I want it to look like this:

| Location    | Object   | Duration | CumDuration | Activity   |
| ----------- | -------- | -------- | ----------- | ---------- |
| Kitchen     | Food     | 0.5      | 0.5         | Repetitive |
| Kitchen     | Nothing  | 0.5      | 1           | Repetitive |
| Kitchen     | Food     | 0.5      | 1.5         | Repetitive |
| Kitchen     | Nothing  | 0.5      | 2           | Repetitive |
| Kitchen     | Food     | 0.5      | 2.5         | Repetitive |
| Kitchen     | Nothing  | 0.5      | 3           | Repetitive |
| Kitchen     | Food     | 0.5      | 3.5         | Repetitive |
| Kitchen     | Nothing  | 0.5      | 4           | Repetitive |
| Kitchen     | Food     | 0.5      | 4.5         | Repetitive |
| Kitchen     | Nothing  | 0.5      | 5           | Repetitive |
| Kitchen     | Food     | 0.5      | 5.5         | Repetitive |
| Kitchen     | Nothing  | 0.5      | 6           | Repetitive |
| Living Room | Toy      | 3        | 9           | Constant   |
| Living Room | Clothes  | 2        | 11          | Constant   |
| Garage      | Floor    | 0.5      | 11.5        | Repetitive |
| Garage      | Nothing  | 0.5      | 12          | Repetitive |
| Garage      | Floor    | 0.5      | 12.5        | Repetitive |
| Garage      | Nothing  | 0.5      | 13          | Repetitive |
| Garage      | Floor    | 0.5      | 13.5        | Repetitive |
| Garage      | Nothing  | 0.5      | 14          | Repetitive |
| Garage      | Floor    | 0.5      | 14.5        | Repetitive |
| Garage      | Nothing  | 0.5      | 15          | Repetitive |
| Garage      | Floor    | 0.5      | 15.5        | Repetitive |
| Garage      | Nothing  | 0.5      | 16          | Repetitive |

Thanks so much in advance!

1 Answers

Here is a dyplr option to achieve this

library(dplyr)
df$CumDuration = as.numeric(df$CumDuration)

df %>% filter(Activity == "Repetitive") %>% 
  group_by(Location) %>% 
  slice(rep(1:n(), each= Duration/0.5)) %>% # Create the new rows
  mutate(Duration = Duration/(Duration*2)) %>% # Change the Duration to 0.5
  ungroup() %>%
  arrange(CumDuration) %>%
  mutate(Object = ifelse((row_number() %% 2) == 0, "Nothing", Object), ID = 1:n()) %>% # Change the Object every other row for "Nothing" and add ID for sorting in correct order
  full_join(filter(df, Activity != "Repetitive")) %>% # Merge back with the unmodified rows of original data frame
  arrange(CumDuration, ID) %>% # Arrange rows in the correct order
  mutate(CumDuration = cumsum(Duration)) %>% # Recalculate the cumulative sum
  select(-ID) # Remove the ID column no longer wanted


# A tibble: 24 x 5
   Location Object  Duration CumDuration Activity  
   <chr>    <chr>      <dbl>       <dbl> <chr>     
 1 Kitchen  Food         0.5         0.5 Repetitive
 2 Kitchen  Nothing      0.5         1   Repetitive
 3 Kitchen  Food         0.5         1.5 Repetitive
 4 Kitchen  Nothing      0.5         2   Repetitive
 5 Kitchen  Food         0.5         2.5 Repetitive
 6 Kitchen  Nothing      0.5         3   Repetitive
 7 Kitchen  Food         0.5         3.5 Repetitive
 8 Kitchen  Nothing      0.5         4   Repetitive
 9 Kitchen  Food         0.5         4.5 Repetitive
10 Kitchen  Nothing      0.5         5   Repetitive
# ... with 14 more rows
Related