我有一个关于从矩阵到向量的子集的问题。用户可以明确地给出indexmatrix(这是一个与M大小相同的矩阵,如果不需要该条目则为0,如果必须提取该条目,则为1)。如果提供了indexmatrix,那么我们只是对它进行子集化,如果没有提供indexmatrix(indexmatrix = NULL),那么我们使用type1(采用true或false)来构建它。只有两种类型的索引矩阵是可能的。
我使用了提供的子集技术 Subset of a Rcpp Matrix that matches a logical statement
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
using namespace Rcpp;
// [[Rcpp::export]]
arma::colvec extractElementsRcpp(arma::mat M,
Rcpp::Nullable<Rcpp::NumericMatrix> indexmatrix = R_NilValue,
bool type1 = false) {
unsigned int D = M.n_rows; // dimension of the data
arma::mat indmatrix(D, D); // initialize indexmatrix
if (indexmatrix.isNotNull()) {
// copy indexmatrix to numericmatrix
Rcpp::NumericMatrix indexmatrixt(indexmatrix);
// make indexmatrix into arma matrix indmatrix
indmatrix = Rcpp::as<arma::mat>(indexmatrixt);
} //else {
// get indexmatrix
// Rcpp::NumericMatrix indexmatrixt = getindexmatrix(D, type1)["indexmatrix"];
// // make indexmatrix into arma matrix
// indmatrix = Rcpp::as<arma::mat>(indexmatrixt);
// }
arma::colvec unM = M.elem(find(indmatrix == 1)); // extract wanted elements
return(unM);
}
很有效!然而,速度并不是我所希望的。每当提供索引矩阵时,C ++代码比普通的R代码慢,而我的目标是在速度上有一个很好的改进。我觉得我正在复制太多的矩阵。但我是C ++的新手,并没有找到避免它的方法。
速度比较如下:
test replications elapsed relative
2 extractElementsR(M, indexmatrix = ind) 100 0.084 1.00
1 extractElementsRcpp(M, indexmatrix = ind) 100 0.142 1.69
编辑:R函数定义为
extractElementsR <- function (M, indexmatrix, type1 = FALSE) {
D <- nrow(M)
# # get indexmatrix, if necessary
# if(is.null(indexmatrix)) indexmatrix <- getindexmatrix(D, type1 = type1)$indexmatrix
# extract wanted elements
return (M[which(indexmatrix > 0)])
}
例如,可以采用矩阵
M <- matrix(rnorm(1000^2), ncol = 1000)
indexmatrix <- matrix(1, 1000, 1000)
indexmatrix[lower.tri(indexmatrix)] <- 0
作为M和indexmatrix。
EDIT2:我在Rcpp函数中注释了else
语句,并省略了R函数中的默认NULL
值,因为它对我的问题并不重要。我想在提供indexmatrix时提高Rcpp函数的速度。但是,我想保留默认的NULL
值(并在必要时创建和索引矩阵)。
答案 0 :(得分:0)
你能否展示
extractElementR()
以及乍一看,你正在混合Rcpp和RcppArmadillo类型,以便与后者合并。这将创建大量的副本。我们现在可以用Rcpp(和Kevin在这里有一些答案)和RcppArmadillo(几个较旧的答案)进行索引,这样你甚至可以尝试两种不同的方式。