2014-09-29 88 views
3

這與R- view all the columns names with any NA爲什麼data.table在這個例子中如此緩慢R中

我比較data.frame和data.table版本,發現data.table是慢10倍。這與data.table中的大多數代碼相比,實際上要比data.frame版本快得多。

set.seed(49) 
df1 <- as.data.frame(matrix(sample(c(NA,1:200), 1e4*5000, replace=TRUE), ncol=5000)) 

library(microbenchmark) 
f1 <- function() {names(df1)[sapply(df1, function(x) any(is.na(x)))]} 
f2 <- function() { setDT(df1); names(df1)[df1[,sapply(.SD, function(x) any(is.na(x))),]] } 
microbenchmark(f1(), f2(), unit="relative") 
Unit: relative 
expr  min  lq median  uq  max neval 
f1() 1.00000 1.00000 1.000000 1.000000 1.000000 100 
f2() 10.56342 10.20919 9.996129 9.967001 7.199539 100 

setDT事先:

set.seed(49) 
df1 <- as.data.frame(matrix(sample(c(NA,1:200), 1e4*5000, replace=TRUE), ncol=5000)) 
setDT(df1) 

library(microbenchmark) 
f1 <- function() {names(df1)[sapply(df1, function(x) any(is.na(x)))]} 
f2 <- function() {names(df1)[df1[,sapply(.SD, function(x) any(is.na(x))),]] } 
microbenchmark(f1(), f2(), unit="relative") 
Unit: relative 
expr  min  lq median  uq  max neval 
f1() 1.00000 1.00000 1.00000 1.00000 1.000000 100 
f2() 10.64642 10.77769 10.79191 10.77536 7.716308 100 

可能是什麼原因?

+0

作爲小費,你可以直接調用'is.na(DT)'在data.table/data.frame權。 – 2014-09-29 04:52:12

+1

@RicardoSaporta - 但這會創建一個與data.table – mnel 2014-09-29 05:06:52

+0

@mnel相同的矩陣,是的,矩陣上的colSums是faaaaast :) – 2014-09-29 05:15:23

回答

8

data.table在這種情況下不會提供任何神奇的加速。

# Unit: relative 
# expr  min  lq median  uq  max neval 
# f1() 1.000000 1.000000 1.000000 1.000000 1.000000 10 
# f2() 8.350364 8.146091 6.966839 5.766292 4.595742 10 

爲了便於比較,在我的機器上,時間在上面。

在「data.frame」方法中,您實際上只是使用data.frame是列表並遍歷列表的事實。

data.table方法中,您正在做同樣的事情,但通過使用.SD,您正在強制複製整個data.table(以使數據可用)。這是data.table巧妙地將您需要的數據複製到j表達式中的結果。通過使用.SD,您正在複製所有內容。

提高性能的最佳方法是使用anyNA這是一種更快(Primitive)的方法來查找任何NA值(一旦它找到第一個,而不是創建整個is.na載體,然後掃描任何真實值)

對於更定製的測試,你可能需要寫(RCPP糖風格)功能

你還會發現,unlist(lapply(...))一般會快於sapply

f3 <- function() names(df1)[unlist(lapply(df1, anyNA))] 
f4 <- function() names(df1)[sapply(df1, anyNA)] 
microbenchmark(f1(), f2(),f3() ,f4(),unit="relative",times=10) 

# Unit: relative 
# expr  min  lq median  uq  max neval 
# f1() 10.988322 11.200684 11.048738 10.697663 13.110318 10 
# f2() 92.915256 92.000781 91.000729 88.421331 103.627198 10 
# f3() 1.000000 1.000000 1.000000 1.000000 1.000000 10 
# f4() 1.591301 1.663222 1.650136 1.652701 2.133943 10 

,並與馬丁摩根的建議

f3.1 <- function() names(df1)[unlist(lapply(df1, anyNA),use.names=FALSE)] 

microbenchmark(f1(), f2(),f3() ,f3.1(),f4(),unit="relative",times=10) 
# Unit: relative 
# expr  min   lq median   uq  max neval 
# f1() 18.125295 17.902925 18.17514 18.410682 9.2177043 10 
# f2() 147.914282 145.805223 145.05835 143.630573 81.9495460 10 
# f3() 1.608688 1.623366 1.66078 1.648530 0.8257108 10 
# f3.1() 1.000000 1.000000 1.00000 1.000000 1.0000000 10 
# f4() 2.555962 2.553768 2.60892 2.646575 1.3510561 10 
+0

很好澄清。那麼在哪種情況下應該使用data.table? (如果回答太長,請給出鏈接) – rnso 2014-09-29 01:55:57

+4

@rnso閱讀'data.table'小插曲的介紹。 – mnel 2014-09-29 01:57:49

+1

對f3()的輕微改進是'unlist(lapply(df1,anyNA),use.names = FALSE)' – 2014-09-29 02:48:58

相關問題