分配了矩阵列标准差的向量正在改变其值 (RcppArmadillo)

Posted

技术标签:

【中文标题】分配了矩阵列标准差的向量正在改变其值 (RcppArmadillo)【英文标题】:Vector assigned the standard deviation of matrix columns is changing its value (RcppArmadillo) 【发布时间】:2019-01-25 21:05:47 【问题描述】:

我正在开发一个 RcppArma 包,我正在为提升算法集中和标准化一个设计矩阵,这是被剥离的代码:

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

#include <RcppArmadillo.h>
using namespace Rcpp;
using namespace arma;

// [[Rcpp::export]]
List centering(arma::mat & X) 

   int p = X.n_cols;

   rowvec meanx(p);
   rowvec sigmax(p);

    meanx=mean(X,0);
    sigmax=stddev(X,0);

    for(int j=0;j<p;j++)
    
      X.col(j)=X.col(j)-meanx(j);
      X.col(j)=X.col(j)/sigmax(j);
    

  return List::create(Named("sigma") = sigmax, Named("X") = X);

居中工作正常,但在居中后,向量“sigmax”的所有值都等于“1”,因此向量以某种方式将自身更新为居中矩阵 X 的新标准偏差,而无需重新分配。我需要原始值来回变换系数。为什么这样做?我怎样才能避免这种情况?

我使用以下代码在 R 中测试了该函数:

set.seed(42)    
X <- replicate(10, rnorm(100, 5, 3))
res <- centering(X)
res <- centering(X)

当我第二次调用它时出现问题。第一次成功。

【问题讨论】:

嗨奥利弗,欢迎来到 SO!请考虑查看this 以了解最低限度可验证的可重现示例。它们使我们更容易为您提供帮助。 嗨,Dirk,感谢您的回答和帮助,我阅读了它并将问题简化为一个新问题。我希望这可以帮助您了解我的问题。 是的,看起来更好。我现在很忙,无法处理这个问题——但您是否也可以在 R 中添加两行代码来调用一些模拟数据? 好的!基本上我直接在 RStudio 中调用它并生成一个随机的 10x100 X~(5,3)。 Rcpp FAQ 和其他地方解决了这个问题。本质上,您传递的是一个指针,如果您分配给它,传入的数据可能会被更改。这是由于 R 如何为我们提供这个接口。如果您需要,请查看 Rcpp::clone() 以创建不同的(本地)副本。另外:你的例子不是最小的。我们需要一个长度为 10 的列表吗?我们需要矩阵上的 500 行吗? 【参考方案1】:

简单地说:不要在函数定义中将引用 (&amp;) 与参数 X 一起使用。这激活了 RcppArmadillo 对 an advanced constructor for arma::mat 的使用,它重用了 R 对象内存(c.f. include/RcppArmadilloWrap.h

所以,要解决这个问题,请从:

List centering_reuse_memory(arma::mat & X) 
                                    # ^ reference/reuse
  # Routine given in OP

收件人:

List centering_new_memory(arma::mat X) 
                                 # ^ Direct copy

  # Routine given in OP

了解分享...

我们来看看对象是如何变化的。

# Create the original object
set.seed(42)    
X <- replicate(3, rnorm(5, 5, 3))

# Create a duplicate object not sharing memory with X
set.seed(42)    
X_clone <- replicate(3, rnorm(5, 5, 3))

# View object
X
#         [,1]      [,2]       [,3]
# [1,] 9.112875  4.681626  8.9146090
# [2,] 3.305905  9.534566 11.8599362
# [3,] 6.089385  4.716023  0.8334179
# [4,] 6.898588 11.055271  4.1636337
# [5,] 6.212805  4.811858  4.6000360

# Check equality
all.equal(X, X_clone)
# [1] TRUE

现在,以arma::mat &amp; X的参数传递运行函数

res <- centering_reuse_memory(X)

# Verify results are the same.
all.equal(X, X_clone)
# [1] "Mean relative difference: 8.387859"

# Check X manually to see what changed... 
X
#             [,1]       [,2]       [,3]
# [1,]  1.34167459 -0.7368308  0.6566715
# [2,] -1.45185917  0.8327104  1.3376293
# [3,] -0.11282266 -0.7257062 -1.2116948
# [4,]  0.27645691  1.3245379 -0.4417510
# [5,] -0.05344967 -0.6947113 -0.3408550

为什么会有差异?好吧,通过使用引用,C++ 函数中的修改传播回驻留在 R 中的 X 变量,该变量匹配 存储在 @ 的对象987654333@.

# Verify R's X matches the saved C++ routine X modification
all.equal(X, res$X)
# [1] TRUE

【讨论】:

以上是关于分配了矩阵列标准差的向量正在改变其值 (RcppArmadillo)的主要内容,如果未能解决你的问题,请参考以下文章

线性代数——矩阵乘法(续)

如何用MATLAB将特征向量标准化

在标准向量中将元素分配给 Eigen::Vector2d 会引发错误

矩阵向量差的有效元素 argmin

分配向量中元素的索引而不是其值

Matlab:分配给具有列\行索引对的矩阵[重复]