How can I pass column entires as arguments to a function, then creating a new column which is a function of the other two? For example, taking this excellent function to add months to a date, and taking this example data frame:
df <- structure(
list(
date = structure(
c(
17135,
17105,
17105,
17074,
17286,
17317,
17317,
17347,
17105,
17317
),
class = "Date"
),
monthslater = c(10,
11, 13, 14, 3, 3, 3, 3, 4, NA)
),
.Names = c("date", "monthslater"),
row.names = c(NA, 10L),
class = "data.frame"
)
I would like to create a new column where I pass the entries from columns date
and monthslater
to the function add.months
I would have thought that something like this would work:
df$newdate <- add.months(df$date, df$monthslater)
But it doesn't.
The full code for the function is:
add.months <- function(date,n) seq(date, by = paste(n, "months"), length = 2)[2]
Using %m+%
from the lubridate
-package:
library(lubridate)
df$newdate <- df$date %m+% months(df$monthslater)
gives:
> df date monthslater newdate 1 2016-11-30 10 2017-09-30 2 2016-10-31 11 2017-09-30 3 2016-10-31 13 2017-11-30 4 2016-09-30 14 2017-11-30 5 2017-04-30 3 2017-07-30 6 2017-05-31 3 2017-08-31 7 2017-05-31 3 2017-08-31 8 2017-06-30 3 2017-09-30 9 2016-10-31 4 2017-02-28 10 2017-05-31 4 2017-09-30
In a similar way you can also add days or years:
df$newdate2 <- df$date %m+% days(df$monthslater)
df$newdate3 <- df$date %m+% years(df$monthslater)
which gives:
> df date monthslater newdate newdate2 newdate3 1 2016-11-30 10 2017-09-30 2016-12-10 2026-11-30 2 2016-10-31 11 2017-09-30 2016-11-11 2027-10-31 3 2016-10-31 13 2017-11-30 2016-11-13 2029-10-31 4 2016-09-30 14 2017-11-30 2016-10-14 2030-09-30 5 2017-04-30 3 2017-07-30 2017-05-03 2020-04-30 6 2017-05-31 3 2017-08-31 2017-06-03 2020-05-31 7 2017-05-31 3 2017-08-31 2017-06-03 2020-05-31 8 2017-06-30 3 2017-09-30 2017-07-03 2020-06-30 9 2016-10-31 4 2017-02-28 2016-11-04 2020-10-31 10 2017-05-31 4 2017-09-30 2017-06-04 2021-05-31
For your immediate, specific issue, consider mapply
to pass those two vectors element-wise into defined function. And since monthslater includes NA
, add a tryCatch
to defined function.
add.months <- function(date, n) {
tryCatch(seq(date, by = paste(n, "months"), length = 2)[2],
warning = function(w) return(NA),
error = function(e) return(NA))
}
df$newdate <- as.Date(mapply(add.months, df$date, df$monthslater), origin="1970-01-01")
df
# date monthslater newdate
# 1 2016-11-30 10 2017-09-30
# 2 2016-10-31 11 2017-10-01
# 3 2016-10-31 13 2017-12-01
# 4 2016-09-30 14 2017-11-30
# 5 2017-04-30 3 2017-07-30
# 6 2017-05-31 3 2017-08-31
# 7 2017-05-31 3 2017-08-31
# 8 2017-06-30 3 2017-09-30
# 9 2016-10-31 4 2017-03-03
# 10 2017-05-31 NA <NA>
Also, do note the author's item involving end of February and hence #9 is extended 3 days ahead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With