2014-11-16 20 views
7

Ho un oggetto della classe big.matrix in R con dimensione 778844 x 2. I valori sono tutti numeri interi (chilometri). Il mio obiettivo è quello di calcolare la matrice di distanza euclidea usando lo big.matrix e avere come risultato un oggetto della classe big.matrix. Vorrei sapere se esiste un modo ottimale per farlo.Calcolo della matrice di distanza euclidea utilizzando un oggetto big.matrix

Il motivo per cui ho scelto di utilizzare la classe big.matrix è la limitazione della memoria. Potrei trasformare il mio big.matrix in un oggetto della classe matrix e calcolare la matrice di distanza euclidea usando dist(). Tuttavia, dist() restituirebbe un oggetto di dimensioni che non verrebbe assegnato alla memoria.

Modifica

La risposta seguente è stato dato da John W. Emerson, autore e maintainer del pacchetto bigmemory:

Si potrebbe utilizzare grandi algebra mi aspetto, ma questo sarebbe anche un Caso d'uso molto carino per Rcpp via sourceCpp(), e molto breve e facile. In breve, non tentiamo nemmeno di fornire funzionalità di alto livello (oltre alle basi che abbiamo implementato come proof-of-concept). Nessun singolo algoritmo può coprire tutti i casi d'uso una volta che si inizia a parlare di grandi quantità di memoria esaurita.

+0

Forse la risposta qui sotto risolto il problema? In tal caso, accettalo o aggiorna la tua domanda di conseguenza. – cdeterman

risposta

7

Ecco un modo utilizzando RcppArmadillo. Molto di questo è molto simile allo RcppGallery example. Ciò restituirà un big.matrix con le distanze euclidee a coppie (per riga) associate. Mi piace per avvolgere i miei big.matrix funzioni in una funzione wrapper per creare una sintassi più pulita (cioè evitare gli altri @address e inizializzazioni

Nota -. Come stiamo usando bigmemory (e quindi interessati con l'utilizzo di RAM) Ho questo esempio restituito il N-1 x N-1 matrice di elementi triangolari solo inferiori. Si può modificare questo, ma questo è ciò che ho buttato insieme.

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"); 
    } 

} 

mio piccolo involucro

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) 
} 

Il 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

Ho eseguito quanto sopra, e ho ottenuto 'bm_out' come una' matrice '. Leggendo il wrapper, avevo pensato che 'bm_out' avrebbe dovuto essere un' big.matrix'. Mi sbagliavo e questo esempio in effetti dovrebbe produrre una 'matrice '? Qualsiasi modo per avere 'bm_out' direttamente come' big.matrix' (piuttosto che 'matrix' che passo a' as.big.matrix') – Ricky

+1

@Ricky rimuovi solo le parentesi quindi '[]' come sono abituati conferma che l'output è lo stesso di 'dist'. – cdeterman

Problemi correlati