数值稳定的方法来计算正常对数似然

时间:2012-01-06 14:46:33

标签: java numeric

我正在尝试计算正常的对数似然,由下式给出:

L = l1+l2+l3+...+ln,

其中

lk = log(1/(sqrt(2*PI)*sigma_k))-0.5*e_k*e_k

Sigmas在0.2附近,而e_k通常以均值0和单位方差分布,因此大多数都在-2和2之间;

我尝试了以下java代码(上面提到的sigma_k = sigmas.get(k)* Math.sqrt(dt)):

private double new1(List<Double> residuals, List<Double> sigmas, double dt) {
    double a = 0;
    for(int i=0; i<sigmas.size(); i++) {
        a += Math.log(1.0/(Math.sqrt(2*Math.PI*dt)*sigmas.get(i)));
    }
    double b = 0;
    for(int i=0; i<residuals.size(); i++) {
        b += residuals.get(i)*residuals.get(i);
    }
    return a-0.5*b;
}

但是理论最大值低于我通过数值优化得到的最大值,所以我怀疑我的方法不是最理想的。

2 个答案:

答案 0 :(得分:0)

我不确定它是否会大大提高数值稳定性,但使用对数定律可以简化方程式:

log(a*b) = log(a) + log(b)
log(1/a) = -log(a)
log(sqrt(a)) = log(a)/2

所以你有:

lk = -log(2*pi)/2 - log(sigma_k) - 0.5*e_k*e_k
   = -log(2*pi)/2 - log(dt)/2 - log(sigmas.get(k)) - 0.5*e_k*e_k
   = -log(2*pi*dt)/2 - log(sigmas.get(k)) - 0.5*e_k*e_k

首先是常数,所以在第一个循环中你只需要做a -= log(sigmas.get(k))

此外,看起来很可疑,第一个循环是sigmas.size(),第二个循环是residuals.size(),而等式表明它们应该具有相同的长度。

答案 1 :(得分:0)

<强>注: 在某些区域,计算概率/统计数据时不会采用 log ,例如在组合的语言频率中。

以下简化,变得不那么稳定,但之后将其转换回日志总和左右。


double a = 0;
for(int i=0; i<sigmas.size(); i++) {
    a += Math.log(1.0/(Math.sqrt(2*Math.PI*dt)*sigmas.get(i)));
}

log(x)+ log(y)= log(x * y)

double a = 1.0;
for(int i=0; i<sigmas.size(); i++) {
    a *= 1.0/(Math.sqrt(2*Math.PI*dt)*sigmas.get(i));
}
a = Math.log(a);

(1 / x)*(1 / y)= 1 /(x * y)

double a = 1.0;
for(int i=0; i<sigmas.size(); i++) {
    a *= Math.sqrt(2*Math.PI*dt)*sigmas.get(i);
}
a = Math.log(1.0/a);

sqrt(x)^ n =(x ^ 0.5)^ n = x ^(n / 2)

static import Math.*;

double a = pow(2*PI*dt, sigmas.size() / 2.0);
for(int i=0; i<sigmas.size(); i++) {
    a *= sigmas.get(i);
}
a = -log(a);