2016-07-25 6 views
0

Ich versuche eine Funktion zu erstellen, die eine Spalte aus einem big.matrix-Objekt in Rcpp extrahiert (damit sie in cpp analysiert werden kann, bevor die Ergebnisse auf R gebracht werden) , aber ich kann nicht herausfinden, wie man NA's erkennt (sie werden jetzt als -2147483648 dargestellt - wie in meinem Minimalbeispiel unten gezeigt). Es wäre noch besser, wenn ich direkt von Rcpp auf die Funktion GetMatrixCols (src/bigmemory.cpp) zugreifen könnte, aber ich habe noch einen Weg gefunden, dies zu tun.Eine Spalte mit NAs aus einem Bigmemory-Objekt in Rcpp extrahieren

#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) 
*/ 

Antwort

2

Das ist ein großartiger! Bleib bei mir für einen Moment:

tl; dr: Es funktioniert einmal festgelegt:

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> 

Das Problem beginnt an der Innenseite. Wenn Sie Ihre Matrix als

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

erstellen, was erhalten Sie? Ganze Zahl!

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> 

Kein Problem per se, aber ein Problem, wenn Sie daran denken, dass die IEEE 754standard hat NaN für Gleitkomma definiert nur (richtig, wenn ich falsch liege).

Das andere Problem ist, dass Sie reflexartig NumericVector in Ihrem verwendet, aber auf ganzen Zahlen arbeiten. Jetzt hat R NaN und sogar NA, für Fließkomma und Integer, aber 'normale Bibliotheken' außerhalb von R nicht. Und eine große Erinnerung von Design stellt Dinge außerhalb von R, du bist fest.

Die Fehlerbehebung ist einfach genug: Verwenden Sie IntegerVector (oder konvertieren Sie gleichwertige Ganzzahldaten am Eingang). Unten ist meine geänderte Version Ihres Codes.

// -*- 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

Danke Dirk, schätze wirklich all deine Arbeit an Rcpp. Obwohl dies die richtige Antwort liefert, denke ich immer noch, dass es "einfacher" wäre, wenn ich die GetMatrixCols-Funktion aufrufen könnte - nicht nur, weil sie genau diese Operation ausführt, sondern weil ich ähnliche Bedürfnisse in anderen Projekten habe -> * * Die Notwendigkeit, Rcpp Exportierte Funktionen in meinem eigenen Rcpp-Code aufzurufen.** Ich habe eine Header-Datei erstellt, die 'SEXP GetMatrixCols (SEXP bigMatAddr, SEXP col) enthält; und habe eine neue Version von bigmemory erstellt, aber wenn ich SourceCpp: ed:' Fehler in dyn.load' .. Irgendwelche Ideen, wie man vorgeht oder Mache ich etwas wirklich dummes? – samssan

+0

Zu 1): Ich denke, das ist ein Fehler. Dann kann das Binärmuster einer NA die erzwungene Kopie von "double" zu "int" nicht überleben. Erstellen Sie einfach "double" bei der Eingabe. Re 2) und Fettschrift. Keine Ahnung, wovon du sprichst. * Jedes * Paket, das Rcpp-Attribute verwendet, macht das, siehe die Rcpp-Attribut-Vignette für Details. Re 3) Ich vermute, Sie haben einen Hang-up auf Paket-Build. Neue Frage oder Post zu rcpp-devel? –

+0

Weiß nicht, ob das noch klarer ist, aber ich werde es versuchen. Es gibt eine cpp-Funktion in OtherPackage und sie ist nicht in den Header-Dateien dieses Pakets definiert. Ich muss diese Funktion in MyPackage auf cpp-Ebene verwenden. Ich habe eine ähnliche Frage hier gefunden [link] (http://stackoverflow.com/questions/27079811/how-do-i-share-c-functions-in-rcpp-based-libraries-between-r-packages?rq= 1). Ich versuche das vorerst zu verfolgen. Vielen Dank! – samssan

1

eine Spalte einer big.matrix in RCPP Zugriff ist nicht schwierig, Sie können zum Beispiel einen std Vektor erhalten, ein Armadillo-Vektor oder einen Eigenvektor mit dem folgenden Code (es kann saubereren Code vorhanden sind):

// [[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) bekommt man:

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 

Sie können sehen, dass C nicht über NAs weiß aber Wenn du zu R zurückkehrst, behälst du sie.

Also, es hängt davon ab, welche Operationen Sie in Rcpp auf den Spalten ausführen möchten. Ich denke, wenn Sie direkt Eigen- oder Armadillo-Operationen verwenden, sollte es OK sein, aber Sie werden sicherlich viele NAs in Ihrem Ergebnis bekommen.

Vielleicht wäre es klarer, wenn Sie sagen, was diese Operationen sind, die Sie tun möchten.

Verwandte Themen