2016-04-12 13 views
6

短い回答:はい、受け入れられた回答を参照してください。ファンクションオブジェクトを要素として持つことは可能ですか?


私は以下の2つを持っています。data.tablestocksの各行について

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 

、Iはttの値の線形補間に基づいて、t所与近似yを見つけたいです。

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 

問題は、この方法を行うことは、重複計算をたくさん持っているということです。理想的には、毎日approxfunを定義し、それをstocksの各行に適用したいと考えています。しかし、データテーブルは、その要素として関数オブジェクトをとることはできません。

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. 

私の質問は:

  1. は、各行にapproxをやって(と低速である)よりも良い方法はありますか?
  2. datatableが関数オブジェクトを要素として持つことは可能ですか?
私たちは、機能のグローバルリストとsuperassignment演算子でそれをハックすることができ

答えて

6

それはdata.tableに機能を保存するために非常に簡単です - あなただけのリストにそれらを配置する必要があります。

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 
2

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 
+2

不要hackiness – eddi

5

どのようなものについて:あなたがそれを必要とするどのように一般的か分からないのです

> 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 
> 

あなたが実際に持っているカラム数です。しかし、行ごとに関数呼び出しのオーバーヘッドを節約するために、このようにベクトル化しようとする価値があります。時間デルタの数(この場合2)のループのいくつかの反復は、行ごとのループより速くなければなりません(そのように行って、時間デルタごとに動的にクエリを生成する必要がある場合はお知らせください)。

+0

おかげでマット。私は後で私は(線形よりも)より複雑な近似を持っていると思うので、おそらくあなたがここで行ったように綴ることはできません。 – jf328

+0

@ jf328スペルアウトの代わりに 'approx()'を使うことができます。効率のための主なものは、一括して行うことです。何か行ごとに関数呼び出しがあります。 –

関連する問題