2016-07-25 5 views
0

Rcppのbig.matrixオブジェクトから列を抽出する関数を作成しようとしています(その結果をRに変換する前にcppで解析できるようにしています)しかし、NAの認識方法を理解することはできません(以下の最小限の例で示すように-2147483648として表示されます)。 Rcppから直接GetMatrixColssrc/bigmemory.cpp)の関数にアクセスできればさらに良いでしょうが、私はそれを行う方法をまだ発見していません。RcppのbigmemoryオブジェクトからNAを持つ列を抽出する

#include <Rcpp.h> 
// [[Rcpp::plugins(cpp11)]] 
// [[Rcpp::depends(BH, bigmemory)]] 
#include <bigmemory/MatrixAccessor.hpp> 
#include <bigmemory/isna.hpp> 
using namespace Rcpp; 

//Logic for extracting column from a Big Matrix object 
template <typename T> 
NumericVector GetColumn_logic(XPtr<BigMatrix> pMat, MatrixAccessor<T> mat, int cn) { 
    NumericVector nv(pMat->nrow()); 
    for(int i = 0; i < pMat->nrow(); i++) { 
    if(isna(mat[cn][i])) { 
     nv[i] = NA_INTEGER; 
    } else { 
     nv[i] = mat[cn][i]; 
    } 
    } 
    return nv; 
} 

//' Extract Column from a Big Matrix. 
//' 
//' @param pBigMat A bigmemory object address. 
//' @param colNum Column Number to extract. Indexing starts from zero. 
//' @export 
// [[Rcpp::export]] 
NumericVector GetColumn(SEXP pBigMat, int colNum) { 
    XPtr<BigMatrix> xpMat(pBigMat); 

    switch(xpMat->matrix_type()) { 
    case 1: return GetColumn_logic(xpMat, MatrixAccessor<char>(*xpMat), colNum); 
    case 2: return GetColumn_logic(xpMat, MatrixAccessor<short>(*xpMat), colNum); 
    case 4: return GetColumn_logic(xpMat, MatrixAccessor<int>(*xpMat), colNum); 
    case 6: return GetColumn_logic(xpMat, MatrixAccessor<float>(*xpMat), colNum); 
    case 8: return GetColumn_logic(xpMat, MatrixAccessor<double>(*xpMat), colNum); 
    default: throw Rcpp::exception("Unknown type detected for big.matrix object!"); 
    } 
} 

/*** R 
bm <- bigmemory::as.big.matrix(as.matrix(reshape2::melt(matrix(c(1:4,NA,6:20),4,5)))) 
bigmemory:::CGetType([email protected]) 
bigmemory:::GetCols.bm(bm, 3) 
GetColumn([email protected], 2) 
*/ 

答えて

2

これは素晴らしいものです。一瞬のために私と一緒に滞在:

TL; DR:それは一度固定動作します:

R> sourceCpp("/tmp/bigmemEx.cpp") 

R> bm <- bigmemory::as.big.matrix(as.matrix(reshape2::melt(matrix(c(1:4,NA,6:20),4,5)))) 

R> bigmemory:::CGetType([email protected]) 
[1] 4 

R> bigmemory:::GetCols.bm(bm, 3) 
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 

R> GetColumn([email protected], 2) 
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 
R> 

トラブルが内側から始まります。あなたが行列を作成するときに

matrix(c(1:4,NA,6:20),4,5) 

何を得るのですか?整数!

R> matrix(c(1:4,NA,6:20),4,5) 
    [,1] [,2] [,3] [,4] [,5] 
[1,] 1 NA 9 13 17 
[2,] 2 6 10 14 18 
[3,] 3 7 11 15 19 
[4,] 4 8 12 16 20 
R> class(matrix(c(1:4,NA,6:20),4,5)) 
[1] "matrix" 
R> typeof(matrix(c(1:4,NA,6:20),4,5)) 
[1] "integer" 
R> 

ないそれ自体が問題が、問題あなたはIEEEの754standardがNaN(私が間違っている場合は、正しい)のみ浮動小数点のために定義されていることを覚えていたら。

もう1つの問題は、反射的にNumericVectorを使用していて、整数で動作することです。現在、RはNaN、さらにはNAであり、浮動小数点と整数の場合でも、Rの外側の「通常のライブラリ」はそうではありません。そして大きなメモリはデザインによってはRの外のものを表します、あなたは立ち往生しています。

修正は簡単です:IntegerVectorを使用してください(または、等価的に入力時に整数データを変換する)。以下は私の変更されたバージョンのコードです。 Rcppでbig.matrixの列へのアクセス

// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- 

#include <Rcpp.h> 

// [[Rcpp::plugins(cpp11)]] 
// [[Rcpp::depends(BH, bigmemory)]] 

#include <bigmemory/MatrixAccessor.hpp> 
#include <bigmemory/isna.hpp> 

using namespace Rcpp; 

//Logic for extracting column from a Big Matrix object 
template <typename T> 
IntegerVector GetColumn_logic(XPtr<BigMatrix> pMat, MatrixAccessor<T> mat, int cn) { 
    IntegerVector nv(pMat->nrow()); 
    for(int i = 0; i < pMat->nrow(); i++) { 
     if(isna(mat[cn][i])) { 
      nv[i] = NA_INTEGER; 
     } else { 
      nv[i] = mat[cn][i]; 
     } 
    } 
    return nv; 
} 

//' Extract Column from a Big Matrix. 
//' 
//' @param pBigMat A bigmemory object address. 
//' @param colNum Column Number to extract. Indexing starts from zero. 
//' @export 
// [[Rcpp::export]] 
IntegerVector GetColumn(SEXP pBigMat, int colNum) { 
    XPtr<BigMatrix> xpMat(pBigMat); 

    switch(xpMat->matrix_type()) { 
    case 1: return GetColumn_logic(xpMat, MatrixAccessor<char>(*xpMat), colNum); 
    case 2: return GetColumn_logic(xpMat, MatrixAccessor<short>(*xpMat), colNum); 
    case 4: return GetColumn_logic(xpMat, MatrixAccessor<int>(*xpMat), colNum); 
    case 6: return GetColumn_logic(xpMat, MatrixAccessor<float>(*xpMat), colNum); 
    case 8: return GetColumn_logic(xpMat, MatrixAccessor<double>(*xpMat), colNum); 
    default: throw Rcpp::exception("Unknown type detected for big.matrix object!"); 
    } 
} 

/*** R 
bm <- bigmemory::as.big.matrix(as.matrix(reshape2::melt(matrix(c(1:4,NA,6:20),4,5)))) 
bigmemory:::CGetType([email protected]) 
bigmemory:::GetCols.bm(bm, 3) 
GetColumn([email protected], 2) 
*/ 
+0

ありがとうございました。本当にありがとうございました。私はGetMatrixCols関数を呼び出すことができれば簡単にできると思います。これは正確な操作を行うためだけでなく、他のプロジェクトでも同様のニーズがあるためです。 *自分のRcppコードでRcppエクスポート関数を呼び出す必要があります。**私は 'SEXP GetMatrixCols(SEXP bigMatAddr、SEXP col);を含むヘッダーファイルを作成し、bigmemoryの新しいバージョンを作成しましたが、sourceCpp:ed:' Error in dyn.load'。私は本当に馬鹿なことをしていますか? – samssan

+0

Re 1):あなたは誤りだと思います。 NAのバイナリパターンは、 'double'から' int'への強制コピーで生き残れないかもしれません。入力時に 'double'を作成するだけです。 Re 2)と太字のテキスト。あなたが何を話しているのか分かりません。 * Rcpp属性を使用するすべての*パッケージはそれを行います。詳細については、Rcpp Attribributes vignetteを参照してください。 Re 3)あなたは、パッケージビルドでハングアップしていると思う。 rcpp-develへの新しい質問または投稿? –

+0

これがもっと明確かどうかは分かりませんが、試してみます。 OtherPackageにはcpp関数があり、そのパッケージのヘッダファイルには定義されていません。私はcppレベルでMyPackageでその関数を使用する必要があります。私はここで同様の質問を見つけた[リンク](http://stackoverflow.com/questions/27079811/how-do-i-share-c-functions-in-rcpp-based-libraries-between-r-packages?rq= 1)。当分の間それに従おうとしています。ありがとうございました! – samssan

1

により、たとえばSTDベクトル、アルマジロベクトルまたは次のコードで固有ベクトル を(クリーンなコードが存在していてもよい)を得ることができ 、難しいことではありません。

// [[Rcpp::depends(RcppEigen, RcppArmadillo, bigmemory, BH)]] 
#include <RcppArmadillo.h> 
#include <RcppEigen.h> 
#include <bigmemory/BigMatrix.h> 
#include <bigmemory/MatrixAccessor.hpp> 

using namespace Rcpp; 
using namespace arma; 
using namespace Eigen; 
using namespace std; 

// [[Rcpp::plugins(cpp11)]] 

// [[Rcpp::export]] 
ListOf<IntegerVector> AccessVector(SEXP pBigMat, int j) { 
    XPtr<BigMatrix> xpMat(pBigMat); 
    MatrixAccessor<int> macc(*xpMat); 

    int n = xpMat->nrow(); 

    // Bigmemory 
    cout << "Bigmemory:"; 
    for (int i = 0; i < n; i++) { 
    cout << macc[j][i] << ' '; 
    } 
    cout << endl;  

    // STD VECTOR 
    vector<int> stdvec(macc[j], macc[j] + n); 

    // ARMA VECTOR 
    Row<int> armavec(macc[j], n); // Replace Row by Col if you want 

    // EIGEN VECTOR 
    VectorXi eigenvec(n); 
    memcpy(&(eigenvec(0)), macc[j], n * sizeof(int)); 

    return(List::create(_["Std vector"] = stdvec, 
         _["Arma vector"] = armavec, 
         _["Eigen vector"] = eigenvec)); 
} 

AccessVector([email protected], 2)はあなたを取得します。

Bigmemory:1 2 3 4 -2147483648 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 
$`Std vector` 
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 

$`Arma vector` 
    [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] 
[1,] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 
    [,16] [,17] [,18] [,19] [,20] 
[1,] 16 17 18 19 20 

$`Eigen vector` 
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 

あなたがCは、NASについて知らないことがわかりますが、 Rに戻ると、あなたはそれらを保持します。

したがって、列のRcppで実行する操作によって異なります。私は、あなたがEigenやArmadilloの操作を直接使うと思っていますが、それは問題ありませんが、確かにあなたの結果には多くのNAsがあります。

あなたがしたい操作が何であるかを言うならば、それはもっと明白でしょう。

関連する問題