2014-11-16 13 views
7

Mam obiekt klasy big.matrix w R o wymiarze 778844 x 2. Wszystkie wartości to liczby całkowite (kilometry). Moim celem jest obliczenie macierzy odległości Euclidean za pomocą big.matrix i w rezultacie obiekt klasy big.matrix. Chciałbym wiedzieć, czy istnieje optymalny sposób robienia tego.Oblicz macierzy odległości Euclidean za pomocą obiektu big.matrix

Powodem mojego wyboru używania klasy big.matrix jest ograniczenie pamięci. Mógłbym przekształcić mój big.matrix w obiekt klasy matrix i obliczyć matrycę odległości euklidesową za pomocą dist(). Jednak dist() zwróci obiekt o rozmiarze, który nie zostanie przydzielony w pamięci.

Edit

Poniższa odpowiedź została udzielona przez Johna W. Emerson, autora i opiekuna pakietu bigmemory:

można użyć dużego Algebra I spodziewać, ale to byłoby również bardzo ładny przypadek użycia dla Rcpp przez sourceCpp(), i bardzo krótki i łatwy. Krótko mówiąc, nie próbujemy nawet dostarczać funkcji wysokiego poziomu (poza podstawami, które wdrożyliśmy jako dowód koncepcji). Żaden pojedynczy algorytm nie byłby w stanie pokryć wszystkich przypadków użycia, gdy zaczniesz mówić o braku pamięci.

+0

Czy poniżej odpowiedź w rozwiązaniu problemu? Jeśli tak, proszę zaakceptuj to lub odpowiednio zaktualizuj swoje pytanie. – cdeterman

Odpowiedz

7

Oto sposób korzystania z RcppArmadillo. Wiele z tego jest bardzo podobnych do RcppGallery example. Spowoduje to zwrócenie big.matrix z powiązanymi odległościami euklidesowymi parami (za wierszami). Chciałbym zawijać moje funkcje big.matrix w funkcji otoki, aby utworzyć czystszą składnię (tj. Uniknąć @address i innych inicjalizacji.)

Uwaga - ponieważ używamy bigmemory (i dlatego dotyczy to użycia pamięci RAM) Mam ten przykład zwrócił N-1 x n-1 matryca tylko dolnych elementów trójkątnych. można modyfikować to, ale to co wrzuciłem razem.

euc_dist.cpp

// To enable the functionality provided by Armadillo's various macros, 
// simply include them before you include the RcppArmadillo headers. 
#define ARMA_NO_DEBUG 

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

using namespace Rcpp; 
using namespace arma; 

// The following header file provides the definitions for the BigMatrix 
// object 
#include <bigmemory/BigMatrix.h> 

// C++11 plugin 
// [[Rcpp::plugins(cpp11)]] 

template <typename T> 
void BigArmaEuclidean(const Mat<T>& inBigMat, Mat<T> outBigMat) { 

    int W = inBigMat.n_rows; 

    for(int i = 0; i < W - 1; i++){ 
     for(int j=i+1; j < W; j++){ 
      outBigMat(j-1,i) = sqrt(sum(pow((inBigMat.row(i) - inBigMat.row(j)),2))); 
     } 
    } 
} 

// [[Rcpp::export]] 
void BigArmaEuc(SEXP pInBigMat, SEXP pOutBigMat) { 
    // First we tell Rcpp that the object we've been given is an external 
    // pointer. 
    XPtr<BigMatrix> xpMat(pInBigMat); 
    XPtr<BigMatrix> xpOutMat(pOutBigMat); 


    int type = xpMat->matrix_type(); 
    switch(type) { 
     case 1: 
     BigArmaEuclidean(
      arma::Mat<char>((char *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false), 
      arma::Mat<char>((char *)xpOutMat->matrix(), xpOutMat->nrow(), xpOutMat->ncol(), false) 
     ); 
     return; 

     case 2: 
     BigArmaEuclidean(
      arma::Mat<short>((short *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false), 
      arma::Mat<short>((short *)xpOutMat->matrix(), xpOutMat->nrow(), xpOutMat->ncol(), false) 
     ); 
     return; 

     case 4: 
     BigArmaEuclidean(
      arma::Mat<int>((int *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false), 
      arma::Mat<int>((int *)xpOutMat->matrix(), xpOutMat->nrow(), xpOutMat->ncol(), false) 
     ); 
     return; 

     case 8: 
     BigArmaEuclidean(
      arma::Mat<double>((double *)xpMat->matrix(), xpMat->nrow(), xpMat->ncol(), false), 
      arma::Mat<double>((double *)xpOutMat->matrix(), xpOutMat->nrow(), xpOutMat->ncol(), false) 
     ); 
     return; 

     default: 
     // We should never get here, but it resolves compiler warnings. 
     throw Rcpp::exception("Undefined type for provided big.matrix"); 
    } 

} 

Mój mały wrapper

bigMatrixEuc <- function(bigMat){ 
    zeros <- big.matrix(nrow = nrow(bigMat)-1, 
         ncol = nrow(bigMat)-1, 
         init = 0, 
         type = typeof(bigMat)) 
    BigArmaEuc([email protected], [email protected]) 
    return(zeros) 
} 

Test

library(Rcpp) 
sourceCpp("euc_dist.cpp") 

library(bigmemory) 

set.seed(123) 
mat <- matrix(rnorm(16), 4) 
bm <- as.big.matrix(mat) 

# Call new euclidean function 
bm_out <- bigMatrixEuc(bm)[] 

# pull out the matrix elements for out purposes 
distMat <- as.matrix(dist(mat)) 
distMat[upper.tri(distMat, diag=TRUE)] <- 0 
distMat <- distMat[2:4, 1:3] 

# check if identical 
all.equal(bm_out, distMat, check.attributes = FALSE) 
[1] TRUE 
+1

Uruchomiłem powyższe i otrzymałem 'bm_out' jako' matrycę'. Czytając opakowanie, myślałem, że 'bm_out' powinno być' big.matrix'. Czy myliłem się i ten przykład rzeczywiście powinien dać "matrycę"? Jakikolwiek sposób na bezpośrednie użycie 'bm_out' jako' big.matrix' (a nie 'matrix', który przekazuję do' as.big.matrix') – Ricky

+1

@Ricky wystarczy usunąć nawiasy, a następnie '[]', ponieważ są one używane tylko do potwierdź, że wynik jest taki sam jak z "dist". – cdeterman

Powiązane problemy