Функция Rcpp проверяет, отсутствует ли значение

Я конвертирую код на основе R в код на основе Rcpp. Глава моей функции:

NumericMatrix createMatrixOfLinkRatiosC(NumericMatrix matr, double threshold4Clean) {
int i,j; 
NumericMatrix myMatr(matr.nrow(),matr.ncol());
myMatr=matr;
....;

}

Я хочу обработать вызов функции, где threshold4Clean отсутствует, но я не нахожу, как это сделать... Любая помощь будет принята с благодарностью.

Ответ 1

Оба Rcpp и RcppArmadillo имеют предикаты для тестирования NA, NaN (расширение R) и Inf.

Вот пример RcppArmadillo:

#include <RcppArmadillo.h>

// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
arma::mat foo(int n, double threshold=NA_REAL) {
  arma::mat M = arma::zeros<arma::mat>(n,n);
  if (arma::is_finite(threshold)) M = M + threshold;
  return M;
}

/*** R
foo(2)
foo(2, 3.1415)
***/

Мы инициализируем матрицу нулей и проверяем аргумент. Если он конечен (т.е. Не NA или Inf или NaN), добавим это значение. Если бы вы этого захотели, вы могли бы также проверить свои возможности индивидуально.

Это дает желаемый результат: без второго аргумента применяется значение по умолчанию NA, и мы получаем матрицу нулей.

R> Rcpp::sourceCpp("/tmp/giorgio.cpp")

R> foo(2)
     [,1] [,2]
[1,]    0    0
[2,]    0    0

R> foo(2, 3.1415)
       [,1]   [,2]
[1,] 3.1415 3.1415
[2,] 3.1415 3.1415
R> 

Ответ 2

R имеет как NaN, так и NA (что действительно является особым типом NaN) для представления отсутствующих значений. Это важно знать, потому что есть много функций, которые проверяют, есть ли значение NaN -y (NA или NaN):

Некоторые таблицы истинности для функций из API R/C (обратите внимание на неудовлетворительное отсутствие согласованности)

+---------------------+
| Function | NaN | NA |
+---------------------+
| ISNAN    |  t  | t  |
| R_IsNaN  |  t  | f  |
| ISNA     |  f  | t  |
| R_IsNA   |  f  | t  |
+---------------------+

и Rcpp:

+-------------------------+
| Function     | NaN | NA |
+-------------------------+
| Rcpp::is_na  |  t  | t  |
| Rcpp::is_nan |  t  | f  |
+-------------------------+

и из интерпретатора R (примечание: Rcpp пытается сопоставить это, а не API R/C):

+---------------------+
| Function | NaN | NA |
+---------------------+
| is.na    |  t  | t  |
| is.nan   |  t  | f  |
+---------------------+

К сожалению, это запутанный ландшафт, но это должно немного помочь вам.

Ответ 3

Я проверял это и могу пролить свет на возможности.

Для одного SEXP target я использовал опцию Rcpp:

switch(TYPEOF(target)) {
case INTSXP:
    return Rcpp::traits::is_na<INTSXP>(Rcpp::as<int>(target));
case REALSXP:
    return Rcpp::traits::is_na<REALSXP>(Rcpp::as<double>(target));
case LGLSXP:
    return Rcpp::traits::is_na<LGLSXP>(Rcpp::as<int>(target));
case CPLXSXP:
    return Rcpp::traits::is_na<CPLXSXP>(Rcpp::as<Rcomplex>(target));
case STRSXP: {
    Rcpp::StringVector vec(target);
    return Rcpp::traits::is_na<STRSXP>(vec[0]);
}
}

Если вы хотите проверить без использования Rcpp, есть несколько предостережений:

  • Как уже упоминалось здесь, целое и логическое NA (оба хранятся как int) равно минимальному значению int (-2147483648).
  • Для double вы можете напрямую использовать то, что Rcpp использует, а именно R_isnancpp. Эквивалентно, можно использовать макрос ISNAN.
  • Для комплексных чисел вы можете проверить как действительные, так и мнимые части с помощью метода double, описанного выше.

Символ NA хитрый, поскольку он одиночный, поэтому адрес имеет значение. Лично я тестировал способы выполнения операций с символами R без сохранения std::string, чтобы избежать копий, т.е. используя char* напрямую. Я обнаружил, что это работает - объявить это в файле .cpp:

static const char *na_string_ptr = CHAR(Rf_asChar(NA_STRING));

и, основываясь на этом ответе, сделать что-то подобное для Rcpp::StringVector или Rcpp::StringMatrix x:

Rcpp::CharacterVector one_string = Rcpp::as<Rcpp::CharacterVector>(x[i]);
char *ptr = (char *)(one_string[0]);
return ptr == na_string_ptr;

Этот последний все еще использует Rcpp, но я могу использовать его один раз для начальной настройки, а затем просто использовать указатели char. Я уверен, что есть способ сделать что-то подобное с R API, но это то, что я еще не пробовал.