这与R- view all the columns names with any NA
有关我比较了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 :(得分: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
这是一种更快(原始)的方法来查找任何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
以及Martin Morgan的建议
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