从 Rcpp 中的大内存对象中提取带有 NA 的列
Extracting a column with NA's from a bigmemory object in Rcpp
我正在尝试创建一个从 Rcpp 中的 big.matrix 对象中提取列的函数(以便在将结果带到 R 之前可以在 cpp 中对其进行分析),但我想不通了解如何让它识别 NA(它们现在显示为 -2147483648 - 如我下面的最小示例所示)。如果我可以直接从 Rcpp 访问函数 GetMatrixCols (src/bigmemory.cpp) 会更好,但我还没有找到一种方法来做到这一点。
#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::depends(BH, bigmemory)]]
#include <bigmemory/MatrixAccessor.hpp>
#include <bigmemory/isna.hpp>
using namespace Rcpp;
//Logic for extracting column from a Big Matrix object
template <typename T>
NumericVector GetColumn_logic(XPtr<BigMatrix> pMat, MatrixAccessor<T> mat, int cn) {
NumericVector nv(pMat->nrow());
for(int i = 0; i < pMat->nrow(); i++) {
if(isna(mat[cn][i])) {
nv[i] = NA_INTEGER;
} else {
nv[i] = mat[cn][i];
}
}
return nv;
}
//' Extract Column from a Big Matrix.
//'
//' @param pBigMat A bigmemory object address.
//' @param colNum Column Number to extract. Indexing starts from zero.
//' @export
// [[Rcpp::export]]
NumericVector GetColumn(SEXP pBigMat, int colNum) {
XPtr<BigMatrix> xpMat(pBigMat);
switch(xpMat->matrix_type()) {
case 1: return GetColumn_logic(xpMat, MatrixAccessor<char>(*xpMat), colNum);
case 2: return GetColumn_logic(xpMat, MatrixAccessor<short>(*xpMat), colNum);
case 4: return GetColumn_logic(xpMat, MatrixAccessor<int>(*xpMat), colNum);
case 6: return GetColumn_logic(xpMat, MatrixAccessor<float>(*xpMat), colNum);
case 8: return GetColumn_logic(xpMat, MatrixAccessor<double>(*xpMat), colNum);
default: throw Rcpp::exception("Unknown type detected for big.matrix object!");
}
}
/*** R
bm <- bigmemory::as.big.matrix(as.matrix(reshape2::melt(matrix(c(1:4,NA,6:20),4,5))))
bigmemory:::CGetType(bm@address)
bigmemory:::GetCols.bm(bm, 3)
GetColumn(bm@address, 2)
*/
太棒了!陪我一会儿:
tl;dr:修复后有效:
R> sourceCpp("/tmp/bigmemEx.cpp")
R> bm <- bigmemory::as.big.matrix(as.matrix(reshape2::melt(matrix(c(1:4,NA,6:20),4,5))))
R> bigmemory:::CGetType(bm@address)
[1] 4
R> bigmemory:::GetCols.bm(bm, 3)
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
R> GetColumn(bm@address, 2)
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
R>
麻烦从内部开始。当您将矩阵创建为
matrix(c(1:4,NA,6:20),4,5)
你得到了什么?整数!
R> matrix(c(1:4,NA,6:20),4,5)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 NA 9 13 17
[2,] 2 6 10 14 18
[3,] 3 7 11 15 19
[4,] 4 8 12 16 20
R> class(matrix(c(1:4,NA,6:20),4,5))
[1] "matrix"
R> typeof(matrix(c(1:4,NA,6:20),4,5))
[1] "integer"
R>
本身不是问题,但一旦您记得 IEEE 754 标准仅针对浮点数定义了 NaN(如果我错了,请更正)。
另一个问题是你反身使用了NumericVector
,但是对整数进行操作。现在 R 有 NaN
,甚至 NA
,用于浮点数和整数,但 R 之外的 'normal libraries' 没有。大内存 设计 表示 R 之外的东西,你被卡住了。
修复非常简单:使用 IntegerVector
(或等效地转换输入的整数数据)。以下是我修改后的代码版本。
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::depends(BH, bigmemory)]]
#include <bigmemory/MatrixAccessor.hpp>
#include <bigmemory/isna.hpp>
using namespace Rcpp;
//Logic for extracting column from a Big Matrix object
template <typename T>
IntegerVector GetColumn_logic(XPtr<BigMatrix> pMat, MatrixAccessor<T> mat, int cn) {
IntegerVector nv(pMat->nrow());
for(int i = 0; i < pMat->nrow(); i++) {
if(isna(mat[cn][i])) {
nv[i] = NA_INTEGER;
} else {
nv[i] = mat[cn][i];
}
}
return nv;
}
//' Extract Column from a Big Matrix.
//'
//' @param pBigMat A bigmemory object address.
//' @param colNum Column Number to extract. Indexing starts from zero.
//' @export
// [[Rcpp::export]]
IntegerVector GetColumn(SEXP pBigMat, int colNum) {
XPtr<BigMatrix> xpMat(pBigMat);
switch(xpMat->matrix_type()) {
case 1: return GetColumn_logic(xpMat, MatrixAccessor<char>(*xpMat), colNum);
case 2: return GetColumn_logic(xpMat, MatrixAccessor<short>(*xpMat), colNum);
case 4: return GetColumn_logic(xpMat, MatrixAccessor<int>(*xpMat), colNum);
case 6: return GetColumn_logic(xpMat, MatrixAccessor<float>(*xpMat), colNum);
case 8: return GetColumn_logic(xpMat, MatrixAccessor<double>(*xpMat), colNum);
default: throw Rcpp::exception("Unknown type detected for big.matrix object!");
}
}
/*** R
bm <- bigmemory::as.big.matrix(as.matrix(reshape2::melt(matrix(c(1:4,NA,6:20),4,5))))
bigmemory:::CGetType(bm@address)
bigmemory:::GetCols.bm(bm, 3)
GetColumn(bm@address, 2)
*/
在Rcpp中访问big.matrix
的一列并不难,
例如,您可以获得标准向量、犰狳向量或特征向量
使用以下代码(可能存在更清晰的代码):
// [[Rcpp::depends(RcppEigen, RcppArmadillo, bigmemory, BH)]]
#include <RcppArmadillo.h>
#include <RcppEigen.h>
#include <bigmemory/BigMatrix.h>
#include <bigmemory/MatrixAccessor.hpp>
using namespace Rcpp;
using namespace arma;
using namespace Eigen;
using namespace std;
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
ListOf<IntegerVector> AccessVector(SEXP pBigMat, int j) {
XPtr<BigMatrix> xpMat(pBigMat);
MatrixAccessor<int> macc(*xpMat);
int n = xpMat->nrow();
// Bigmemory
cout << "Bigmemory:";
for (int i = 0; i < n; i++) {
cout << macc[j][i] << ' ';
}
cout << endl;
// STD VECTOR
vector<int> stdvec(macc[j], macc[j] + n);
// ARMA VECTOR
Row<int> armavec(macc[j], n); // Replace Row by Col if you want
// EIGEN VECTOR
VectorXi eigenvec(n);
memcpy(&(eigenvec(0)), macc[j], n * sizeof(int));
return(List::create(_["Std vector"] = stdvec,
_["Arma vector"] = armavec,
_["Eigen vector"] = eigenvec));
}
AccessVector(bm@address, 2)
让你:
Bigmemory:1 2 3 4 -2147483648 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
$`Std vector`
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
$`Arma vector`
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15]
[1,] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15
[,16] [,17] [,18] [,19] [,20]
[1,] 16 17 18 19 20
$`Eigen vector`
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
你可以看到 C 不知道 NA 但当返回到 R 时,你保留它们。
因此,这取决于您要在 Rcpp 中对列执行哪些操作。我想如果你直接使用Eigen或者Armadillo操作,应该可以,但是你的结果中肯定会得到很多NA。
如果你说出你想做的这些操作是什么,也许会更清楚。
我正在尝试创建一个从 Rcpp 中的 big.matrix 对象中提取列的函数(以便在将结果带到 R 之前可以在 cpp 中对其进行分析),但我想不通了解如何让它识别 NA(它们现在显示为 -2147483648 - 如我下面的最小示例所示)。如果我可以直接从 Rcpp 访问函数 GetMatrixCols (src/bigmemory.cpp) 会更好,但我还没有找到一种方法来做到这一点。
#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::depends(BH, bigmemory)]]
#include <bigmemory/MatrixAccessor.hpp>
#include <bigmemory/isna.hpp>
using namespace Rcpp;
//Logic for extracting column from a Big Matrix object
template <typename T>
NumericVector GetColumn_logic(XPtr<BigMatrix> pMat, MatrixAccessor<T> mat, int cn) {
NumericVector nv(pMat->nrow());
for(int i = 0; i < pMat->nrow(); i++) {
if(isna(mat[cn][i])) {
nv[i] = NA_INTEGER;
} else {
nv[i] = mat[cn][i];
}
}
return nv;
}
//' Extract Column from a Big Matrix.
//'
//' @param pBigMat A bigmemory object address.
//' @param colNum Column Number to extract. Indexing starts from zero.
//' @export
// [[Rcpp::export]]
NumericVector GetColumn(SEXP pBigMat, int colNum) {
XPtr<BigMatrix> xpMat(pBigMat);
switch(xpMat->matrix_type()) {
case 1: return GetColumn_logic(xpMat, MatrixAccessor<char>(*xpMat), colNum);
case 2: return GetColumn_logic(xpMat, MatrixAccessor<short>(*xpMat), colNum);
case 4: return GetColumn_logic(xpMat, MatrixAccessor<int>(*xpMat), colNum);
case 6: return GetColumn_logic(xpMat, MatrixAccessor<float>(*xpMat), colNum);
case 8: return GetColumn_logic(xpMat, MatrixAccessor<double>(*xpMat), colNum);
default: throw Rcpp::exception("Unknown type detected for big.matrix object!");
}
}
/*** R
bm <- bigmemory::as.big.matrix(as.matrix(reshape2::melt(matrix(c(1:4,NA,6:20),4,5))))
bigmemory:::CGetType(bm@address)
bigmemory:::GetCols.bm(bm, 3)
GetColumn(bm@address, 2)
*/
太棒了!陪我一会儿:
tl;dr:修复后有效:
R> sourceCpp("/tmp/bigmemEx.cpp")
R> bm <- bigmemory::as.big.matrix(as.matrix(reshape2::melt(matrix(c(1:4,NA,6:20),4,5))))
R> bigmemory:::CGetType(bm@address)
[1] 4
R> bigmemory:::GetCols.bm(bm, 3)
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
R> GetColumn(bm@address, 2)
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
R>
麻烦从内部开始。当您将矩阵创建为
matrix(c(1:4,NA,6:20),4,5)
你得到了什么?整数!
R> matrix(c(1:4,NA,6:20),4,5)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 NA 9 13 17
[2,] 2 6 10 14 18
[3,] 3 7 11 15 19
[4,] 4 8 12 16 20
R> class(matrix(c(1:4,NA,6:20),4,5))
[1] "matrix"
R> typeof(matrix(c(1:4,NA,6:20),4,5))
[1] "integer"
R>
本身不是问题,但一旦您记得 IEEE 754 标准仅针对浮点数定义了 NaN(如果我错了,请更正)。
另一个问题是你反身使用了NumericVector
,但是对整数进行操作。现在 R 有 NaN
,甚至 NA
,用于浮点数和整数,但 R 之外的 'normal libraries' 没有。大内存 设计 表示 R 之外的东西,你被卡住了。
修复非常简单:使用 IntegerVector
(或等效地转换输入的整数数据)。以下是我修改后的代码版本。
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::depends(BH, bigmemory)]]
#include <bigmemory/MatrixAccessor.hpp>
#include <bigmemory/isna.hpp>
using namespace Rcpp;
//Logic for extracting column from a Big Matrix object
template <typename T>
IntegerVector GetColumn_logic(XPtr<BigMatrix> pMat, MatrixAccessor<T> mat, int cn) {
IntegerVector nv(pMat->nrow());
for(int i = 0; i < pMat->nrow(); i++) {
if(isna(mat[cn][i])) {
nv[i] = NA_INTEGER;
} else {
nv[i] = mat[cn][i];
}
}
return nv;
}
//' Extract Column from a Big Matrix.
//'
//' @param pBigMat A bigmemory object address.
//' @param colNum Column Number to extract. Indexing starts from zero.
//' @export
// [[Rcpp::export]]
IntegerVector GetColumn(SEXP pBigMat, int colNum) {
XPtr<BigMatrix> xpMat(pBigMat);
switch(xpMat->matrix_type()) {
case 1: return GetColumn_logic(xpMat, MatrixAccessor<char>(*xpMat), colNum);
case 2: return GetColumn_logic(xpMat, MatrixAccessor<short>(*xpMat), colNum);
case 4: return GetColumn_logic(xpMat, MatrixAccessor<int>(*xpMat), colNum);
case 6: return GetColumn_logic(xpMat, MatrixAccessor<float>(*xpMat), colNum);
case 8: return GetColumn_logic(xpMat, MatrixAccessor<double>(*xpMat), colNum);
default: throw Rcpp::exception("Unknown type detected for big.matrix object!");
}
}
/*** R
bm <- bigmemory::as.big.matrix(as.matrix(reshape2::melt(matrix(c(1:4,NA,6:20),4,5))))
bigmemory:::CGetType(bm@address)
bigmemory:::GetCols.bm(bm, 3)
GetColumn(bm@address, 2)
*/
在Rcpp中访问big.matrix
的一列并不难,
例如,您可以获得标准向量、犰狳向量或特征向量
使用以下代码(可能存在更清晰的代码):
// [[Rcpp::depends(RcppEigen, RcppArmadillo, bigmemory, BH)]]
#include <RcppArmadillo.h>
#include <RcppEigen.h>
#include <bigmemory/BigMatrix.h>
#include <bigmemory/MatrixAccessor.hpp>
using namespace Rcpp;
using namespace arma;
using namespace Eigen;
using namespace std;
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
ListOf<IntegerVector> AccessVector(SEXP pBigMat, int j) {
XPtr<BigMatrix> xpMat(pBigMat);
MatrixAccessor<int> macc(*xpMat);
int n = xpMat->nrow();
// Bigmemory
cout << "Bigmemory:";
for (int i = 0; i < n; i++) {
cout << macc[j][i] << ' ';
}
cout << endl;
// STD VECTOR
vector<int> stdvec(macc[j], macc[j] + n);
// ARMA VECTOR
Row<int> armavec(macc[j], n); // Replace Row by Col if you want
// EIGEN VECTOR
VectorXi eigenvec(n);
memcpy(&(eigenvec(0)), macc[j], n * sizeof(int));
return(List::create(_["Std vector"] = stdvec,
_["Arma vector"] = armavec,
_["Eigen vector"] = eigenvec));
}
AccessVector(bm@address, 2)
让你:
Bigmemory:1 2 3 4 -2147483648 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
$`Std vector`
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
$`Arma vector`
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15]
[1,] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15
[,16] [,17] [,18] [,19] [,20]
[1,] 16 17 18 19 20
$`Eigen vector`
[1] 1 2 3 4 NA 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
你可以看到 C 不知道 NA 但当返回到 R 时,你保留它们。
因此,这取决于您要在 Rcpp 中对列执行哪些操作。我想如果你直接使用Eigen或者Armadillo操作,应该可以,但是你的结果中肯定会得到很多NA。
如果你说出你想做的这些操作是什么,也许会更清楚。