Short answer: yes, see the accepted reply.
I have the two data.table
below.
stocks = data.table(Ticker = c('xx','xx','yy','yy'), Date = c(as.IDate("2000-01-01"), as.IDate("2000-01-02")), t = c(1.8, 3.5))
Ticker Date t
1: xx 2000-01-01 1.8
2: xx 2000-01-02 3.5
3: yy 2000-01-01 1.8
4: yy 2000-01-02 3.5
tt = data.table(Date = c(as.IDate("2000-01-01"), as.IDate("2000-01-02")), t0 = c(1,2), t1 = c(2,3), t2 = c(3,4), y0 = c(10, 20), y1 = c(-20, -30), y2 = c(33,44))
Date t0 t1 t2 y0 y1 y2
1: 2000-01-01 1 2 3 10 -20 33
2: 2000-01-02 2 3 4 20 -30 44
For each row in stocks
, I want to find the approximate y
given t
, based on linear interpolation of values in tt
.
zz = tt[stocks, on = 'Date']
zz[, y.approx := approx(c(t0,t1,t2), c(y0,y1,y2), t)$y, by = 'Date,Ticker']
Date t0 t1 t2 y0 y1 y2 Ticker t y.approx
1: 2000-01-01 1 2 3 10 -20 33 xx 1.8 -14
2: 2000-01-02 2 3 4 20 -30 44 xx 3.5 7
3: 2000-01-01 1 2 3 10 -20 33 yy 1.8 -14
4: 2000-01-02 2 3 4 20 -30 44 yy 3.5 7
The problem is that doing this way has lots of duplicate calculation. Ideally I want to define an approxfun
for each day and apply it to each row in stocks
. But datatable cannot take function objects as its element.
tt[, ff := approxfun(c(t0,t1,t2), c(y0,y1,y2)), by = Date]
Error in `[.data.table`(tt, , `:=`(ff, approxfun(c(t0, t1, t2), c(y0, :
j evaluates to type 'closure'. Must evaluate to atomic vector or list.
My question is:
approx
on each row (and being slow)?7.3. Methods—setting functions as properties of objects. In JavaScript, you can use functions as values, just like numbers, strings, and objects. That means you can pass them as arguments, return them from other functions, and set them as properties of objects.
An object is a collection of properties, and a property is an association between a name (or key) and a value. A property's value can be a function, in which case the property is known as a method.
To pass an object as an argument we write the object name as the argument while calling the function the same way we do it for other variables. Syntax: function_name(object_name); Example: In this Example there is a class which has an integer variable 'a' and a function 'add' which takes an object as argument.
You can call a function inside an object by declaring the function as a property on the object and invoking it, e.g. obj. sum(2, 2) . An object's property can point to a function, just like it can point to a string, number or other values.
It's pretty easy to store functions in a data.table
- you just need to put them in a list:
tt[, ff := .(list(approxfun(c(t0,t1,t2), c(y0,y1,y2)))), by = Date]
# Date t0 t1 t2 y0 y1 y2 ff
#1: 2000-01-01 1 2 3 10 -20 33 <function>
#2: 2000-01-02 2 3 4 20 -30 44 <function>
stocks[tt, y.approx := ff[[1]](t), on = 'Date', by = .EACHI]
stocks
# Ticker Date t y.approx
#1: xx 2000-01-01 1.8 -14
#2: xx 2000-01-02 3.5 7
#3: yy 2000-01-01 1.8 -14
#4: yy 2000-01-02 3.5 7
How about something like:
> zz
Date t0 t1 t2 y0 y1 y2 Ticker t
1: 2000-01-01 1 2 3 10 -20 33 xx 1.8
2: 2000-01-02 2 3 4 20 -30 44 xx 3.5
3: 2000-01-01 1 2 3 10 -20 33 yy 1.8
4: 2000-01-02 2 3 4 20 -30 44 yy 3.5
> zz[t0<=t & t<=t1, y.approx:={a=(t-t0)/(t1-t0); y0+a*(y1-y0)}]
> zz
Date t0 t1 t2 y0 y1 y2 Ticker t y.approx
1: 2000-01-01 1 2 3 10 -20 33 xx 1.8 -14
2: 2000-01-02 2 3 4 20 -30 44 xx 3.5 NA
3: 2000-01-01 1 2 3 10 -20 33 yy 1.8 -14
4: 2000-01-02 2 3 4 20 -30 44 yy 3.5 NA
> zz[t1<=t & t<=t2, y.approx:={a=(t-t1)/(t2-t1); y1+a*(y2-y1)}]
> zz
Date t0 t1 t2 y0 y1 y2 Ticker t y.approx
1: 2000-01-01 1 2 3 10 -20 33 xx 1.8 -14
2: 2000-01-02 2 3 4 20 -30 44 xx 3.5 7
3: 2000-01-01 1 2 3 10 -20 33 yy 1.8 -14
4: 2000-01-02 2 3 4 20 -30 44 yy 3.5 7
>
Don't know how general you need it to be (how many columns you really have). But worth trying to vectorize like this to save the function call overhead by row. Several iterations of a for
loop for number of time deltas (2 in this case) should be faster than looping by row (let us know if you go that way and need to generate the query dynamically for each time delta).
We can hack it with a global list of functions and the superassignment operator:
x <- list();
invisible(tt[,{ x[[as.character(Date)]] <<- approxfun(c(t0,t1,t2),c(y0,y1,y2)); 0; },Date]);
x;
## $`2000-01-01`
## function (v)
## .approxfun(x, y, v, method, yleft, yright, f)
## <bytecode: 0x602762000>
## <environment: 0x603118610>
##
## $`2000-01-02`
## function (v)
## .approxfun(x, y, v, method, yleft, yright, f)
## <bytecode: 0x602762000>
## <environment: 0x60312c9d0>
##
stocks[,y.approx:=x[[as.character(Date)]](t),Date];
## Ticker Date t y.approx
## 1: xx 2000-01-01 1.8 -14
## 2: xx 2000-01-02 3.5 7
## 3: yy 2000-01-01 1.8 -14
## 4: yy 2000-01-02 3.5 7
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