Rcpp中数值向量与arma::vec的判定

Rcpp中数值向量与arma::vec的判定,r,rcpp,armadillo,R,Rcpp,Armadillo,使用RcppArmadillo,使用arma::vec从R到Rcpp的转换与使用Rcpp和NumericVector一样简单。我的项目使用RcppArmadillo 我不确定该用什么,NumericVector或arma::vec?这两者之间的主要区别是什么?什么时候用哪个?使用其中一个是否有性能/内存优势?成员功能的唯一区别是什么?作为一个额外的问题:我应该考虑 ARMA::COLVEC 还是 ARMA::RoVEC < /COD>?< /P> 这两者之间的主要区别是什么 Rcpp中的*Vec

使用RcppArmadillo,使用
arma::vec
从R到Rcpp的转换与使用Rcpp和
NumericVector
一样简单。我的项目使用RcppArmadillo

我不确定该用什么,
NumericVector
arma::vec
?这两者之间的主要区别是什么?什么时候用哪个?使用其中一个是否有性能/内存优势?成员功能的唯一区别是什么?作为一个额外的问题:我应该考虑<代码> ARMA::COLVEC 还是<代码> ARMA::RoVEC < /COD>?< /P> 这两者之间的主要区别是什么

Rcpp中的
*Vector
*Matrix
类充当R的SEXP表示的包装器,例如作为数据指针的s表达式。有关Rcpp的设计,请通过将包含指向数据指针的类构造C++对象来实现这一点。这促进了两个关键特性:

R和C++对象之间的无缝迁移,以及 Low传递代价在R和C++之间,因为只有指针被传递。
  • 因为数据不是复制的,而是引用的
<> >,<>代码> ARMA对象类似于传统的<代码> STD::vector < /代码>,在R和C++对象之间发生深度拷贝的方式。此语句有一个例外,即存在,它允许在
犰狳
对象的结构中重用R对象后面的内存。因此,如果你不小心,你可能会在从R到C++的过渡过程中遭受不必要的惩罚,反之亦然。p> 注意:允许内存重用的高级构造函数不存在。因此,使用稀疏矩阵的引用可能不会产生期望的速度,因为从R到C++和Real.< /P>执行拷贝。 您可以主要基于“通过引用传递”或“通过复制传递”范式来查看差异。要理解代码之外的差异,请考虑下面的GIF:

在代码中说明这个场景,考虑以下三个函数:

#include <RcppArmadillo.h>

// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
void memory_reference_double_ex(arma::vec& x, double value) {
    x.fill(value);
}

// [[Rcpp::export]]
void memory_reference_int_ex(arma::ivec& x, int value) {
    x.fill(value);
}

// [[Rcpp::export]]
arma::vec memory_copy_ex(arma::vec x, int value) {
    x.fill(value);
    return x;
}
#include <RcppArmadillo.h>

// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
void copy_double_ex(arma::vec x, double value) {
    x.fill(value);
}

// [[Rcpp::export]]
void reference_double_ex(arma::vec& x, double value) {
    x.fill(value);
}
现在,如果R对象的基础类型是
整数而不是
双精度
,会发生什么

x = c(1L, 2L, 3L, 4L)
typeof(x)
# [1] "integer"

x
# [1] 1 2 3 4

# Return nothing...
memory_reference_double_ex(x, value = 9)

x
# [1] 1 2 3 4
发生了什么事?为什么
x
没有更新?好的,在幕后,Rcpp创建了一个新的内存分配,它是正确的类型--
double
而不是
int
,然后将它传递给
armadillo
。这导致两个对象之间的引用“链接”不同

如果我们在
犰狳
向量中更改为使用整数数据类型,请注意,我们现在具有前面给出的相同效果:

memory_reference_int_ex(x, value = 3)

x
# [1] 3 3 3 3
这导致了对这两种范式有用性的讨论。在使用C++时,速度是首选的基准,让我们从一个基准来查看。p> 考虑以下两个功能:

#include <RcppArmadillo.h>

// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
void memory_reference_double_ex(arma::vec& x, double value) {
    x.fill(value);
}

// [[Rcpp::export]]
void memory_reference_int_ex(arma::ivec& x, int value) {
    x.fill(value);
}

// [[Rcpp::export]]
arma::vec memory_copy_ex(arma::vec x, int value) {
    x.fill(value);
    return x;
}
#include <RcppArmadillo.h>

// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
void copy_double_ex(arma::vec x, double value) {
    x.fill(value);
}

// [[Rcpp::export]]
void reference_double_ex(arma::vec& x, double value) {
    x.fill(value);
}

注意:每次迭代引用的对象比复制的范例快约6.509771倍,因为我们不必重新分配和填充内存

什么时候用哪个

你需要做什么

你只是想快速加速一个依赖循环但不需要严格线性代数操作的算法吗

如果是这样,只使用Rcpp就足够了

你正在尝试执行线性代数运算吗? 或者您是否希望跨多个库或计算平台(例如MATLAB、Python、R等)使用此代码

如果是这样,您应该在armadillo中编写算法的关键,并设置适当的钩子,以使用Rcpp将函数导出到R中

使用其中一个是否有性能/内存优势

是的,如前所述,肯定有性能/内存优势。不仅如此,通过使用RcppArmadillo,您还可以有效地在Rcpp上添加一个额外的库,从而增加总体安装占用空间、编译时间和系统需求(请参阅macOS构建的麻烦)。找出你的项目需要什么,然后选择那种结构

成员功能的唯一区别是什么

不仅是成员功能,而且:

  • 基于矩阵分解的估计例程
  • 计算统计数量值
  • 对象生成
  • 稀疏表示(避免操纵S4对象)
这些是Rcpp和犰狳之间的根本区别。一个是为了方便R对象转移到C++,而另一个则是为了更严格的线性代数计算。这在很大程度上是显而易见的,因为Rcpp不执行任何矩阵乘法逻辑,而犰狳使用系统的基本线性代数子程序(BLAS)执行计算

作为一个额外的问题:我是否应该考虑ARMA::CalvEC或ARMA::RoVEC?< /P> 取决于您希望返回结果的方式。是否要使用:
1 x N
(行向量)或
N x 1
(列向量)<默认情况下,code>RcppArmadillo
将这些结构作为矩阵对象返回,并具有适当的维度,而不是传统的1D R向量

例如:

#include <RcppArmadillo.h>

// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
arma::vec col_example(int n) {
    arma::vec x = arma::randu<arma::vec>(n);
    return x;
}


// [[Rcpp::export]]
arma::rowvec row_example(int n) {
    arma::rowvec x = arma::randu<arma::rowvec>(n);
    return x;
}

@coatless的回答是正确的,但它会向你提供你没有要求的细节

同时,你的问题没有明确说明,因为你没有说明你需要向量做什么。有了这个警告,我会这么说

  • 对于简单的用例,Rcpp很好,而RcppArmadillo也同样好
  • 对于需要线性代数的用例,首选RcppArmadillo
  • 性能在很大程度上是等效的,但需要注意的是,正如上面所讨论的,您希望对RcppArmadillo进行显式的“引用调用”
  • 只读向量访问(比如,
    set.seed(1)
    col_example(4)
    #           [,1]
    # [1,] 0.2655087
    # [2,] 0.3721239
    # [3,] 0.5728534
    # [4,] 0.9082078
    
    set.seed(1)
    row_example(4)
    #           [,1]      [,2]      [,3]      [,4]
    # [1,] 0.2655087 0.3721239 0.5728534 0.9082078