sotiris sotiris - 3 months ago 11
R Question

Dealing with NAs in vectors with user-defined functions

I'm trying to create a function in R that replicates Excel's EOMonth function (i.e. you enter a date and a number of months and it returns you the end of the month date for the same number of months before / after the input date). I've a got a function that works on a single input using the lubridate package:

EOMonth <- function(date, months)
{
NewDate <- date %m+% months(months)
NewDate <- ceiling_date(NewDate, "month") - days(1)
}


The problem is how to 'vectorise' this (not sure that's the right word). When I pass the function a vector (in this case a column in a data frame), I get the following message:


NAs are not allowed in subscripted assignments


I don't want to ignore any NAs in the vector (because I am sending the results to a new column in the data frame). I just want the function, when it sees an NA, to return an NA, but to process all the valid dates as the function dictates. I'm really confused as to how to do this; most of the posts I have seen on this topic relate to how to ignore / remove NAs from the results.

Any help would be greatly appreciated.

Thanks.

Edit. Added in some sample data. Below is sample input data:

01/07/2016
NA
22/07/2016
NA
30/06/2016
22/07/2016
22/07/2016
29/07/2016
NA
22/07/2016
30/06/2016
NA
31/01/2016
02/08/2016


So, entering the following:

newVector <- EOMonth(OldVector, 3)


Should return the end of the month for each of the dates in 3 months' time:

31/10/2016
NA
31/10/2016
NA
30/09/2016
31/10/2016
31/10/2016
31/10/2016
NA
31/10/2016
30/09/2016
NA
NA
30/04/2016
30/11/2016

Answer

One solution is to first make a vector of NAs and then process only the non-NA elements of date. Note the NA class needs to be date or the dates are converted to numeric.

EOMonth <- function(date, months) 
{
  NewDate <- date(rep(NA, length(date)))
  NewDate[!is.na(date)] <- date[!is.na(date)] %m+% months(months) 
  NewDate[!is.na(date)] <- ceiling_date(NewDate[!is.na(date)], "month") - days(1)
  NewDate
}

EOMonth(OldVector, 3)
Comments