Chapter 21 NA NaN Inf NULL

21.1 NA NaN Inf の値

Rcpp で Inf -Inf NaN の値を表現するには R_PosInf R_NegInf R_NaN の記号を用います。

Rでの値 Rcppでの表記
Inf|R_PosInf| |-Inf|R_NegInf| |NaN|R_NaN`

一方、NA については Vector の型ごとに異なる NA の値が定義されています。

ベクトル型 NA値
NumericVector NA_REAL
IntegerVector NA_INTEGER
LogicalVector NA_LOGICAL
CharacterVector NA_STRING

次のコード例では、これらの記号を使ってベクトルを作成する方法を示します。

21.2 NA NaN Inf の判定

21.2.1 ベクトルの要素をまとめて判定する場合

ベクトル v の要素にある、NA NaN Inf -Inf をまとめて判定するには、関数is_na() is_nan() is_infinite() を使います。

下のコード例では、R で NA NaN Inf -Inf を含むベクトルを作成し、それを Rcpp で判定しています。この例から Rcpp の is_na() 関数は R の is.na() 関数と同じく、NANaN の両方を true であると判定することがわかります。

これらの関数を使うことでベクトルから NA NaN Inf を取り除くことができます。また NA を取り除くためには na_omit() を使うこともできます。

下のコード例では、関数 is_na()na_omit() を使ってベクトルから NA を取り除く方法を示します。

// NA を含むベクトルの作成
NumericVector v =
    NumericVector::create( 1, NA_REAL, 2, NA_REAL, 3);

//ベクトルから NA を取り除く
NumericVector v1 = v[!is_na(v)];
NumericVector v2 = na_omit(v);

21.2.2 ベクトルの要素1つに対して判定する場合

ベクトルの要素1つに対して NA NaN Inf -Inf の判定を行いたい場合には、ベクトルの静的メンバ関数の Vector::is_na()traits::is_nan<RTYPE>()traits:: is_infinite<RTYPE>() を用います。RTYPE には判定したいベクトルの SEXPTYPE を指定します。

以下に主要なベクトルの SEXPTYPE のリストを示します。

SEXPTYPE ベクトル
LGLSXP 論理ベクトル
INTSXP 整数ベクトル
REALSXP 実数ベクトル
CPLXSXP 複素数ベクトル
STRSXP 文字列ベクトル

21.3 NULL

Rcpp で NULL を扱う場合には R_NilValue を利用します。下のコード例では、NULL がリストの要素に含まれる場合の判定と、NULL を代入して属性の値を消去する例を示します。

// [[Rcpp::export]]
List rcpp_list()
{
    // 要素名がついたリストを作成する
    // 2つの要素のうち1つは NULL になっています
    List L = List::create(Named("x",NumericVector({1,2,3})),
                          Named("y",R_NilValue));

    // NULL の判定
    for(int i=0; i<L.length(); ++i){
        if(L[i]==R_NilValue) {
            Rprintf("L[%i] is NULL.\n\n", i+1);
        }
    }

    // オブジェクトの属性値(要素名)の値を消去する
    L.attr("names") = R_NilValue;

    return(L);
}

実行結果

> rcpp_list()
L[2] is NULL.

[[1]]
[1] 1 2 3

[[2]]
NULL

21.4 Rcpp で NA を扱う際の注意点

内部的には NA_INTEGERNA_LOGICAL には int の最小値 (-2147483648) がセットされています。Rcpp で定義された関数や演算子は int の最小値を NA として適切に扱ってくれます(つまり、NA の要素に対する演算の結果を NA にします)。しかし、標準 C++ の関数や演算子は int の最小値を単なる数値としてそのまま扱います。そのため、例えば IntegerVectorNA に 1 を足すと、結果は int の最小値ではなくなるため、もはや NA ではなくなってしまいます。

加えて bool 型に NA を代入した場合には常に true になります。これは bool は 0 以外の数値をすべて true と評価するためです。

一方、double には naninf が定義されているため、標準 C++ でも nan inf に対する演算の結果は、R と同様の結果なるため問題はありません。

下の表では、R の NA Inf -Inf NaN の値を Vector やスカラー型に対して代入したときに、どのような値として評価されるのかまとめています。

NA NaN Inf -Inf
NumericVector NA_REAL R_NaN R_PosInf R_NegInf
IntegerVector NA_INTEGER NA_INTEGER NA_INTEGER NA_INTEGER
LogicalVector NA_LOGICAL NA_LOGICAL NA_LOGICAL NA_LOGICAL
CharacterVector NA_STRING “NaN” “Inf” “-Inf”
String NA_STRING “NaN” “Inf” “-Inf”
double nan nan inf -inf
int -2147483648 -2147483648 -2147483648 -2147483648
bool true true true true

下のコード例は、NA_INTEGER に対して Rcpp の演算子と標準 C++ の演算子を用いて演算を行った時の結果の違いを示しています。この実行結果から Rcpp の演算子は NA に対する演算の結果を NA にしますが、標準 C++ の演算子は整数ベクトルの NA を数値として扱っていることがわかります。

実行結果

> rcpp_na_sum()
$`Rcpp plus`
[1]  2 NA  4

$`C++  plus`
[1]  2 -2147483647 4