Handling closures in data.table

I use the data.table package to return a list of function closures in an expression jas a function output approxfunfrom a statistics package. Basically, on every Date I would like to close, which allows me to compute an arbitrary yval based on an arbitrary xval, as defined approxfun.

However, it approxfunis only valid when there are at least two unique x values ​​passed to the function. In the case where there is only one unique value of x, I would like to return a function that returns a single value of y.

In the code below, I complete this step by checking the value .Nand returning another function depending on whether there is .N > 1.

 library(data.table)
 set.seed(10)
 N <- 3
 x <- data.table(Date = Sys.Date() + rep(1:N, each = 3), xval = c(0, 30, 90), yval = rnorm(N * 3))
 x <- x[-c(2:3), ]

 ##interpolation happens correctly
 x2 <- x[order(Date, xval), {
     if(.N > 1){
         afun <- approxfun(xval, yval, rule = 1)
     }else{
         afun <- function(v) yval
     }
     print(afun(30))
     list(Date, afun = list(afun))
 }, by = Date]

 ##evaluation does NOT happen correctly, the val used is the last...
 sapply(x2[, afun], do.call, args = list(v = 30))

"afun" j "yval". , , yval yval , "by" , approxfun ( , approxfun ).

, , . , "force", .

 x3 <- x[order(Date, xval), {
      if(.N > 1){
         afun <- approxfun(xval, yval, rule = 1)
     }else{
         fn <- function(x){
             force(x)
             function(v) x
         }
         afun <- fn(yval)
     }
     print(afun(30))
     list(Date, afun = list(afun))
 }, by = Date]

 sapply(x3[, afun], do.call, args = list(v = 30))

- ? - R - data.table?

+4
1

, . :

x2 <- x[order(Date, xval), {
  if(.N > 1){
    afun <- approxfun(xval, yval, rule = 1)
  }else{
    fn <- function(){
      #ensure the value is copied
      x <- copy(yval)
      function(v) x
    }
    afun <- fn()
  }
  print(afun(30))
  list(Date, afun = list(afun))
}, by = Date]
#[1] 0.01874617
#[1] 0.2945451
#[1] -0.363676

sapply(x2[, afun], do.call, args = list(v = 30))
#[1]  0.01874617  0.29454513 -0.36367602
+5

Source: https://habr.com/ru/post/1683899/


All Articles