2016-04-12 14 views
6

Câu trả lời ngắn gọn: có, xem câu trả lời được chấp nhận.Có thể có đối tượng chức năng làm thành phần


Tôi có hai data.table bên dưới.

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 với mỗi hàng trong stocks, tôi muốn tìm ra xấp xỉ y cho t, dựa trên nội suy tuyến tính của các giá trị trong 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 

Vấn đề là làm theo cách này có nhiều phép tính trùng lặp. Lý tưởng nhất là tôi muốn xác định một approxfun cho mỗi ngày và áp dụng nó cho mỗi hàng trong stocks. Nhưng datatable không thể lấy các đối tượng hàm làm phần tử của nó.

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. 

Câu hỏi của tôi là:

  1. Có cách nào tốt hơn là làm approx trên mỗi hàng (và bị chậm)?
  2. Có thể đặt dữ liệu để có đối tượng hàm làm phần tử của nó không?

Trả lời

6

Nó khá dễ dàng để các chức năng lưu trữ trong một data.table - bạn chỉ cần đặt chúng trong một danh sách:

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

Chúng ta có thể hack nó với một danh sách toàn cầu của các chức năng và các nhà điều hành superassignment:

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 không cần thiết – eddi

5

Làm thế nào về một cái gì đó như:

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

Không biết chung như thế nào bạn cần nó (bao nhiêu cột bạn thực sự có). Nhưng giá trị cố gắng để vectorize như thế này để tiết kiệm chi phí cuộc gọi chức năng theo hàng. Một số lần lặp của vòng lặp for đối với số lượng dấu thời gian (2 trong trường hợp này) phải nhanh hơn vòng lặp theo hàng (cho chúng tôi biết nếu bạn đi theo cách đó và cần tạo truy vấn động cho mỗi delta).

+0

Cảm ơn Matt. Tôi nghĩ rằng sau này tôi sẽ có một xấp xỉ phức tạp hơn (so với tuyến tính), vì vậy có lẽ không thể đánh vần như bạn đã làm ở đây. – jf328

+0

@ jf328 Bạn có thể sử dụng 'approx()' thay vì viết chính tả. Điều chính cho hiệu quả là làm điều đó với số lượng lớn; bất cứ điều gì ngoài một cuộc gọi hàm trên mỗi hàng. –

Các vấn đề liên quan