检测向量NA
的R值是否至少为1的最快方法是什么?我一直在使用:
sum( is.na( data ) ) > 0
但这需要检查每个元素,强制和求和函数。
Answers:
从R 3.1.0开始anyNA()
是执行此操作的方法。在原子向量上,它将在第一个NA之后停止,而不是像那样经过整个向量any(is.na())
。另外,这避免了创建中间逻辑向量,is.na
该中间逻辑向量被立即丢弃。借用乔兰的例子:
x <- y <- runif(1e7)
x[1e4] <- NA
y[1e7] <- NA
microbenchmark::microbenchmark(any(is.na(x)), anyNA(x), any(is.na(y)), anyNA(y), times=10)
# Unit: microseconds
# expr min lq mean median uq
# any(is.na(x)) 13444.674 13509.454 21191.9025 13639.3065 13917.592
# anyNA(x) 6.840 13.187 13.5283 14.1705 14.774
# any(is.na(y)) 165030.942 168258.159 178954.6499 169966.1440 197591.168
# anyNA(y) 7193.784 7285.107 7694.1785 7497.9265 7865.064
请注意,即使我们修改了向量的最后一个值,它的速度也显着提高。这部分是由于避免了中间逻辑向量。
我在想:
any(is.na(data))
应该稍微快一点。
any()
发现FALSE后停止,我不会感到惊讶。无论如何,any(...)
变得太慢以至于无法处理的那一刻可能已经超过了RAM耗尽的那一刻。
all()
顺便说一句,还有功能可以正常使用。可能很有用(不是针对此问题,而是一般而言)。
any
并all
在到达aTRUE
或a时停止迭代FALSE
;看到checkValues
在svn.r-project.org/R/trunk/src/main/logic.c ; 在is.na
仍然强求一切虽然。
is.na(data)
首先计算出来的成本,对于所有数据元素,无论早期是否事实上是NA。我们使用Rcpp糖版本is.na()
(在C ++中实现,可通过Rcpp使用)进行了改进。看到我的答案更多。
我们在一些Rcpp演示文稿中提到了这一点,实际上还有一些基准测试,这些基准显示出与R解决方案相比,使用Rcpp的嵌入式C ++的收益很大
向量化的R解决方案仍会计算向量表达式的每个元素
如果您的目标是仅仅满足any()
,那么您可以在第一个匹配项后中止-这就是我们的Rcpp糖(本质上:使C ++表达式看起来更像R表达式的一些C ++模板魔术,更多信息请参见此插图) 。
因此,通过获得已编译的专用解决方案来工作,我们确实获得了快速的解决方案。我应该补充一点,虽然我没有将其与此处的SO问题所提供的解决方案进行比较,但我对性能相当有信心。
编辑并且Rcpp软件包在目录中包含示例sugarPerformance
。它比'R-computes-full-vector-expression'的'sugar-can-abort-soon'增加了几千any()
,但我应该补充一点,这种情况只涉及is.na()
一个简单的布尔表达式。
any
计算每个元素,而不是首先停止计算?
any
不知道里面有什么。它只是评估其参数(所有参数),然后对其应用any
,它确实在第一个停止FALSE
,但仅在评估其所有参数之后才停止。Dirk的Rcpp糖版本any
(据我所知)确实知道如何按术语(至少对于某些表达式而言)来评估术语中的内容,因此它可以依次评估每个术语是否为TRUE / FALSE。
可以编写一个for循环在NA处停止,但是system.time取决于NA所在的位置...(如果不存在,则需要looooong)
set.seed(1234)
x <- sample(c(1:5, NA), 100000000, replace = TRUE)
nacount <- function(x){
for(i in 1:length(x)){
if(is.na(x[i])) {
print(TRUE)
break}
}}
system.time(
nacount(x)
)
[1] TRUE
User System verstrichen
0.14 0.04 0.18
system.time(
any(is.na(x))
)
User System verstrichen
0.28 0.08 0.37
system.time(
sum(is.na(x)) > 0
)
User System verstrichen
0.45 0.07 0.53
这是我(慢速)机器上实际的时间,用于到目前为止讨论的各种方法:
x <- runif(1e7)
x[1e4] <- NA
system.time(sum(is.na(x)) > 0)
> system.time(sum(is.na(x)) > 0)
user system elapsed
0.065 0.001 0.065
system.time(any(is.na(x)))
> system.time(any(is.na(x)))
user system elapsed
0.035 0.000 0.034
system.time(match(NA,x))
> system.time(match(NA,x))
user system elapsed
1.824 0.112 1.918
system.time(NA %in% x)
> system.time(NA %in% x)
user system elapsed
1.828 0.115 1.925
system.time(which(is.na(x) == TRUE))
> system.time(which(is.na(x) == TRUE))
user system elapsed
0.099 0.029 0.127
match
和%in%
相似并不奇怪,因为它%in%
是使用实现的match
。
你可以试试:
d <- c(1,2,3,NA,5,3)
which(is.na(d) == TRUE, arr.ind=TRUE)