提取rcpp

时间:2018-10-17 06:46:15

标签: r rcpp armadillo

我正在努力处理arma :: mat类矩阵的子集列。

假设给出了arma::mat X,并且我尝试创建索引向量IDX,以便进行X.cols(IDX)。特别地,索引向量具有从1到p(X的维数)的第k个整数。例如,可能对每个偶数列IDX=[2,4,6,8, ...]都感兴趣。

基于this documentation,如果m <= p,则可以使用X.cols(0, m - 1)轻松提取诸如[0,1,2,...,m-1]的连续索引。但是,我找不到用上述索引向量IDX子集矩阵的好方法。

我想知道如何完成此代码以提供所需的输出。

我的“ subset_armamat.cpp”文件看起来像

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
using namespace arma;

// [[Rcpp::export]]
mat subset_armamat(mat X, int k){
  uvec IDX = "every k-th integer from 0 to X.ncols";
  return X.cols(IDX);
}

执行所定义函数的R代码是

library("Rcpp")
sourceCpp("subset_armamat.cpp")
subset_armamat(matrix(1:10, 2, 5, byrow = T), 2)

这将产生一个2 x 3矩阵,如以下R代码所给出的

> matrix(1:10, 2, 5, byrow = T)[,seq(1, 5, by = 2)]
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    6    8   10

如果您提供任何输入,将不胜感激。

p.s。我试图

  • 手动生成序列向量seq(1,m) * 2,但这不适用于X.cols()
  • 或使用find(seq(1,p) % 2 == 0)查找索引,但是%运算符在seq(1,p)2之间不能很好地工作。

2 个答案:

答案 0 :(得分:4)

F. Privé's answer表明,实际上,您可以使用s使用uvec来对矩阵进行子集化,即使它不是连续的范围,也可以使用基数R .cols()函数生成序列。我将进一步说明,您可以使用Armadillo函数生成序列。您可以使用seq() -它“生成具有规则间隔元素的向量”(Armadillo documentation source):

arma::regspace()

与调用R的// [[Rcpp::depends(RcppArmadillo)]] #include <RcppArmadillo.h> using namespace Rcpp; using namespace arma; // [[Rcpp::export]] mat subset_armamat(mat X, int k) { uvec IDX = regspace<uvec>(0, k, X.n_cols-1); return X.cols(IDX); } (其中seq()是F.Privé的答案中的函数)的比较:

subset_armamatR()

reprex package(v0.2.1)于2018-10-17创建

更新:通过引用传递

来自hbrerkere的评论值得进行一些简短的额外讨论。如果从C ++调用此函数,则可以通过将library("Rcpp") sourceCpp("subset_armamat.cpp") mat <- matrix(1:10, 2, 5, byrow = TRUE) subset_armamat(mat, 2) #> [,1] [,2] [,3] #> [1,] 1 3 5 #> [2,] 6 8 10 subset_armamatR(mat, 2) #> [,1] [,2] [,3] #> [1,] 1 3 5 #> [2,] 6 8 10 library(microbenchmark) microbenchmark(Rseq = subset_armamatR(mat, 2), regspace = subset_armamat(mat, 2)) #> Unit: microseconds #> expr min lq mean median uq max neval cld #> Rseq 235.535 239.1615 291.1954 241.9850 248.6005 4704.467 100 a #> regspace 14.221 15.0225 520.9235 15.8165 16.6740 50408.375 100 a 更改为mat subset_armamat(mat X, int k)来提高速度。这样通过引用传递可避免不必要的复制,并且当您不打算更改通过引用传递的对象时,应使用mat subset_armamat(const mat& X, int k)。但是,如果您是从R调用此函数,则无法避免复制,因为const不是本机R类型(例如,参见this answerDirk Eddelbuettel(两者的维护者) RcppRcppArmadillo)。请考虑以下示例:

arma::mat

然后从R呼叫:

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>

// [[Rcpp::export]]
void reference_example(arma::mat& X) {
    X(0, 0) = 42;
}

// [[Rcpp::export]]
void print_reference_example(arma::mat X) {
    reference_example(X);
    Rcpp::Rcout << X << "\n";
}

reprex package(v0.2.1)于2018-10-18创建

答案 1 :(得分:2)

这有效:

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
using namespace arma;

// [[Rcpp::export]]
mat subset_armamat(mat X, int k) {

  // Obtain environment containing function
  Rcpp::Environment base("package:base"); 

  // Make function callable from C++
  Rcpp::Function seq = base["seq"];    

  uvec IDX = as<uvec>(seq(0, X.n_cols, k));
  return X.cols(IDX);
}

我只是从Rcpp调用R函数base::seq()