2014-11-16 8 views
7

크기가 778844 x 2 인 클래스 big.matrix의 객체가 있습니다. 값은 모두 정수 (킬로미터)입니다. 내 목표는 big.matrix을 사용하여 유클리드 거리 매트릭스를 계산하고 결과적으로 클래스 big.matrix의 객체를 갖는 것입니다. 최선의 방법이 있는지 알고 싶습니다.big.matrix 객체를 사용하여 유클리드 거리 행렬을 계산하십시오.

내가 big.matrix 클래스를 사용하기로 선택한 이유는 메모리 제한 때문입니다. 내 big.matrix을 클래스 matrix의 객체로 변환하고 dist()을 사용하여 유클리드 거리 매트릭스를 계산할 수 있습니다. 그러나 dist()은 메모리에 할당되지 않는 크기의 객체를 반환합니다.

편집

다음 대답은 존 W. 에머슨의 bigmemory 패키지의 저자와 테이너에 의해 주어졌다 : 당신은 내가 기대 큰 대수를 사용할 수

하지만,이 또한 일 것 sourceCpp()를 통한 Rcpp에 대한 매우 유용한 유스 케이스. 매우 짧고 쉽다. 간단히 말해, 우리는 개념 증명 (proof-of-concept)으로 구현 한 기본 사항 이외의 고급 기능을 제공하려고 시도조차하지 않습니다. 메모리 부족 현상에 대해 이야기하기 시작하면 단일 알고리즘으로 모든 유스 케이스를 처리 할 수 ​​없습니다.

+0

? 그렇다면이를 수락하거나 그에 맞게 질문을 업데이트하십시오. – cdeterman

답변

7

여기에 RcppArmadillo을 사용하는 방법이 있습니다. 이 중 많은 부분이 RcppGallery example과 매우 유사합니다. 연결된 행 (pairwise by euclidean) 거리와 함께 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"); 
    } 

} 

내 작은 래퍼

,523,

테스트 대답은 아래의 문제를 해결하는 데 도움이 되었습니까

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'로 받았습니다. wrapper를 읽었을 때, 나는'bm_out'이'big.matrix'이어야한다고 생각했다. 나는 틀렸는가?이 예제는 실제로'매트릭스 '를 만들어야 하는가? 'bm_out'을 직접'big.matrix' (''as.big.matrix'에 전달하는'matrix'가 아닌)로 직접 가져 오는 방법 – Ricky

+1

@Ricky는 대괄호를 제거한 후 '[]'를 사용합니다. 출력이 'dist'와 동일한 지 확인하십시오. – cdeterman