2016-07-25 18 views
0

Rcpp의 big.matrix 객체에서 열을 추출하는 함수를 만들려고합니다 (결과를 R로 가져 오기 전에 cpp에서 분석 할 수 있도록) ,하지만 NA를 인식하는 방법을 알아낼 수는 없습니다 (아래의 최소 예제에서 볼 수 있듯이 -2147483648로 표시됨). Rcpp에서 바로 GetMatrixCols (src/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]ess, 2) 
*/ 

답변

2

멋진 소식입니다. 잠시 나와 함께있어 :

TL을, 박사을 : 그것은 한 번 고정 작품 :

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은 부동 소수점에 대한 정의가 기억하면 문제 (올바른 내가 틀렸다면).

다른 문제는 귀하가 반사적으로 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

감사합니다. Dirk, Rcpp에 대한 모든 작업에 정말로 감사드립니다. 비록 이것이 정확한 답을 산출 할지라도 GetMatrixCols 함수를 호출 할 수 있다면 '더 쉽다'고 생각합니다. -이 정확한 연산을 수행 할 수있을뿐만 아니라 다른 프로젝트에서도 비슷한 필요성이 있기 때문에 -> * * 내 자신의 Rcpp 코드에서 Rcpp 내 보낸 함수를 호출해야합니다.** 나는'SEXP GetMatrixCols (SEXP bigMatAddr, SEXP col);을 포함하는 헤더 파일을 생성하고 bigmemory의 새 버전을 만들었지 만, sourceCpp : ed :'Error in dyn.load' .. 어떤 방법으로 진행할 것인가 정말 바보 같은 짓하고있어? – samssan

+0

Re 1) : 나는 그것이 당신 실수라고 생각한다. 그런 다음 NA의 바이너리 패턴이 '이중'에서 'int'로의 강제 복사에서 살아남지 못할 수 있습니다. 입력시'double'을 생성하십시오. Re 2) 및 굵게 표시된 텍스트. 네가 무슨 말하는지는 모르겠다. * Rcpp 속성을 사용하는 모든 * 패키지는 그렇게합니다. 자세한 내용은 Rcpp 속성 비 네트를 참조하십시오. Re 3) 패키지 빌드를 중단 한 것으로 의심됩니다. rcpp-devel에 대한 새로운 질문이나 게시물? –

+0

이것이 더 명확한 지 모르겠지만 시도해 보겠습니다. OtherPackage에는 cpp 함수가 있으며 그 패키지의 헤더 파일에는 정의되어 있지 않습니다. 나는 cpp 수준에서 MyPackage에서 그 기능을 사용할 필요가있다. 나는 [link] 비슷한 질문을 발견했다. (http://stackoverflow.com/questions/27079811/how-do-i-share-c-functions-in-rcpp-based-libraries-between-r-packages?rq= 1). 당분간은 그것을 따르려고 노력합니다. 고맙습니다! – samssan

1

는 어려운 일이 아니다, (청소기 코드가있을 수 있습니다) :

// [[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가 많이 나타날 것입니다.

당신이 원하는 작업이 무엇인지 말하면 아마도 더 명확해질 것입니다.