2015-05-28 27 views
7

Giả sử I cần để lặp qua các hàng trong một khung dữ liệu vì một lý do nào đó.Lặp qua các hàng trong một khung dữ liệu

tôi tạo ra một data.frame đơn giản

df <- data.frame(id = sample(1e6, 1e7, replace = TRUE)) 

Dường như f2 đó là chậm hơn nhiều so với f1, trong khi tôi mong đợi họ là tương đương.

f1 <- function(v){ 
     for (obs in 1:(1e6)){ 
      a <- v[obs] 
     } 
     a 
    } 
system.time(f1(df$id)) 

f2 <- function(){ 
     for (obs in 1:(1e6)){ 
      a <- df$id[obs] 
     } 
    a 
    } 
system.time(f2()) 

Bạn có biết tại sao không? Họ có sử dụng chính xác cùng một lượng bộ nhớ không?

+3

Với chức năng đầu tiên bạn sử dụng '$ 'một lần, trong hàm thứ hai bạn sử dụng nó 1e6 lần. '$' không phải là hàm subsetting nhanh nhất. – Roland

+0

Điều làm tôi bất ngờ là 'f1' nhanh gấp hai lần' f3 <- hàm (v) cho (a in v) {NULL}; system.time (f3 (df $ id)) '. Ồ, tôi hiểu: '1e6' không phải là chiều dài của vectơ. 'system.time (f3 (df $ id [1: 1e6]))' là nhanh. – Frank

Trả lời

6

Nếu bạn thay vì viết timings của bạn như thế này và nhận ra rằng df$x thực sự là một lời gọi hàm (để `$`(df,x)) những bí ẩn biến mất:

system.time(for(i in 1:1e6) df$x) 
# user system elapsed 
# 8.52 0.00 8.53 
system.time(for(i in 1) df$x) 
# user system elapsed 
#  0  0  0 
2

Trong f1, bạn bỏ qua toàn bộ khung dữ liệu bằng cách chỉ truyền vector cho hàm của bạn. Vì vậy, mã của bạn về cơ bản là "Tôi có một vectơ! Đây là phần tử đầu tiên. Đây là phần tử thứ hai. Đây là phần tử thứ hai ..."

Ngược lại, trong f2, bạn cung cấp cho nó toàn bộ khung dữ liệu lấy từng phần tử của một cột đơn mỗi lần. Vì vậy, mã của bạn là "Tôi có một khung dữ liệu. Đây là phần tử đầu tiên của cột ID. Đây là phần tử thứ hai của cột ID. Đây là phần tử thứ hai ..."

Sẽ nhanh hơn nhiều nếu bạn trích xuất cấu trúc dữ liệu đơn giản (vector) một lần, và sau đó chỉ có thể làm việc với điều đó, thay vì trích xuất liên tục cấu trúc đơn giản từ đối tượng lớn hơn.

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