我有一个关于快速实施的问题。假设您有一个矩阵Ys,其中每行都引用一个源自多元正态分布的观测值向量,例如
Ys = matrix(c(1.0,1.0,1.0,0.0,0.5,0.6,0.1,0.1,0.3), nrow = 3, ncol = 3)
此外,还有一个矩阵Sigs,其中每一行都引用Ys中每个结果向量的方差协方差矩阵的对角元素,例如
Sigs = matrix(c(1.0,0.5,0.1,0.2,0.3,0.4,0.3,0.7,0.8), nrow = 3, ncol = 3)
我要做的是给定Sigs中相应行的对角线元素,计算Ys中每一行的密度值。
例如,可以在R中使用for循环
colSigs = ncol(Sigs)
res = rep(0,3)
means = rep(0,colSigs)
for (i in 1:nrow(Ys) ) {
sigma = diag(Sigs[i,],colSigs)
res[i] = mvtnorm::dmvnorm(Ys[i,],means,sigma)
}
但是,在我的情况下,Y和Sig包含大约100,000行。因此,我编写了一个Rcpp函数,它的速度要快得多。但是,我想知道是否有一个花哨的技巧(一种更有效的方法),这样我就不必执行循环了?任何想法都欢迎。
编辑:我被要求添加Rcpp函数。在这里,您去了:
此函数计算在多元法线密度中出现的二次形式:
double dmvnorm_distance( arma::rowvec y, arma::mat Sigma )
{
int n = Sigma.n_rows;
double res=0;
double fac=1;
for (int ii=0; ii<n; ii++){
for (int jj=ii; jj<n; jj++){
if (ii==jj){ fac = 1; } else { fac = 2;}
res += fac *y(0,ii) * Sigma(ii,jj) * y(0,jj);
}
}
return res;
}
此函数计算密度值:
double dmvnorm_rcpp(arma :: rowvec y,arma :: mat Sigma) {
int p = Sigma.n_rows;
// inverse Sigma
arma::mat Sigma1 = arma::inv(Sigma);
// determinant Sigma
double det_Sigma = arma::det(Sigma);
// distance
double dist = dmvnorm_distance( y, Sigma1);
double pi1 = 3.14159265358979;
double l1 = - p * std::log(2*pi1) - dist - std::log( det_Sigma );
double ll = 0.5 * l1;
return ll;
}
此函数包含for循环,并从R中调用:
Rcpp::NumericVector mvnorm_loop( arma::mat Ys, arma::mat SIGs )
{
int n = Ys.n_rows;
Rcpp::NumericVector out(n);
for (int ii=0; ii<n; ii++){
// get yi and diagonal entries
arma::rowvec yi = Ys.row(ii);
arma::rowvec si = SIGs.row(ii);;
// make Sigma
arma::mat Sigma = arma::diagmat(si);
// compute likelihood value
out[ii] = dmvnorm_rcpp( yi, Sigma );
}
return out;
}
因此,基本上的问题是,是否存在另一种方法可以在Rcpp中实现插入,从而使整个过程更快。
最好, 斯蒂芬
PS:我也在R中使用了apply,它比Rcpp循环功能慢。