Rcpp 中如何使用 noNA?
How is noNA used in Rcpp?
Hadley Wickham 在他的 "Advanced R" 书中说:“noNA(x)
断言向量 x
不包含任何缺失值。”但是我仍然不知道如何使用它。我做不到
if (noNA(x))
do this
那么我应该如何使用它呢?
许多 Rcpp 糖表达式是通过模板 classes 实现的,这些模板具有针对输入对象 已知 没有缺失值的情况的专门化,从而允许底层算法避免执行处理 NA
值的额外工作(例如调用 is_na
)。这是唯一可能的,因为 VectorBase
class 有一个布尔参数,指示基础对象 是否可以 (可以,但不一定 确实 ) 是否有 NA
值。
noNA
returns (when called on a VectorBase
object) an instance of the Nona
模板 class。请注意 Nona
本身派生自
Rcpp::VectorBase<RTYPE, false, Nona<RTYPE,NA,VECTOR>>
// ^^^^^
意味着返回的对象使用本质上说 "you can assume that this data is free of NA
values" 的信息进行编码。
例如,Rcpp::sum
是通过 Rcpp::sugar
命名空间中的 Sum
class 实现的。在 default case 中,我们看到有额外的工作来管理缺失值的可能性:
STORAGE get() const {
STORAGE result = 0 ;
R_xlen_t n = object.size() ;
STORAGE current ;
for( R_xlen_t i=0; i<n; i++){
current = object[i] ;
if( Rcpp::traits::is_na<RTYPE>(current) ) // here
return Rcpp::traits::get_na<RTYPE>() ; // here
result += current ;
}
return result ;
}
另一方面,对于输入没有缺失值的情况,也有a specialization,算法做的工作较少:
STORAGE get() const {
STORAGE result = 0 ;
R_xlen_t n = object.size() ;
for( R_xlen_t i=0; i<n; i++){
result += object[i] ;
}
return result ;
}
为了回答您 "how do I apply this in practice?" 的问题,这里有一个例子:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
int Sum(IntegerVector x) {
return sum(x);
}
// [[Rcpp::export]]
int SumNoNA(IntegerVector x) {
return sum(noNA(x));
}
对这两个函数进行基准测试,
set.seed(123)
x <- as.integer(rpois(1e6, 25))
all.equal(Sum(x), SumNoNA(x))
# [1] TRUE
microbenchmark::microbenchmark(
Sum(x),
SumNoNA(x),
times = 500L
)
# Unit: microseconds
# expr min lq mean median uq max neval
# Sum(x) 577.386 664.620 701.2422 677.1640 731.7090 1214.447 500
# SumNoNA(x) 454.990 517.709 556.5783 535.1935 582.7065 1138.426 500
noNA
版本确实更快。
Hadley Wickham 在他的 "Advanced R" 书中说:“noNA(x)
断言向量 x
不包含任何缺失值。”但是我仍然不知道如何使用它。我做不到
if (noNA(x))
do this
那么我应该如何使用它呢?
许多 Rcpp 糖表达式是通过模板 classes 实现的,这些模板具有针对输入对象 已知 没有缺失值的情况的专门化,从而允许底层算法避免执行处理 NA
值的额外工作(例如调用 is_na
)。这是唯一可能的,因为 VectorBase
class 有一个布尔参数,指示基础对象 是否可以 (可以,但不一定 确实 ) 是否有 NA
值。
noNA
returns (when called on a VectorBase
object) an instance of the Nona
模板 class。请注意 Nona
本身派生自
Rcpp::VectorBase<RTYPE, false, Nona<RTYPE,NA,VECTOR>>
// ^^^^^
意味着返回的对象使用本质上说 "you can assume that this data is free of NA
values" 的信息进行编码。
例如,Rcpp::sum
是通过 Rcpp::sugar
命名空间中的 Sum
class 实现的。在 default case 中,我们看到有额外的工作来管理缺失值的可能性:
STORAGE get() const {
STORAGE result = 0 ;
R_xlen_t n = object.size() ;
STORAGE current ;
for( R_xlen_t i=0; i<n; i++){
current = object[i] ;
if( Rcpp::traits::is_na<RTYPE>(current) ) // here
return Rcpp::traits::get_na<RTYPE>() ; // here
result += current ;
}
return result ;
}
另一方面,对于输入没有缺失值的情况,也有a specialization,算法做的工作较少:
STORAGE get() const {
STORAGE result = 0 ;
R_xlen_t n = object.size() ;
for( R_xlen_t i=0; i<n; i++){
result += object[i] ;
}
return result ;
}
为了回答您 "how do I apply this in practice?" 的问题,这里有一个例子:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
int Sum(IntegerVector x) {
return sum(x);
}
// [[Rcpp::export]]
int SumNoNA(IntegerVector x) {
return sum(noNA(x));
}
对这两个函数进行基准测试,
set.seed(123)
x <- as.integer(rpois(1e6, 25))
all.equal(Sum(x), SumNoNA(x))
# [1] TRUE
microbenchmark::microbenchmark(
Sum(x),
SumNoNA(x),
times = 500L
)
# Unit: microseconds
# expr min lq mean median uq max neval
# Sum(x) 577.386 664.620 701.2422 677.1640 731.7090 1214.447 500
# SumNoNA(x) 454.990 517.709 556.5783 535.1935 582.7065 1138.426 500
noNA
版本确实更快。