R days before date event variable

Viewed 165

I'm looking at animal movements in response to winter weather, using R. I need to capture behavior during the day leading up to and days following a winter blizzard event. For this example:

library(dplyr)
d<-data.frame(date = seq(as.POSIXct("2018-12-01"), as.POSIXct("2019-01-31"),by="day"))
d<-d %>% 
  mutate(day = as.numeric(strftime(date, format = "%d")),
         bliz = ifelse(day == 13, 1,0)) %>% 
  select(-day)
view(d)

What I envision is 2 binary categories and a numerical variable, like this:

date bliz day_before_blizzard 3days_after num_days_after
2018-12-11 0 0 0 -2
2018-12-12 0 1 0 -1
2018-12-13 1 0 0 0
2018-12-14 0 0 1 1
2018-12-15 0 0 1 2
2018-12-16 0 0 1 3
... ... ... ... ...
2019-01-12 0 1 0 31
2019-01-13 1 0 0 0
... ... ... ... ...

Though I would consider alternative methods to capture this information. Just being able to calculate "number of days before/after a event" will be a valuable tool for me. Thank you in advance.

1 Answers

You can do this in a loop using the difftime function.

Starting with your code -

library(dplyr)
d<-data.frame(date = seq(as.POSIXct("2018-12-01"), as.POSIXct("2019-01-31"),by="day"))
d<-d %>% 
  mutate(day = as.numeric(strftime(date, format = "%d")),
         bliz = ifelse(day == 13, 1,0)) %>% 
  select(-day)

The first thing I would do is create your day before and 3 days after columns and make them default to 0.

# set default for day_before_blizzard and 3days_after to 0
d$day_before_blizzard <- 0
d$threeDaysAfter <- 0

Then the loop below will loop through the blizzard dates. The loop calculates the number of days before (or after) a date in the 'date' column is using difftime().

If difftime() returns -1 it will put a 1 in the day_before_blizzard column and if it is 1, 2, or 3 it will put a 1 in the threeDaysAfter column (R doesn't like columns starting with a number so I used 'three' rather than '3').

If there hasn't been a blizzard yet then the loop will set the num_days_after to be negative but otherwise it will determine the number of days since the most recent blizzard.

# extract blizzard dates and make sure they are in order
blizzardDates <- d[which(d$bliz == 1), "date"]
blizzardDates <- blizzardDates[order(blizzardDates)]

for(blizzardIndex in 1:length(blizzardDates)){
  # get the date of the blizzard
  blizzardDate <- blizzardDates[blizzardIndex]
  # figure out the the days to / from this date for each date in dataframe
  daysToIndexDate <- as.numeric(difftime(d$date, blizzardDate, units = "days"))
  # for any date that is 1 day before the blizzard set day_before_blizzard to 1
  d[which(daysToIndexDate == -1),"day_before_blizzard"] <- 1
  # for any date that contains 1 2 or 3 put it as within 3 days after
  d[which(daysToIndexDate %in% c(1,2,3)), "threeDaysAfter"] <- 1
  # if it is the first blizzard then we want to fill in num_days_after up to this date with negative numbers
  # this line of code will fill in all the rows with num_days_after the first date (but don't worry we will override these later)
  if(blizzardIndex == 1){d$num_days_after <- daysToIndexDate
  # otherwise (if it is not the first blizzard) we want to overwrite the previous num_days_after after for any date after the current date
  } else {
    d[which(daysToIndexDate >= 0),"num_days_after"] <- daysToIndexDate[which(daysToIndexDate >= 0)]
  }}
Related