如何在 bigmemory rcpp 中修改文件支持矩阵的值

how to modify values of a file-backed matrix in bigmemory rcpp

我正在使用 R bigmemory 包和 Rcpp 来处理大矩阵(1 到 1000 万列 x 1000 行)。一旦我将包含 0、2 和 NA 的整数矩阵读入 R 中的文件支持的大内存矩阵,我想通过 C++ 修改所有 NA 值,以便对每列的平均值或任意值进行插补(我在这里显示后者)。

下面是我编写的Rcpp 函数,但它不起作用。我希望从 R 中调用 BigNA(mybigmatrix@address) 可以找到矩阵中的 NA 元素并直接在支持文件中修改它的值。

我认为问题可能出在 std::isnan(mat[j][i]) 的评估中。我通过创建一个替代函数来检查这一点,该函数使用累加器计算 NA 值并且确实没有计算任何 NA。但是一旦解决了这个问题,我也不确定表达式 mat[j][i] = 1 是否会修改支持文件中的值。对于具有 R 背景的我来说,编写这些语句感觉很直观,但可能是错误的。

任何 help/suggestion 将不胜感激。

#include <stdio.h>
#include <Rcpp.h>
#include <bigmemory/MatrixAccessor.hpp>
#include <numeric>
// [[Rcpp::depends(BH, bigmemory)]]
// [[Rcpp::depends(Rcpp)]]


// [[Rcpp::export]]
void BigNA(SEXP pBigMat) {
  /*
  * Imputation of "NA" values for "1" in a big 0, 2 NA matrix.
  */

  // Create the external bigmatrix pointer and iniciate matrix accessor
  XPtr<BigMatrix> xpMat(pBigMat);
  MatrixAccessor<int> mat = (*xpMat);

  // Iterater over the elements in a matrix and when NA is found, substitute for "1"
  for(int i=0; i< xpMat->ncol(); i++){
    for(int j=0; j< xpMat->nrow(); j++){
      if(std::isnan(mat[j][i])){ 
        mat[j][i] = 1;
      }
    }
  }
} 

问题源于R中的NA和C++中的NAN之间的差异。

MatrixAccessor<int> 为您提供 int 类型值的访问器。 R 中的任何数字都可以是 NA,但 C++ 中的 int 永远不会是 NAN。优化编译器可以完全忽略 std::isnan(x),其中 x 属于 int 类型,就像您的情况一样。

要解决此问题,您可以:

  • 使用MatrixAccessor<float>(或double)。这意味着实际存储不同的数据类型。
  • 检查 NA 个元素实际获得的价值。我想你会发现它在 C++ 中是 INT_MIN (-2147483648)。将 isnan(x) 替换为 x == INT_MIN.

相关:

软件包 bigmemory 有一些检查 NAs 的函数。

只需添加带有 #include <bigmemory/isna.hpp> 的页眉。 并将 std::isnan(mat[j][i]) 替换为 isna(mat[j][i]).