2013-06-02 21 views
16

Trong công việc của tôi, tôi sử dụng để có nhiều bảng (chi tiết khách hàng, hồ sơ giao dịch, v.v.). Là một số trong số chúng rất lớn (hàng triệu hàng), gần đây tôi đã chuyển sang gói data.table (nhờ Matthew). Tuy nhiên, một số trong số đó là khá nhỏ (vài trăm hàng và 4/5 cột) và được gọi nhiều lần. Do đó, tôi bắt đầu suy nghĩ về chi phí [.data.table trong truy xuất dữ liệu thay vì đặt giá trị (như đã mô tả rõ ràng trong ?set, ở đâu, bất kể kích thước của bảng một mục được đặt trong khoảng 2 micro giây (tùy thuộc vào cpu).Thời gian trong việc nhận các elemets đơn lẻ từ các đối tượng data.table và data.frame

Tuy nhiên, dường như không tồn tại tương đương với set để nhận giá trị từ data.table biết chính xác hàng và cột. Một loại có thể lặp lại[.data.table.

library(data.table) 
library(microbenchmark) 

m = matrix(1,nrow=100000,ncol=100) 
DF = as.data.frame(m) 
DT = as.data.table(m) # same data used in ?set 

> microbenchmark(DF[3450,1] , DT[3450, V1], times=1000) # much more overhead in DT 

Unit: microseconds 
expr  min  lq median  uq  max neval 
DF[3450, 1] 32.745 36.166 40.5645 43.497 193.533 1000 
DT[3450, V1] 788.791 803.453 813.2270 832.287 5826.982 1000 

> microbenchmark(DF$V1[3450], DT[3450, 1, with=F], times=1000) # using atomic vector and 
                   # removing part of DT overhead 
Unit: microseconds            
expr  min  lq median  uq  max neval 
DF$V1[3450] 2.933 3.910 5.865 6.354 36.166 1000 
DT[3450, 1, with = F] 297.629 303.494 305.938 309.359 1878.632 1000 

> microbenchmark(DF$V1[3450], DT$V1[3450], times=1000) # using only atomic vectors 
Unit: microseconds 
     expr min lq median uq max neval 
DF$V1[3450] 2.933 2.933 3.421 3.422 40.565 1000 # DF seems still a bit faster (23%) 
DT$V1[3450] 3.910 3.911 4.399 4.399 16.128 1000 

Phương pháp cuối cùng thực sự là phương pháp tốt nhất để nhanh chóng truy lục một phần tử một vài lần. Tuy nhiên, set thậm chí còn nhanh hơn

> microbenchmark(set(DT,1L,1L,5L), times=1000) 
Unit: microseconds 
       expr min lq median uq max neval 
set(DT, 1L, 1L, 5L) 1.955 1.956 2.444 2.444 24.926 1000 

câu hỏi là: nếu chúng ta có thể set một giá trị trong 2,444 micro nên không thể thực hiện để có được một giá trị trong một khoảng nhỏ hơn (hoặc ít nhất là tương tự) của thời gian? Cảm ơn.

EDIT: bổ sung thêm hai lựa chọn như đề xuất:

> microbenchmark(`[.data.frame`(DT,3450,1), DT[["V1"]][3450], times=1000) 
Unit: microseconds 
         expr min  lq median  uq  max neval 
`[.data.frame`(DT, 3450, 1) 46.428 47.895 48.383 48.872 2165.509 1000 
      DT[["V1"]][3450] 20.038 21.504 23.459 24.437 116.316 1000 

mà tiếc là không phải là nhanh hơn so với những nỗ lực trước đó.

+0

Tôi đồng ý với câu hỏi của bạn rằng chi phí có thể/không nên quá nhiều. Tuy nhiên, để thay đổi, làm thế nào về 'DT [[" V1 "]] [3450]' ?? – Arun

+0

Hoặc sử dụng data.frame subsetting: ''[.data.frame' (DT, 3450,1)' (''' được cho là backticks.) – Roland

+2

Nhưng tôi là một chút hoài nghi về nhu cầu nhận thức của bạn cho subsetting lặp đi lặp lại. Thường thì điều này có nghĩa là bạn có thể tối ưu hóa bằng cách thay đổi thuật toán của mình. – Roland

Trả lời

7

Nhờ @hadley chúng tôi có giải pháp!

> microbenchmark(DT$V1[3450], set(DT,1L,1L,5L), .subset2(DT, "V1")[3450], times=1000, unit="us") 
Unit: microseconds 
        expr min lq median uq max neval 
       DT$V1[3450] 2.566 3.208 3.208 3.528 27.582 1000 
     set(DT, 1L, 1L, 5L) 1.604 1.925 1.925 2.246 15.074 1000 
.subset2(DT, "V1")[3450] 0.000 0.321 0.322 0.642 8.339 1000 
Các vấn đề liên quan