Sam*_*osa 7 r matrix sparse-matrix bigdata r-bigmemory
我有类的对象,big.matrix在R与尺寸778844 x 2.值均为整数(千米).我的目标是使用并计算欧几里德距离矩阵,big.matrix并将其作为类的对象big.matrix.我想知道是否有最佳方法.
我选择使用该类的原因big.matrix是内存限制.我可以将我转换big.matrix为类的对象matrix并使用计算欧几里德距离矩阵dist().但是,dist()将返回一个不会在内存中分配的大小的对象.
编辑
以下答案由bigmemory包装的作者和维护者John W. Emerson给出:
您可以使用我期望的大代数,但这对于Rcpp来说也是一个非常好的用例来源于sourceCpp(),非常简短.但简而言之,我们甚至不尝试提供高级功能(除了我们作为概念验证实现的基础知识).一旦你开始谈论内存不足,没有一种算法可以涵盖所有用例.
这是一种使用方式RcppArmadillo.其中大部分与RcppGallery示例非常相似.这将返回a 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(bigMat@address, zeros@address)
    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