Я не уверен, что Rcpp поможет, если вы не найдете хороший алгоритм для аппроксимации своего многомерного (cholesky, svd и т. Д.) И запрограммируйте его с помощью Eigen (RccpEigen) или Armadillo (используя RcppArmadillo).
Вот один подход, использующий разложение Холецкого и (Rcpp) Armadillo
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
using namespace arma;
using namespace Rcpp;
mat mvrnormArma(int n, mat sigma) {
int ncols = sigma.n_cols;
mat Y = randn(n, ncols);
return Y * chol(sigma);
}
Теперь наивная реализация в чистом R
mvrnormR <- function(n, sigma) {
ncols <- ncol(sigma)
matrix(rnorm(n * ncols), ncol = ncols) %*% chol(sigma)
}
Вы также можете проверить, если Everythings работать
sigma <- matrix(c(1, 0.9, -0.3, 0.9, 1, -0.4, -0.3, -0.4, 1), ncol = 3)
cor(mvrnormR(100, sigma))
cor(MASS::mvrnorm(100, mu = rep(0, 3), sigma))
cor(mvrnormArma(100, sigma))
Теперь давайте сравним его
require(bencharmk)
benchmark(mvrnormR(1e4, sigma),
MASS::mvrnorm(1e4, mu = rep(0, 3), sigma),
mvrnormArma(1e4, sigma),
columns=c('test', 'replications', 'relative', 'elapsed'))
## 2 MASS::mvrnorm(10000, mu = rep(0, 3), sigma) 100
## 3 mvrnormArma(10000, sigma) 100
## 1 mvrnormR(10000, sigma) 100
## relative elapsed
## 2 3.135 2.295
## 3 1.000 0.732
## 1 1.807 1.323
В этом примере я использовал нормальное распределение с единичной дисперсией и нулевым средним значением, но вы можете легко обобщить на гауссовский дистрибутив с пользовательским средним значением и дисперсией.
Надеюсь, что это поможет
Хороший ответ, +1. Вы хотите записать это для галереи Rcpp (gallery.rcpp.org)? –
@DirkEddelbuettel Спасибо большое. Да, будет очень приятно внести вклад в галерею Rcpp. Я разблокирую репозитории github и отправлю запрос на вытягивание. – dickoa
Простой файл как .Rmd или .cpp с разметкой тоже хорош, но вы, конечно же, тоже должны идти официальным и длинным путем ... –