均匀分布矩阵Rcpp

时间:2018-04-14 02:59:03

标签: r rcpp

我试图创建一个函数,它使用Rcpp包创建一个大小为nxm的矩阵,其中包含均匀分布的条目。 (我没经验过这个包。)

library(Rcpp)
cppFunction('NumericMatrix rngCpp(const int n,const int m) {
   NumericMatrix X(n, m);
             X(_,0) = runif(n);
             return X;
             }')
set.seed(1)
rngCpp(4,5)
          [,1] [,2] [,3] [,4] [,5]
[1,] 0.2655087    0    0    0    0
[2,] 0.3721239    0    0    0    0
[3,] 0.5728534    0    0    0    0
[4,] 0.9082078    0    0    0    0

预期输出

set.seed(1)
matrix(runif(4*5), nrow=4, ncol = 5)
          [,1]      [,2]       [,3]      [,4]      [,5]
[1,] 0.2655087 0.2016819 0.62911404 0.6870228 0.7176185
[2,] 0.3721239 0.8983897 0.06178627 0.3841037 0.9919061
[3,] 0.5728534 0.9446753 0.20597457 0.7698414 0.3800352
[4,] 0.9082078 0.6607978 0.17655675 0.4976992 0.7774452

3 个答案:

答案 0 :(得分:7)

好吧

 X(_,0) = runif(n);

显式仅分配给第一列。所以只需循环遍历所有m列。

另一种(棒球内部)方式是请求n * m的向量,然后设置(n,m)的dim属性以使其成为矩阵。

相关的,IIRC是一个构造函数,可以使用该向量并重新调整它。

编辑:最后一种方法最简单,就像这样:

R> cppFunction('NumericMatrix mu(int n, int m) { 
       NumericVector v = runif(n*m); 
       return NumericMatrix(n, m, v.begin()); }')
R> set.seed(1); mu(4,5)
         [,1]     [,2]      [,3]     [,4]     [,5]
[1,] 0.265509 0.201682 0.6291140 0.687023 0.717619
[2,] 0.372124 0.898390 0.0617863 0.384104 0.991906
[3,] 0.572853 0.944675 0.2059746 0.769841 0.380035
[4,] 0.908208 0.660798 0.1765568 0.497699 0.777445
R> 

编辑2:其他变种如F.Privé坚持争论:

我们可以添加这两个:

// [[Rcpp::export]]
NumericMatrix mu3(int n, int m) { 
  return NumericMatrix(n, m, runif(n*m).begin()); 
}

// [[Rcpp::export]]
NumericMatrix mu4(int n, int m) { 
  NumericVector v = runif(n * m);
  v.attr("dim") = Dimension(n, m);
  return as<NumericMatrix>(v); 
}

然后获取

R> N <- 1000; M <- 1000

R> microbenchmark::microbenchmark(
+   mu(N, M),
+   mu2(N, M),
+   mu3(N, M),
+   mu4(N, M),
+   rngCpp(N, M)
+ )
Unit: milliseconds
         expr     min      lq    mean  median      uq     max neval
     mu(N, M) 4.77894 4.98485 7.32315 5.18153 5.36468 33.2427   100
    mu2(N, M) 3.99137 4.05308 5.43207 4.36296 4.57510 30.7335   100
    mu3(N, M) 4.73176 5.01524 6.35186 5.17173 5.39541 31.7425   100
    mu4(N, M) 3.99784 4.10052 4.72563 4.41176 4.60303 30.6166   100
 rngCpp(N, M) 5.18726 5.60165 7.53171 5.83892 6.14315 34.5934   100
R> 

答案 1 :(得分:4)

在OP的代码中,分配仅发生在第一列索引,即0。我们可以遍历列索引并分配统一分布值

cppFunction('NumericMatrix rngCpp(const int n,const int m) {
   NumericMatrix X(n, m);

             for(int i = 0; i < m; i++){
               X(_,i) = runif(n);
                 }
             return X;
             }')


set.seed(1)
rngCpp(4,5)
#          [,1]      [,2]       [,3]      [,4]      [,5]
#[1,] 0.2655087 0.2016819 0.62911404 0.6870228 0.7176185
#[2,] 0.3721239 0.8983897 0.06178627 0.3841037 0.9919061
#[3,] 0.5728534 0.9446753 0.20597457 0.7698414 0.3800352
#[4,] 0.9082078 0.6607978 0.17655675 0.4976992 0.7774452

答案 2 :(得分:1)

一般来说,我会使用Dirk的第二个想法:改变向量的维度,使其成为矩阵。

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector mu2(int n, int m) { 
  NumericVector v = runif(n * m);
  v.attr("dim") = Dimension(n, m);
  return v; 
}

// [[Rcpp::export]]
NumericMatrix mu(int n, int m) { 
  NumericVector v = runif(n*m); 
  return NumericMatrix(n, m, v.begin()); 
}

// [[Rcpp::export]]
NumericMatrix rngCpp(const int n,const int m) {
  NumericMatrix X(n, m);

  for(int i = 0; i < m; i++){
    X(_,i) = runif(n);
  }
  return X;
}

/*** R
set.seed(1); mu(4, 5)
set.seed(1); mu2(4, 5)

N <- 1000; M <- 1000
microbenchmark::microbenchmark(
  mu(N, M),
  mu2(N, M),
  rngCpp(N, M)
)
*/

微基准:

Unit: milliseconds
         expr      min        lq     mean    median        uq      max neval cld
     mu(N, M) 7.627591 10.290691 16.05829 10.932174 11.416555 119.2110   100   a
    mu2(N, M) 6.315160  6.590293 12.30125  8.510765  9.368282 117.8750   100   a
 rngCpp(N, M) 8.330158 10.306584 16.14374 10.893767 11.398675 121.4233   100   a

所以,mu2有点快,因为它不会复制任何内容。