2013-02-20 29 views
13

Tôi muốn thêm một cột mới vào data.table của tôi. Cột này phải chứa tổng của một cột khác của tất cả các hàng thỏa mãn một điều kiện nhất định. Một ví dụ: data.table của tôi trông như thế này:Làm thế nào để tự tham gia một data.table trên một điều kiện

require(data.table) 
DT <- data.table(n=c("a", "a", "a", "a", "a", "a", "b", "b", "b"), 
      t=c(10, 20, 33, 40, 50, 22, 25, 34, 11), 
      v=c(20, 15, 16, 17, 11, 12, 20, 22, 10) 
      ) 
DT 
    n t v 
1: a 10 20 
2: a 20 15 
3: a 33 16 
4: a 40 17 
5: a 50 11 
6: a 22 12 
7: b 25 20 
8: b 34 22 
9: b 11 10 

Đối với mỗi hàng x và mỗi hàng i, nơi abs (t [i] - t [x]) < = 10, tôi muốn để tính toán

foo = sum(v[i] * abs(t[i] - t[x])) 

Trong SQL, tôi sẽ giải quyết vấn đề này bằng cách tự tham gia. Trong R Tôi đã có thể thực hiện việc này bằng cách sử dụng vòng lặp for:

for (i in 1:nrow(DT)) 
    DT[i, foo:=DT[n==DT[i]$n & abs(t-DT[i]$t)<=10, sum(v * abs(t-DT[i]$t))]] 

DT 
    n t v foo 
1: a 10 20 150 
2: a 20 15 224 
3: a 33 16 119 
4: a 40 17 222 
5: a 50 11 170 
6: a 22 12 30 
7: b 25 20 198 
8: b 34 22 180 
9: b 11 10 0 

Thật không may tôi phải làm điều này khá thường xuyên và bảng tôi làm việc khá lớn. Cách tiếp cận vòng lặp hoạt động nhưng quá chậm. Tôi chơi xung quanh với gói sqldf, không có bước đột phá thực sự. Tôi rất thích làm điều này bằng cách sử dụng một số phép thuật data.table và có tôi cần sự giúp đỡ của bạn :-). Tôi nghĩ những gì cần thiết là một số loại tự tham gia vào điều kiện rằng sự khác biệt của các giá trị t là nhỏ hơn ngưỡng đó.

Theo dõi: Tôi có câu hỏi tiếp theo: Trong đơn đăng ký của tôi, lần kết nối này được thực hiện lặp đi lặp lại. Sự thay đổi của v, nhưng t và n luôn giống nhau. Vì vậy, tôi đang suy nghĩ về việc bằng cách nào đó lưu trữ những hàng thuộc về nhau. Bất kỳ ý tưởng làm thế nào để làm điều này một cách thông minh?

+0

từ đầu ra của bạn, có vẻ như bạn cũng có điều kiện 'i! = X' đúng không? –

+0

Không. Đối với hàng 9 foo = 0 vì thuật ngữ abs (t-DT [i] $ t) == 0. Nhưng không nên loại trừ i! = X, vì việc tính toán trong ứng dụng của tôi phức tạp hơn một chút như trong ví dụ này và tôi cần hàng x trong đó. – uuazed

Trả lời

5

Hãy thử như sau:

unique(merge(DT, DT, by="n")[abs(t.x - t.y) <= 10, list(n, sum(v.x * abs(t.x - t.y))), by=list(t.x, v.x)]) 

Phân tích cho dòng trên:

Bạn có thể kết hợp một bảng với chính nó, đầu ra cũng sẽ là một data.table. Chú ý rằng các tên cột sẽ được cung cấp một hậu tố của .x.y

merge(DT, DT, by="n") 

... bạn chỉ có thể lọc và tính toán như với bất kỳ DT

# this will give you your desired rows 
[abs(t.x - t.y), ] 

# this is the expression you outlined 
[ ... , sum(v.x * abs(t.x - t.y)) ] 

# summing by t.x and v.x 
[ ... , ... , by=list(t.x, v.x)]) ] 

Sau đó, cuối cùng gói tất cả trong unique để loại bỏ bất kỳ hàng trùng lặp nào.


UPDATE: này phải là một bình luận nhưng quá dài

Dòng dưới đây là những gì phù hợp với đầu ra của bạn. Sự khác biệt duy nhất giữa điều này và câu trả lời ở đầu câu trả lời này là cụm từ v.y trong sum(v.y * ...) tuy nhiên câu lệnh by vẫn sử dụng v.x. Điều đó có chủ ý không?

unique(merge(DT, DT, by="n")[abs(t.x - t.y) <= 10, list(n, sum(v.y * abs(t.x - t.y))), by=list(t.x, v.x)]) 
+0

Cảm ơn! Điều này nhanh hơn khoảng 6 lần so với phương pháp tiếp cận vòng lặp của tôi trên mẫu. Tôi sẽ cố gắng này trên các dữ liệu thực tế bây giờ ... – uuazed

+0

vui mừng để giúp ... thú vị, tôi đang sử dụng 'v.x' và nó xuất hiện bạn có thể đang sử dụng' v.y' Mà là tính toán của bạn mong đợi? –

+0

Về việc hợp nhất. Bạn đang sử dụng hàm hợp nhất tiêu chuẩn. Một data.table hợp nhất như DT [DT] nên được nhanh hơn, phải không? – uuazed

11

Câu hỏi hay. Câu trả lời này chỉ là một taster thực sự bên cạnh câu trả lời của Ricardo.

Lý tưởng nhất là chúng ta muốn tránh sự tham gia của chính người Descartes lớn cho hiệu quả. Thật không may là range joins (FR#203) chưa được triển khai. Trong thời gian chờ đợi, hãy sử dụng v1.8 mới nhất.7 (chưa được kiểm tra):

setkey(DT,n,t) 
DT[,from:=DT[.(n,t-10),which=TRUE,roll=-Inf,rollends=TRUE]] 
DT[,to:=DT[.(n,t+10),which=TRUE,roll=+Inf,rollends=TRUE]] 
DT[,foo:=0L] 
for (i in 1:nrow(DT)) { 
    s = seq.int(DT$from[i],DT$to[i]) 
    set(DT, i, "foo", DT[,sum(v[s]*abs(t[s]-t[i]))]) 
} 

Khi FR # 203 được thực hiện, logic trên sẽ được xây dựng trong, và nó sẽ trở thành một lót:

setkey(DT,n,t) 
DT[.(n,.(t-10,t+10),t), foo:=sum(v*abs(t-i.t))] 

Cột thứ hai của i bảng có là cột 2 cột (biểu thị một số giữa số tham gia). Điều đó phải nhanh vì, như thường lệ, j sẽ được đánh giá cho mỗi hàng i mà không cần phải tạo một bảng tự tham gia rất lớn.

Đó là suy nghĩ hiện tại.

+0

Tôi sẽ thử rằng một khi data.table v1.8.7 được phát hành – uuazed

+0

Có FR # 203 đang được triển khai chưa? Tôi đã đưa ra câu hỏi sau trong SO và tôi nghĩ rằng nó sẽ được hưởng lợi từ đề xuất bạn đã thực hiện. http://stackoverflow.com/questions/29100911/r-data-table-self-join-on-condition-using-a-matrix – Picarus

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