简体   繁体   中英

matrix of Uniform distribution Rcpp

I'm trying to create a function, which creates an matrix of size nxm, with entries of the uniform distribution, with the Rcpp package. (I'm inexperienced using this package.)

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

Expected output

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

Well with

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

you explicitly only assign to the first column. So just loop over all m column doing the same.

Another (inside-baseball) way is to request a vector of n*m, and then set the dim attributes of (n,m) to make it a matrix.

Related, there is IIRC a constructor that would take that vector and re-dim it.

Edit: And that last approach is the simplest and works like this:

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> 

Edit 2: Additional variants as F.Privé insists on arguing:

We can add these two:

// [[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); 
}

and then get

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> 

In the OP's code, the assignment only happens for the 1st column index ie 0 . We can loop through the column index and assign the uniform distribution values

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

Generally, I would use the second idea of Dirk: changing the dimension of a vector so that it becomes a matrix.

#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)
)
*/

Microbenchmark:

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

So, mu2 is a bit faster because it doesn't make any copy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM