2014-01-29 46 views
3

我有以下數據:爲什麼數據框列與矩陣列相比工作更快?

height = 1:10000000 
length = -(1:10000000) 
body_dim = data.frame(height,length) 
body_dim_mat = as.matrix(body_dim) 

爲什麼which()運行速度更快的數據幀相比矩陣?

> microbenchmark(body_dim[which(body_dim$height==50000),"length"]) 
Unit: milliseconds 
               expr  min  lq median  uq  max neval 
body_dim[which(body_dim$height == 50000), "length"] 124.4586 125.1625 125.9281 127.9496 284.9824 100 

> microbenchmark(body_dim_mat[which(body_dim_mat[,1] == 50000),2]) 
Unit: milliseconds 
               expr  min  lq median  uq  max neval 
body_dim_mat[which(body_dim_mat[, 1] == 50000), 2] 251.1282 252.4457 389.7251 400.313 1004.25 100 

回答

5

data.frame是一個列表,列是一個簡單的向量,很容易從列表中提取。矩陣是具有維度屬性的矢量。屬於一列的哪些值必須從維度計算。這種效應子集,它在您的基準包括:

library(microbenchmark) 

set.seed(42) 
m <- matrix(rnorm(1e5), ncol=10) 
DF <- as.data.frame(m) 

microbenchmark(m[,1], DF[,1], DF$V1) 
#Unit: microseconds 
# expr min  lq median  uq  max neval 
# m[, 1] 80.997 82.536 84.230 87.1560 1147.795 100 
#DF[, 1] 15.399 16.939 20.789 22.6365 100.090 100 
# DF$V1 1.849 2.772 3.389 4.3130 90.235 100 

然而,帶回家的消息是不是你應該總是用data.frame。因爲如果你做的子集,其結果爲不是矢量:

microbenchmark(m[1:10, 1:10], DF[1:10, 1:10]) 
# Unit: microseconds 
#   expr  min  lq median  uq  max neval 
# m[1:10, 1:10] 1.233 1.8490 3.2345 3.697 11.087 100 
# DF[1:10, 1:10] 211.267 219.7355 228.2050 252.226 1265.131 100 
+0

+1即使'DF [[1]]'比'DF $ V1'慢。 –

+0

有趣的附加測試:採用'm [1:1e4]',因爲'R'在內部將矩陣看作帶有dim屬性的向量。結果只是比'm [,1]'稍快。 –

1

看來,問題是which()之前,data.frame列的子集簡直是更快,如果相對於整個矩陣的子集:

microbenchmark(body_dim$height==50000) 
# Unit: milliseconds 
#      expr  min  lq median  uq  max neval 
# body_dim$height == 50000 138.2619 148.5132 170.1895 170.8909 249.4592 100 

microbenchmark(body_dim_mat[,1]==50000) 
# Unit: milliseconds 
#      expr  min  lq median  uq  max neval 
# body_dim_mat[, 1] == 50000 299.599 308.6066 310.9036 354.4641 432.7833 100 

順便說一句,這種情況是data.table可以照:

require(data.table) 
dt <- data.table(body_dim, key="height") 
microbenchmark(dt[J(50000)]$length, unit="ms") 
# Unit: milliseconds 
#     expr  min  lq median  uq  max neval 
# dt[J(50000)]$length 0.96637 0.97908 0.989772 1.025257 2.588402 100 
+0

您data.table查詢的模擬,對於data.frame DF,可能是'DF $長度[50000]'(data.table慢20倍);子集比較可能是dt [height == 50000] vs df [df $ height == 50000,](data.table 2x更快) –

+0

@MartinMorgan,你是對的。我已更新該帖子。 – redmode

相關問題