2014-11-16 129 views
7

我有一個big.matrix類的對象,其中R的尺寸爲778844 x 2。這些值都是整數(公里)。我的目標是使用big.matrix來計算歐幾里得距離矩陣,並且因此產生類big.matrix的對象。我想知道是否有一個最佳的方式來做到這一點。使用big.matrix對象計算歐幾里德距離矩陣

我選擇使用類big.matrix的原因是內存限制。我可以將我的big.matrix轉換爲類matrix的對象,並使用dist()計算歐幾里得距離矩陣。但是,dist()會返回一個不會在內存中分配的大小對象。

編輯

以下的答案必須由約翰·W·愛默生的bigmemory包的作者和維護者給出:

你可以使用大代數我希望,但這也將是一個通過sourceCpp()非常好的Rcpp用例,非常簡短。但總之,我們甚至不試圖提供高級功能(除了我們作爲概念驗證實現的基礎知識之外)。一旦開始說內存不足,沒有一種算法可以覆蓋所有用例。

+0

沒有下面的回答解決問題了嗎?如果是這樣,請接受它或相應地更新您的問題。 – cdeterman

回答

7

這是一種使用RcppArmadillo的方法。其中很大一部分與RcppGallery example非常相似。這將返回big.matrix與相關的成對(逐行)歐幾里德距離。我想換我big.matrix功能於一身的包裝函數來創建一個更清晰的語法(即避免@address等初始化

注 - 因爲我們使用bigmemory(因此關注RAM的使用)我有這樣的例子返回只有下三角元素的N-1 X N-1矩陣,你可以修改這個,但是這是我扔在一起。

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

} 

我的小包裝

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

測試

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

我運行了上面的代碼,並將'bm_out'作爲'matrix'。閱讀包裝,我曾認爲'bm_out'應該是'big.matrix'。我錯了嗎?這個例子確實應該產生一個「矩陣」?任何直接將'bm_out'作爲'big.matrix'(而不是'matrix'我將它傳遞給'as.big.matrix')的方法# – Ricky

+1

@Ricky只是刪除括號然後'[]',因爲它們只用於確認輸出與'dist'相同。 – cdeterman