我正在尝试在java中创建逻辑回归算法,但是当我计算可能性的对数时,它总是返回NaN。我计算对数的方法如下:
//Calculate log likelihood on given data
private double getLogLikelihood(double cat, double[] x) {
return cat * Math.log(findProbability(x))
+ (1 - cat) * Math.log(1 - findProbability(x));
}
findProbability方法只是从数据集中获取一个实例并返回sigmoid funcion结果,该结果介于0和1之间。
//Calculate the sum of w * x for each weight and attribute
//call the sigmoid function with that s
public double findProbability(double[] x){
double s = 0;
for(int i = 0; i < this.weights.length; i++){
if(i >= x.length) break;
s += this.weights[i] * x[i];
}
return sigmoid(s);
}
private double sigmoid(double s){
return 1 / (1 + Math.exp(-s));
}
此外,我的起始重量是:
[-0.2982955509135178, -0.4984900460081106, -1.816880187922516, -2.7325608512266073, 0.12542715714800834, 0.1516078084483485, 0.27631147403449774, 0.1371611094778011, 0.16029832096058613, 0.3117065974657231, 0.04262385176091778, 0.1948263133838624, 0.10788353525185314, 0.770608588466501, 0.2697281907888033, 0.09920694325563077, 0.003224073601703939, 0.021573742410541247, 0.21528348692817675, 0.3275511757298476, -0.1500597314893408, -0.7221692528386277, -2.062544912370121, 1.4315146889363015, 0.2522133355419722, 0.23919315019065995, 0.3200037377021523, 0.059466770771758076, 0.04012493980772944, 0.2553236501265919]
最后,我的数据集中的一个实例是:[M,17.99,10.38,122.8,1001,0.1184,0.2776,0.3001,0.1471,0.2419,0.07871,1.095,0.9053,8.589,153.4,0.006399,0.04904,0.05373,0.01587,0.03003,0.006193,25.38,17.33,184.6,2019,0.1622,0.6656,0.7119,0.2654,0.4601,0.1189
]
我尝试用不同的随机数初始化起始权重,但那并没有解决问题。
答案 0 :(得分:0)
NaN是除以零或在非正数字上调用Math.log的结果,所以你应该尝试找到恰好发生这种情况的地方。我建议调试或添加代码来打印你的对数/ dividy的值。
编辑:它似乎是一个舍入错误:exp(-s)将返回一个如此小的结果,加上1,它仍将保持为1.这会导致对数返回-Inf。我建议你试着通过尝试近似指数的对数来找到解决这个问题的数学方法。
答案 1 :(得分:0)
arithematic导致舍入错误,让你得到1。
{{1}}
b将等于1,因为否则你将需要太多的sig figs。您必须近似值才能保持精度。 1 /(1 + s)〜= 1 - s;这意味着您需要计算log(1)和log(s)。
编辑:对不起,我犯了一个错误,看似Math.exp(-3522)在四舍五入后被评估为0。我留下这个答案,因为Math.exp(-x)可能太小而不能加1,或者它可能只是零。
答案 2 :(得分:0)
我找到了解决问题的方法,所以我在这里发布: 我添加了溢出检查:
private double sigmoid(double s){
if(s>20){
s=20;
}else if(s<-20){
s=-20;
}
double exp = Math.exp(s);
return exp/(1+exp);
}
同样,将1/(1+Math.exp(s)
更改为exp/(1+exp)
会在输入的小扰动中更加稳定。