/*
* GaussianEstimator.java
* Copyright (C) 2007 University of Waikato, Hamilton, New Zealand
* @author Richard Kirkby (rkirkby@cs.waikato.ac.nz)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package tr.gov.ulakbim.jDenetX.core;
import tr.gov.ulakbim.jDenetX.AbstractMOAObject;
//
//Uses incremental method that is more resistant to floating point imprecision,
//for more info see Donald Knuth's "The Art of Computer Programming, Volume 2: Seminumerical Algorithms", section 4.2.2
//
public class GaussianEstimator extends AbstractMOAObject {
private static final long serialVersionUID = 1L;
protected double weightSum;
protected double mean;
protected double varianceSum;
public static final double NORMAL_CONSTANT = Math.sqrt(2 * Math.PI);
public void addObservation(double value, double weight) {
if (Double.isInfinite(value) || Double.isNaN(value)) {
return;
}
if (this.weightSum > 0.0) {
this.weightSum += weight;
double lastMean = this.mean;
this.mean += (value - lastMean) / this.weightSum;
this.varianceSum += (value - lastMean) * (value - this.mean);
} else {
this.mean = value;
this.weightSum = weight;
}
}
public void addObservations(GaussianEstimator obs) {
if ((this.weightSum > 0.0) && (obs.weightSum > 0.0)) {
this.mean = (this.mean * (this.weightSum / (this.weightSum + obs.weightSum)))
+ (obs.mean * (obs.weightSum / (this.weightSum + obs.weightSum)));
this.weightSum += obs.weightSum;
this.varianceSum += obs.varianceSum;
}
}
public double getTotalWeightObserved() {
return this.weightSum;
}
public double getMean() {
return this.mean;
}
public double getStdDev() {
return Math.sqrt(getVariance());
}
public double getVariance() {
return this.weightSum > 1.0 ? this.varianceSum / (this.weightSum - 1.0)
: 0.0;
}
public double probabilityDensity(double value) {
if (this.weightSum > 0.0) {
double stdDev = getStdDev();
if (stdDev > 0.0) {
double diff = value - getMean();
return (1.0 / (NORMAL_CONSTANT * stdDev))
* Math.exp(-(diff * diff / (2.0 * stdDev * stdDev)));
}
return value == getMean() ? 1.0 : 0.0;
}
return 0.0;
}
public double[] estimatedWeight_LessThan_EqualTo_GreaterThan_Value(
double value) {
double equalToWeight = probabilityDensity(value) * this.weightSum;
double stdDev = getStdDev();
double lessThanWeight = stdDev > 0.0 ? weka.core.Statistics
.normalProbability((value - getMean()) / stdDev)
* this.weightSum - equalToWeight
: (value < getMean() ? this.weightSum - equalToWeight : 0.0);
double greaterThanWeight = this.weightSum - equalToWeight
- lessThanWeight;
if (greaterThanWeight < 0.0) {
greaterThanWeight = 0.0;
}
return new double[]{lessThanWeight, equalToWeight, greaterThanWeight};
}
public void getDescription(StringBuilder sb, int indent) {
// TODO Auto-generated method stub
}
}