Jason
Jason

Reputation: 932

Looping through a data frame of datetimes

I'm trying to create GPS schedules for satellite transmitters that are used to track the migration of a bird species I'm studying. The function below called 'sched_gps_fixes' takes a vector of datetimes and writes them to a .ASF file, which is uploaded to the satellite transmitter. This tells the transmitter what date and time to take a GPS fix. Using R and the sched_gps_fixes function allows me to quickly create a GPS schedule that starts on any day of the year. The software that comes with the transmitters does this as well, but I would have to painstakingly select each time and date I want the transmitter to take a GPS location.

So I want to: 1) create a data frame that contains every day of the year in 2018, and the time I want the transmitter to collect a GPS location, 2) use each row of the data frame as the start date for a sequence of datetimes (so starting on 2018-03-25 12:00:00 for example, I want to create a GPS schedule that takes a GPS point every other day after that, so 2018-03-25 12:00:00, 2018-03-27 12:00:00, etc.), and 3) create a .ASF file for each GPS schedule. Here's a simplified version of what I'm trying to accomplish below:

library(lubridate)

# set the beginning time
start_date <- ymd_hms('2018-01-01 12:00:00')

# create a sequence of datetimes starting January 1
days_df <- seq(ymd_hms(start_date), ymd_hms(start_date+days(10)), by='1 days')
tz(days_df) <- "America/Chicago"
days_df <- as.data.frame(days_df)
days_df

# to reproduce the example
days_df <- structure(list(days_df = structure(c(1514829600, 1514916000, 
1515002400, 1515088800, 1515175200, 1515261600, 1515348000, 1515434400, 
1515520800, 1515607200, 1515693600), class = c("POSIXct", "POSIXt"
), tzone = "America/Chicago")), .Names = "days_df", row.names = c(NA, 
-11L), class = "data.frame")

# the data frame looks like this:

days_df
1  2018-01-01 12:00:00
2  2018-01-02 12:00:00
3  2018-01-03 12:00:00
4  2018-01-04 12:00:00
5  2018-01-05 12:00:00
6  2018-01-06 12:00:00
7  2018-01-07 12:00:00
8  2018-01-08 12:00:00
9  2018-01-09 12:00:00
10 2018-01-10 12:00:00
11 2018-01-11 12:00:00

I would like to loop through each datetime in the data frame, and create a vector for each row of the data frame. So each vector would have a particular row's datetime as the starting date for a GPS schedule, which would take a point every 2 days (something like this):

[1] "2018-01-01 12:00:00 UTC" "2018-01-03 12:00:00 UTC" "2018-01-05 12:00:00 UTC" "2018-01-07 12:00:00 UTC"
[5] "2018-01-09 12:00:00 UTC" "2018-01-11 12:00:00 UTC"

Each vector (or GPS schedule) would then be run in the following function as 'gps_schedule' to create a .ASF file for the transmitters:

sched_gps_fixes(gps_schedule, tz = "America/Chicago", out_file = "./gps_fixes")

So I'm wondering how to create a for loop that would produce a vector of datetimes for each day of 2018. This is pseudocode for what I'm attempting to do:

# create a loop called 'create_schedules' to make the GPS schedules and produce a .ASF file for each day of 2018

create_schedules <- function(days_df) {

  for(row in 1:nrow(days_df)) {

    seq(ymd_hms(days_df[[i]]), ymd_hms(days_df[[i]]+days(10)), by='2 days')

  }
}

# run the function
create_schedules(days_df)

I'm guessing I need an output to store and name each vector by its start date, among other things?

Thanks,

Jay

Upvotes: 2

Views: 62

Answers (1)

MKR
MKR

Reputation: 20095

One option is to use mapply to generate schedule for each row based on schedule definition provided by OP:

library(lubridate)

# For the sample data max_date needs to be calculated. Otherwise to generate
# schedule for whole 2018 max_date can be taken as 31-Dec-2018.
max_date = max(days_df$days_df)

mapply(function(x)seq(x, max_date, by="2 days"),days_df$days_df) 

#Result : Only first 3 items from the list generated. It will continue 
# [[1]]
# [1] "2018-01-01 12:00:00 CST" "2018-01-03 12:00:00 CST" "2018-01-05 12:00:00 CST"
# [4] "2018-01-07 12:00:00 CST" "2018-01-09 12:00:00 CST" "2018-01-11 12:00:00 CST"
# 
# [[2]]
# [1] "2018-01-02 12:00:00 CST" "2018-01-04 12:00:00 CST" "2018-01-06 12:00:00 CST"
# [4] "2018-01-08 12:00:00 CST" "2018-01-10 12:00:00 CST"
# 
# [[3]]
# [1] "2018-01-03 12:00:00 CST" "2018-01-05 12:00:00 CST" "2018-01-07 12:00:00 CST"
# [4] "2018-01-09 12:00:00 CST" "2018-01-11 12:00:00 CST"
# ....
# ....
# ....
# [[10]]
# [1] "2018-01-10 12:00:00 CST"
# 
# [[11]]
# [1] "2018-01-11 12:00:00 CST"

If OP prefers to have names for items in result list then mapply can be used as:

Update: Based on OP's request to generate schedule for start+10 days. 10 days is equivalent to 10*24*3600 seconds.

mapply(function(x, y)seq(y, y+10*24*3600, by="2 days"),
    as.character(days_df$days_df), days_df$days_df, 
    SIMPLIFY = FALSE,USE.NAMES = TRUE) 

#Result
# $`2018-01-01 12:00:00`
# [1] "2018-01-01 12:00:00 CST" "2018-01-03 12:00:00 CST" "2018-01-05 12:00:00 CST"
# [4] "2018-01-07 12:00:00 CST" "2018-01-09 12:00:00 CST" "2018-01-11 12:00:00 CST"
#.......
#.......
#.......so on

Upvotes: 1

Related Questions