具有rcpp和RcppArmadillo的多元正态/高斯函数的一阶导数
我试图在R中实现多元正态分布的一阶导数,建立在多元正态分布的具有rcpp和RcppArmadillo的多元正态/高斯函数的一阶导数,r,rcpp,R,Rcpp,我试图在R中实现多元正态分布的一阶导数,建立在多元正态分布的rcpp实现的基础上 下面是一个快速的R实现 mvnormDeriv = function(..., mu=rep(0,length(list(...))), sigma=diag(length(list(...)))) { if(sd(laply(list(...),length))!=0) stop("The vectors not same length.") fn = function(x) -1
rcpp
实现的基础上
下面是一个快速的R实现
mvnormDeriv = function(..., mu=rep(0,length(list(...))), sigma=diag(length(list(...)))) {
if(sd(laply(list(...),length))!=0)
stop("The vectors not same length.")
fn = function(x) -1 * c((1/sqrt(det(2*pi*sigma))) * exp(-0.5*t(x-mu)%*%solve(sigma)%*%(x-mu))) * solve(sigma,(x-mu))
out = t(apply(cbind(...),1,fn))
colnames(out) = c('x', 'y')
return(out[,1])
}
以及一些具有基准的测试数据:
set.seed(123456789)
sigma = rWishart(1, 2, diag(2))
means = rnorm(2)
X = rmvnorm(10000, means, sigma[,,1])
x1 = X[,1]
x2 = X[,2]
benchmark(mvnormDeriv(x1,x2,mu=means,sigma=sigma),
order="relative", replications=5)[,1:4]
该配方可在matrix cookbook(2012)配方346中找到
我未能修改多变量正态分布的rcpp
实现。下面是一些代码,我曾经尝试过
// [[Rcpp::export]]
arma::vec dmvnormDeriv_arma(arma::mat x, SEXP mu_sexp, arma::mat sigma, bool log = false) {
// create Rcpp vector and matrix from SEXP arguments
Rcpp::NumericVector mu_rcpp(mu_sexp);
// create views for arma objects(reuses memory and avoids extra copy)
arma::vec mu_vec(mu_rcpp.begin(), mu_rcpp.size(), false);
arma::rowvec mu(mu_rcpp.begin(), mu_rcpp.size(), false);
// return(mu_vec);
arma::vec distval = Mahalanobis(x, mu, sigma);
double logdet = sum(arma::log(arma::eig_sym(sigma)));
double log2pi = std::log(2.0 * M_PI);
arma::vec val = exp(-( (x.n_cols * log2pi + logdet + distval)/2));
// x.each_row() -= mu;
// arma::vec val2 = solve(sigma, x.row(1));
// arma::vec retval = -1 * val(1) * solve(sigma, x.row(1)-mu_vec);
return(val);
}
当然,这还不完全。我有什么想法可以在
rcpp
或Armadillo
中实现*求解(sigma,(x-mu))
部分吗?我在处理不同的变量类型和为x的每一行运行solve时遇到问题。这里有一个基于RcppArmadillo
的解决方案。它比R实现快100多倍。首先,C++实现,依赖于.< /p>
最后,一些基准:
set.seed(123456789)
sigma = rWishart(1, 2, diag(2))[,,1]
means = rnorm(2)
X = rmvnorm(10000, means, sigma)
benchmark(dmvnormderiv_arma(X,means,sigma),
mvnormDeriv(X,mu=means,sigma=sigma),
dmvnormDeriv(X,mean=means,sigma=sigma),
order="relative", replications=5)[,1:4]
test replications elapsed
1 dmvnormderiv_arma(X, means, sigma) 5 0.016
3 dmvnormDeriv(X, mean = means, sigma = sigma) 5 2.118
2 mvnormDeriv(X, mu = means, sigma = sigma) 5 5.939
relative
1 1.000
3 132.375
2 371.187
那不是
solve()
只是inv()
的一个(可能是Matlab-)缩写吗?在这种情况下,你可以直接从犰狳医生那里拿到。[我们将更新您提到的图库帖子;请密切关注。然后提交一篇带有以下内容的帖子:)]谢谢,我在下面添加了一个解决方案。如果有兴趣的话,我会为画廊提交一些东西。如果您有改进建议,请告诉我。但是您提到使用2012年的Matrix Cookbook,您能提供问题中的链接吗?很难找到。在主题方面,它可能有助于使问题更加独立。非常感谢。干得好。看起来不错,差不多准备好了。查看现有的.Rmd
(或者,如果您愿意,.cpp
)文件,或者通过邮件向我发送一些东西,或者fork并执行Github上常见的pull请求操作。与sum(arma::log(arma::eig_sym(sigma))不同,Rmd文件的要点是可能更有效的标记。我将在gallery github页面中添加一个问题,以便继续讨论。
library('RcppArmadillo')
library('mvtnorm')
library('rbenchmark')
sourceCpp('mvnorm.cpp')
mvnormDeriv = function(X, mu=rep(0,ncol(X)), sigma=diag(ncol(X))) {
fn = function(x) -1 * c((1/sqrt(det(2*pi*sigma))) * exp(-0.5*t(x-mu)%*%solve(sigma)%*%(x-mu))) * solve(sigma,(x-mu))
out = t(apply(X,1,fn))
return(out)
}
dmvnormDeriv = function(X, mean, sigma) {
if (is.vector(X)) X <- matrix(X, ncol = length(X))
if (missing(mean)) mean <- rep(0, length = ncol(X))
if (missing(sigma)) sigma <- diag(ncol(X))
n = nrow(X)
mvnorm = dmvnorm(X, mean = mean, sigma = sigma)
deriv = array(NA,c(n,ncol(X)))
for (i in 1:n)
deriv[i,] = -mvnorm[i] * solve(sigma,(X[i,]-mean))
return(deriv)
}
set.seed(123456789)
sigma = rWishart(1, 2, diag(2))[,,1]
means = rnorm(2)
X = rmvnorm(10000, means, sigma)
benchmark(dmvnormderiv_arma(X,means,sigma),
mvnormDeriv(X,mu=means,sigma=sigma),
dmvnormDeriv(X,mean=means,sigma=sigma),
order="relative", replications=5)[,1:4]
test replications elapsed
1 dmvnormderiv_arma(X, means, sigma) 5 0.016
3 dmvnormDeriv(X, mean = means, sigma = sigma) 5 2.118
2 mvnormDeriv(X, mu = means, sigma = sigma) 5 5.939
relative
1 1.000
3 132.375
2 371.187