2015-06-03 12 views
10

Tôi đã nhận thấy rằng cbind mất nhiều thời gian hơn đáng kể so với rbind cho data.tables. Lý do cho điều này là gì?cbind vs rbind với data.table

> dt <- as.data.table(mtcars)        
> new.dt <- copy(dt)          
> timeit({for (i in 1:100) dt.new <- rbind(dt.new, dt)}) 
    user system elapsed         
    0.237 0.012 0.253         
> new.dt <- copy(dt)          
> timeit({for (i in 1:100) dt.new <- cbind(dt.new, dt)}) 
    user system elapsed         
14.795 0.090 14.912  

timeit <- function(expr) 
{ 
    ptm <- proc.time() 
    expr 
    proc.time() - ptm 
} 
+0

Tôi không biết bên trong của data.table, nhưng tôi đoán thêm kỷ lục mới (hàng) là dễ dàng hơn hơn là tái cơ cấu bảng với các biến mới (cột). – zx8754

+0

@ zx8754 Có Tôi đồng ý với sự nghi ngờ của tôi nữa, tò mò về cổ chai cụ thể là gì. Có lẽ đó là sự phân bổ bộ nhớ, có thể yêu cầu bộ nhớ lớn hơn, hy vọng một người nào đó hài lòng với gritty nitty của gói có thể làm sáng tỏ .. – andrew

+3

Trừ khi tôi bị nhầm lẫn, gọi 'rbind' trên' data.table' sẽ gửi 'rbind.data. table', gọi hàm 'data.table'' rbindlist'- được triển khai trong C và rất nhanh. Xem câu trả lời của @ Arun [tại đây] (http://stackoverflow.com/questions/15673550/why-is-rbindlist-better-than-rbind). Trên hết, hầu như chắc chắn có sự khác biệt cơ bản giữa sửa đổi cột khôn ngoan và sửa đổi hàng khôn ngoan (liên quan đến cách đối tượng được lưu trữ trong bộ nhớ), vì vậy đây không thực sự là so sánh "táo-to-táo". Nhiều khả năng đây là lý do tại sao 'data.table' thực hiện': = 'để sửa đổi các cột một cách hiệu quả. – nrussell

Trả lời

8

Cuối cùng tôi nghĩ đâu này đi xuống đến alloc.col bị chậm do một vòng lặp mà nó loại bỏ thuộc tính khác nhau từ các cột. Tôi không hoàn toàn chắc chắn lý do tại sao nó được thực hiện, có lẽ Arun hoặc Matt có thể giải thích.

Như bạn thấy dưới đây, các hoạt động cơ bản cho cbind là nhanh hơn nhiều so với rbind:

cbind.dt.simple = function(...) { 
    x = c(...) 
    setattr(x, "class", c("data.table", "data.frame")) 
    ans = .Call(data.table:::Calloccolwrapper, x, max(100L, ncol(x) + 64L), FALSE) 
    .Call(data.table:::Csetnamed, ans, 0L) 
} 

library(microbenchmark) 

microbenchmark(rbind(dt, dt), cbind(dt, dt), cbind.dt.simple(dt, dt)) 
#Unit: microseconds 
#     expr  min  lq  mean median  uq  max neval 
#   rbind(dt, dt) 785.318 996.5045 1665.1762 1234.4045 1520.3830 21327.426 100 
#   cbind(dt, dt) 2350.275 3022.5685 3885.0014 3533.7595 4093.1975 21606.895 100 
# cbind.dt.simple(dt, dt) 74.125 116.5290 168.5101 141.9055 180.3035 1903.526 100 
+0

Tôi thấy rằng 'cbind2 <- function (...) (setattr (do.call (c, list (...))," class ", c (" data.table "," data.frame "))) 'thậm chí còn nhanh hơn. Tôi không thực sự làm theo những gì đang xảy ra với các hàm 'C *', vì vậy có lẽ tôi đang thiếu một cái gì đó. 'all.equal (cbind.dt.simple (dt, dt), cbind2 (dt, dt)) # TRUE' – Frank

+0

@Bên phải, nhưng để lại một số thứ chưa hoàn thành, hãy thử ví dụ: 'cbind2 (dt, dt) [, newcol: = 5]' – eddi

+0

Ah, tôi hiểu rồi. Ý tưởng tiếp theo của tôi 'setDT (setattr (do.call (c, list (...))," class ", c (" data.frame ")))' là cách chậm hơn. Oh, chỉ đơn giản là 'setDT (do.call (c, list (...)))' hoạt động, nhưng là cùng tốc độ (chậm). – Frank

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