我比较了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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
可能是什么原因?
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
Run Code Online (Sandbox Code Playgroud)
为了比较,在我的机器上,时间在上面.
在"data.frame"方法中,您实际上只是使用a data.frame是列表并迭代列表的事实.
在该data.table方法中,您正在执行相同的操作,但是通过使用.SD,您将强制复制整个data.table(以使数据可用).这是data.table巧妙地将您需要的数据复制到j表达式中的结果.通过使用.SD,您将复制所有内容.
提高性能的最佳方法是使用anyNA更快(原始)方法来查找任何NA值(一旦找到第一个就会停止,而不是创建整个is.na向量,然后扫描任何TRUE值)
对于更定制的测试,您可能需要编写(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
Run Code Online (Sandbox Code Playgroud)
以及马丁摩根的建议
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
662 次 |
| 最近记录: |