Search code examples
rdata.tablerollapply

Error when combining rollapply() and weighted.mean() in an lapply() data.table setting


I ran the following code:

id <- c(67, 39, 39, 39, 39, 39, 39, 39, 58, 58, 58, 58, 58, 58)
ratio <- c(0.5421248, 0.1558647, 0.1314578, 0.1095102, 0.1149908, 0.1645262, 0.1431160, 0.1633623,
       1.1375268, 1.3219208, 1.3830684, 1.5942101, 0.5991420, 0.6303874)
DT <- data.table(id, ratio)

DT[, lapply(.SD, 
            function(x) rollapplyr(x, 
                                   width = 3,
                                   weighted.mean, 
                                   w = c(0.2, 0.3, 0.5),
                                   align = 'right', 
                                   fill = NA)),
   by = id,
   .SDcols = 'ratio']

And it gives the following error:

Error in `[.data.table`(DT, , lapply(.SD, function(x) rollapplyr(x, width = 3,  : 
  Column 1 of result for group 2 is type 'double' but expecting type 'logical'. Column types must be consistent for each group.

When I exclude the first row like this:

DT[2:14, lapply(.SD, 
                function(x) rollapplyr(x, 
                                       width = 3,
                                       weighted.mean, 
                                       w = c(0.2, 0.3, 0.5),
                                       align = 'right', 
                                       fill = NA)),
       by = id,
       .SDcols = 'ratio']

I don't get an error. I suppose it has something to do with there being only one id = 67.

Is there a way to avoid this error and just get NA for id 67?

I don't really understand why it doesn't work because this works:

rollapplyr(ratio, 
           width = 3,
           weighted.mean, 
           w = c(0.2, 0.3, 0.5),
           align = 'right', 
           fill = NA)

Solution

  • From Andrew's comment:

    DT[, lapply(.SD, zoo::rollapplyr,
                width = 3, FUN = weighted.mean,
                w = c(0.2, 0.3, 0.5), fill = NA_real_),
       by = id, .SDcols = 'ratio']
    #     id     ratio
    #  1: 67        NA
    #  2: 39        NA
    #  3: 39        NA
    #  4: 39 0.1253654
    #  5: 39 0.1166400
    #  6: 39 0.1386624
    #  7: 39 0.1439140
    #  8: 39 0.1575212
    #  9: 58        NA
    # 10: 58        NA
    # 11: 58 1.3156158
    # 12: 58 1.4764097
    # 13: 58 1.0544477
    # 14: 58 0.8137783
    

    The two changes made here:

    1. NA to NA_real_. Many functions enforce preserving the class on operations; in this case, zoo::rollapplyr has an input class of numeric, but class(NA) returns logical. This might be a good time to note that NA actually has at least seven variants: NA (logical), NA_integer_, NA_real_, NA_character_, c.Date(NA), c.POSIXlt(NA), and c.POSIXct(NA). Several of them are documented in ?NA, the others are found by exploration. (This preservation of class is also present in functions such as dplyr::if_else and data.table::fifelse, but sadly not with base's ifelse.)

    2. Not a bug, granted, but removal of align="right", since in this case it is redundant with the use of the rollapplyr function (the trailing r indicates "right").