评估c ++中的多元正态/高斯密度

时间:2017-01-08 21:28:13

标签: c++ eigen normal-distribution

现在我有以下函数来评估高斯密度:

double densities::evalMultivNorm(const Eigen::VectorXd &x, const Eigen::VectorXd &meanVec, const Eigen::MatrixXd &covMat)
{
    double inv_sqrt_2pi = 0.3989422804014327;
    double quadform  = (x - meanVec).transpose() * covMat.inverse() * (x-meanVec);
    double normConst = pow(inv_sqrt_2pi, covMat.rows()) * pow(covMat.determinant(), -.5);
    return normConst * exp(-.5* quadform);
}

这只是转录formula。但是我得到了很多0,nans和infs。我怀疑它来自covMat.determinant()部分非常接近于零。

我听说通过其协方差矩阵的“平方根”的倒数预乘x-meanVec更“稳定”。统计上,这给出了一个平均为零的随机向量,并且具有单位矩阵作为其协方差矩阵。我的问题是:

  1. 这真的是最好的方式吗?
  2. 哪种是“最佳”平方根技术,
  3. 我该怎么办? (最好使用Eigen)

1 个答案:

答案 0 :(得分:3)

广告1:“取决于”。例如,如果你的协方差矩阵有一个特殊的结构,可以很容易地计算它的倒数,或者如果维数非常小,那么可以更快,更稳定地实际计算逆。

广告2:通常,Cholesky分解可以胜任。如果您的协方差确实是正定的(即不接近半定矩阵),则分解covMat = L*L^T并计算squaredNorm(L\(x-mu))(其中x=A\b表示“求解A*x=b {{{ 1}}“)。当然,如果你的协方差是固定的,你应该只计算x一次(也许也可以反转它)。您也应该使用L来计算L,因为计算行列式否则需要再次分解sqrt(covMat.determinant())。 次要改进:而不是covMat计算pow(inv_sqrt_2pi, covMat.rows()),然后返回logSqrt2Pi=log(sqrt(2*pi))

广告3:这应该在Eigen 3.2或更高版本中运行:

exp(-0.5*quadform - covMat.rows()*logSqrt2Pi) / L.determinant()