在 Rcpp 中检查向量的 Null 和 NA
Checking Null and NA of a vector in Rcpp
我正在尝试根据第二个可空向量 (r
) 的值是否为 NA
来计算向量 (y
) 的总和。如果第二个向量 r
为 NULL,则应将 y
的所有值相加。如果 r
的所有元素都是 NA
,函数应该 return NA。请参阅文末以获得所需的输出。
我首先尝试了以下代码:
library(Rcpp)
cppFunction('double foo(NumericVector y, Rcpp::Nullable<Rcpp::IntegerVector> r = R_NilValue) {
double output = 0;
bool return_na = !Rf_isNull(r);
int y_count = y.size();
for (int i = 0; i < y_count; i++) {
if (Rf_isNull(r) || !R_IsNA(r[i])) {
//// if (Rf_isNull(r) || !R_IsNA(as<IntegerVector>(r)[i])) {
if (!Rf_isNull(r))
Rcout << R_IsNA(as<IntegerVector>(r)[i]) << " - "<< as<IntegerVector>(r)[i] << std::endl;
output = output + y[i];
return_na = false;
}
}
if (return_na)
return NA_REAL;
return output;
}')
这给了我以下错误:
error: invalid use of incomplete type 'struct SEXPREC'
if (Rf_isNull(r) || !R_IsNA(r[i])) {
^
为了解决,我改用了if (Rf_isNull(r) || !R_IsNA(as<IntegerVector>(r)[i])) {
。但是这一次,当转换为整数向量时,NA
值被转换为数字并且 R_IsNA()
测试给出了误报。
这是我想要的预期输出。
foo(1:4, NULL) # <- This should return 10 = 1 + 2 + 3 + 4
foo(1:4, c(1, 1, 1, 1)) # <- This should return 10 = 1 + 2 + 3 + 4
foo(1:4, c(1, 1, NA, 1)) # <- This should return 7 = 1 + 2 + 4
foo(1:4, c(NA, NA, NA, NA)) # <- This should return NA
如何获得我想要的功能? (这个例子是简化的,我对 sum 函数不是特别感兴趣。相反,我有兴趣同时检查 NA
和 NULL
,如示例中给出的那样。)
三点建议:
- 使用 Rcpp 代替 R 的 C API。
- Return早于
r
是NULL
。
- 在循环输入向量之前创建
LogicalVector
。
#include <Rcpp.h>
// [[Rcpp::export]]
double foo(Rcpp::NumericVector y, Rcpp::Nullable<Rcpp::IntegerVector> r = R_NilValue) {
if (r.isNull())
return Rcpp::sum(y);
Rcpp::LogicalVector mask = Rcpp::is_na(r.as());
if (Rcpp::is_true(Rcpp::all(mask)))
return NA_REAL;
double output = 0.0;
int y_count = y.size();
for (int i = 0; i < y_count; ++i) {
if (!mask[i]) {
output += y[i];
}
}
return output;
}
/***R
foo(1:4, NULL) # <- This should return 10 = 1 + 2 + 3 + 4
foo(1:4, c(1, 1, 1, 1)) # <- This should return 10 = 1 + 2 + 3 + 4
foo(1:4, c(1, 1, NA, 1)) # <- This should return 7 = 1 + 2 + 4
foo(1:4, c(NA, NA, NA, NA)) # <- This should return NA
*/
结果:
> Rcpp::sourceCpp('60569482.cpp')
> foo(1:4, NULL) # <- This should return 10 = 1 + 2 + 3 + 4
[1] 10
> foo(1:4, c(1, 1, 1, 1)) # <- This should return 10 = 1 + 2 + 3 + 4
[1] 10
> foo(1:4, c(1, 1, NA, 1)) # <- This should return 7 = 1 + 2 + 4
[1] 7
> foo(1:4, c(NA, NA, NA, NA)) # <- This should return NA
[1] NA
进一步建议:
- 使用掩码进行子设置
y
。
#include <Rcpp.h>
// [[Rcpp::export]]
double foo(Rcpp::NumericVector y, Rcpp::Nullable<Rcpp::IntegerVector> r = R_NilValue) {
if (r.isNull())
return Rcpp::sum(y);
Rcpp::LogicalVector mask = Rcpp::is_na(r.as());
if (Rcpp::is_true(Rcpp::all(mask)))
return NA_REAL;
Rcpp::NumericVector tmp = y[!mask];
return Rcpp::sum(tmp);
}
我正在尝试根据第二个可空向量 (r
) 的值是否为 NA
来计算向量 (y
) 的总和。如果第二个向量 r
为 NULL,则应将 y
的所有值相加。如果 r
的所有元素都是 NA
,函数应该 return NA。请参阅文末以获得所需的输出。
我首先尝试了以下代码:
library(Rcpp)
cppFunction('double foo(NumericVector y, Rcpp::Nullable<Rcpp::IntegerVector> r = R_NilValue) {
double output = 0;
bool return_na = !Rf_isNull(r);
int y_count = y.size();
for (int i = 0; i < y_count; i++) {
if (Rf_isNull(r) || !R_IsNA(r[i])) {
//// if (Rf_isNull(r) || !R_IsNA(as<IntegerVector>(r)[i])) {
if (!Rf_isNull(r))
Rcout << R_IsNA(as<IntegerVector>(r)[i]) << " - "<< as<IntegerVector>(r)[i] << std::endl;
output = output + y[i];
return_na = false;
}
}
if (return_na)
return NA_REAL;
return output;
}')
这给了我以下错误:
error: invalid use of incomplete type 'struct SEXPREC'
if (Rf_isNull(r) || !R_IsNA(r[i])) {
^
为了解决,我改用了if (Rf_isNull(r) || !R_IsNA(as<IntegerVector>(r)[i])) {
。但是这一次,当转换为整数向量时,NA
值被转换为数字并且 R_IsNA()
测试给出了误报。
这是我想要的预期输出。
foo(1:4, NULL) # <- This should return 10 = 1 + 2 + 3 + 4
foo(1:4, c(1, 1, 1, 1)) # <- This should return 10 = 1 + 2 + 3 + 4
foo(1:4, c(1, 1, NA, 1)) # <- This should return 7 = 1 + 2 + 4
foo(1:4, c(NA, NA, NA, NA)) # <- This should return NA
如何获得我想要的功能? (这个例子是简化的,我对 sum 函数不是特别感兴趣。相反,我有兴趣同时检查 NA
和 NULL
,如示例中给出的那样。)
三点建议:
- 使用 Rcpp 代替 R 的 C API。
- Return早于
r
是NULL
。 - 在循环输入向量之前创建
LogicalVector
。
#include <Rcpp.h>
// [[Rcpp::export]]
double foo(Rcpp::NumericVector y, Rcpp::Nullable<Rcpp::IntegerVector> r = R_NilValue) {
if (r.isNull())
return Rcpp::sum(y);
Rcpp::LogicalVector mask = Rcpp::is_na(r.as());
if (Rcpp::is_true(Rcpp::all(mask)))
return NA_REAL;
double output = 0.0;
int y_count = y.size();
for (int i = 0; i < y_count; ++i) {
if (!mask[i]) {
output += y[i];
}
}
return output;
}
/***R
foo(1:4, NULL) # <- This should return 10 = 1 + 2 + 3 + 4
foo(1:4, c(1, 1, 1, 1)) # <- This should return 10 = 1 + 2 + 3 + 4
foo(1:4, c(1, 1, NA, 1)) # <- This should return 7 = 1 + 2 + 4
foo(1:4, c(NA, NA, NA, NA)) # <- This should return NA
*/
结果:
> Rcpp::sourceCpp('60569482.cpp')
> foo(1:4, NULL) # <- This should return 10 = 1 + 2 + 3 + 4
[1] 10
> foo(1:4, c(1, 1, 1, 1)) # <- This should return 10 = 1 + 2 + 3 + 4
[1] 10
> foo(1:4, c(1, 1, NA, 1)) # <- This should return 7 = 1 + 2 + 4
[1] 7
> foo(1:4, c(NA, NA, NA, NA)) # <- This should return NA
[1] NA
进一步建议:
- 使用掩码进行子设置
y
。
#include <Rcpp.h>
// [[Rcpp::export]]
double foo(Rcpp::NumericVector y, Rcpp::Nullable<Rcpp::IntegerVector> r = R_NilValue) {
if (r.isNull())
return Rcpp::sum(y);
Rcpp::LogicalVector mask = Rcpp::is_na(r.as());
if (Rcpp::is_true(Rcpp::all(mask)))
return NA_REAL;
Rcpp::NumericVector tmp = y[!mask];
return Rcpp::sum(tmp);
}