【问题标题】:How to scale a NumericMatrix in-place with Rcpp?如何使用 Rcpp 就地缩放 NumericMatrix?
【发布时间】:2020-01-09 02:20:58
【问题描述】:

这就是我现在正在做的事情

library(Rcpp)

A <- diag(c(1.0, 2.0, 3.0))
rownames(A) <- c('X', 'Y', 'Z')
colnames(A) <- c('A', 'B', 'C')

cppFunction('
void scaleMatrix(NumericMatrix& A, double x) {
    A = A * x;
}')

不幸的是它不起作用:(

> A
  A B C
X 1 0 0
Y 0 2 0
Z 0 0 3
> scaleMatrix(A, 2)
> A
  A B C
X 1 0 0
Y 0 2 0
Z 0 0 3

我从Rcpp FAQ, Question 5.1 那里了解到,Rcpp 应该能够更改我按值传递的对象。从Dirk's answer 中偷一个例子到我之前的问题:

> library(Rcpp)
> cppFunction("void inplaceMod(NumericVector x) { x = x * 2; }")
> x <- as.numeric(1:5)
> inplaceMod(x)
> x
[1]  2  4  6  8 10

我很困惑:可以就地修改NumericVector,但不能修改NumericMatrix

【问题讨论】:

  • 你能澄清一下吗?你真的要修改A吗?您的代码当前确实复制了 A。
  • @Roland 是的,我确实想就地修改A。该问题做出了错误的假设并已更新。很抱歉!

标签: c++ r matrix rcpp syntactic-sugar


【解决方案1】:

您可以使用NumericVector 而不是NumericMatrix 来保留行名和列名,请记住,R 中的矩阵只是一个带有附加维度的向量。您可以在从 R 转到 C++(下面的scaleVector)或在 C++ 中(下面的scaleMatrix 取自 @Roland 现已删除的答案)时进行此切换:

library(Rcpp)
cppFunction('
NumericVector scaleVector(NumericVector& A, double x) {
    A = A * x;
    return A;
}')

cppFunction('
NumericMatrix scaleMatrix(NumericMatrix& A, double x) {
    NumericVector B = A;
    B = B * x;
    return A;
}')

如果将这两个函数应用于您的矩阵,则保留行名和列名。但是,矩阵并没有原地改变:

A <- diag(1:3)
rownames(A) <- c('X', 'Y', 'Z')
colnames(A) <- c('A', 'B', 'C')

scaleMatrix(A, 2)
#>   A B C
#> X 2 0 0
#> Y 0 4 0
#> Z 0 0 6
scaleVector(A, 2)
#>   A B C
#> X 2 0 0
#> Y 0 4 0
#> Z 0 0 6
A
#>   A B C
#> X 1 0 0
#> Y 0 2 0
#> Z 0 0 3

原因是diag(1:3)实际上是一个整数矩阵,所以当你将它转移到一个数字矩阵(或向量)时会进行复制:

is.integer(A)
#> [1] TRUE

如果使用数字矩阵开始,则修改就地完成:

A <- diag(c(1.0, 2.0, 3.0))
rownames(A) <- c('X', 'Y', 'Z')
colnames(A) <- c('A', 'B', 'C')

scaleMatrix(A, 2)
#>   A B C
#> X 2 0 0
#> Y 0 4 0
#> Z 0 0 6
scaleVector(A, 2)
#>   A B  C
#> X 4 0  0
#> Y 0 8  0
#> Z 0 0 12
A
#>   A B  C
#> X 4 0  0
#> Y 0 8  0
#> Z 0 0 12

【讨论】:

  • 可能是因为 ALTREP?
  • @RalfStubner 可能有点跑题了,但如果A 必须是NumericMatrix 怎么办?在我的应用程序中,A 是在 C++ 代码中创建的,而不是从 R 中传入的,而且它应该以 NumericMatrix 的形式返回。您是否建议使用 as&lt;NumericVector&gt; 之类的东西进行投射,然后将结果投射回来?无论如何,如果 NumericMatrix 的内容存储在连续的内存块中(至少在 R 中,矩阵只是带有 dim 的向量),那么最好的方法可能是使用 for 循环缩放每个元素,但我可以访问NumericMatrix 的内部成员吗?
  • @nalzok 我删除了这样做的答案,但您可以执行NumericVector B = A; 并修改B。 if 也会在原地修改A(因为A 在内部是一个向量)。
  • @Roland 我已经恢复了那段代码,以便
  • 我很喜欢你的代码。能否请您同时展示两者(对初学者特别有用)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-17
  • 1970-01-01
  • 1970-01-01
  • 2020-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多