2
* This program is free software; you can redistribute it and/or modify
3
* it under the terms of the GNU General Public License as published by
4
* the Free Software Foundation; either version 2 of the License, or
5
* (at your option) any later version.
7
* This program is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
* GNU General Public License for more details.
12
* You should have received a copy of the GNU General Public License
13
* along with this program; if not, write to the Free Software
14
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
* MahalanobisEstimator.java
19
* Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
23
package weka.estimators;
25
import weka.core.Capabilities.Capability;
26
import weka.core.matrix.Matrix;
27
import weka.core.Capabilities;
28
import weka.core.Utils;
31
* Simple probability estimator that places a single normal distribution
32
* over the observed values.
34
* @author Len Trigg (trigg@cs.waikato.ac.nz)
35
* @version $Revision: 1.7 $
37
public class MahalanobisEstimator extends Estimator implements IncrementalEstimator {
39
/** for serialization */
40
private static final long serialVersionUID = 8950225468990043868L;
42
/** The inverse of the covariance matrix */
43
private Matrix m_CovarianceInverse;
45
/** The determinant of the covariance matrix */
46
private double m_Determinant;
49
* The difference between the conditioning value and the conditioning mean
51
private double m_ConstDelta;
53
/** The mean of the values */
54
private double m_ValueMean;
57
private static double TWO_PI = 2 * Math.PI;
60
* Returns value for normal kernel
62
* @param x the argument to the kernel function
63
* @param variance the variance
64
* @return the value for a normal kernel
66
private double normalKernel(double x) {
68
Matrix thisPoint = new Matrix(1, 2);
69
thisPoint.set(0, 0, x);
70
thisPoint.set(0, 1, m_ConstDelta);
71
return Math.exp(-thisPoint.times(m_CovarianceInverse).
72
times(thisPoint.transpose()).get(0, 0)
73
/ 2) / (Math.sqrt(TWO_PI) * m_Determinant);
83
public MahalanobisEstimator(Matrix covariance, double constDelta,
86
m_CovarianceInverse = null;
87
if ((covariance.getRowDimension() == 2) && (covariance.getColumnDimension() == 2)) {
88
double a = covariance.get(0, 0);
89
double b = covariance.get(0, 1);
90
double c = covariance.get(1, 0);
91
double d = covariance.get(1, 1);
100
double denom = d - c * b / a;
104
m_Determinant = covariance.get(0, 0) * covariance.get(1, 1)
105
- covariance.get(1, 0) * covariance.get(0, 1);
106
m_CovarianceInverse = new Matrix(2, 2);
107
m_CovarianceInverse.set(0, 0, 1.0 / a + b * c / a / a / denom);
108
m_CovarianceInverse.set(0, 1, -b / a / denom);
109
m_CovarianceInverse.set(1, 0, -c / a / denom);
110
m_CovarianceInverse.set(1, 1, 1.0 / denom);
111
m_ConstDelta = constDelta;
112
m_ValueMean = valueMean;
117
* Add a new data value to the current estimator. Does nothing because the
118
* data is provided in the constructor.
120
* @param data the new data value
121
* @param weight the weight assigned to the data value
123
public void addValue(double data, double weight) {
128
* Get a probability estimate for a value
130
* @param data the value to estimate the probability of
131
* @return the estimated probability of the supplied value
133
public double getProbability(double data) {
135
double delta = data - m_ValueMean;
136
if (m_CovarianceInverse == null) {
139
return normalKernel(delta);
142
/** Display a representation of this estimator */
143
public String toString() {
145
if (m_CovarianceInverse == null) {
146
return "No covariance inverse\n";
148
return "Mahalanovis Distribution. Mean = "
149
+ Utils.doubleToString(m_ValueMean, 4, 2)
150
+ " ConditionalOffset = "
151
+ Utils.doubleToString(m_ConstDelta, 4, 2) + "\n"
152
+ "Covariance Matrix: Determinant = " + m_Determinant
153
+ " Inverse:\n" + m_CovarianceInverse;
157
* Returns default capabilities of the classifier.
159
* @return the capabilities of this classifier
161
public Capabilities getCapabilities() {
162
Capabilities result = super.getCapabilities();
165
result.enable(Capability.NUMERIC_ATTRIBUTES);
171
* Main method for testing this class.
173
* @param argv should contain a sequence of numeric values
175
public static void main(String [] argv) {
182
Matrix covariance = new Matrix(2, 2);
183
covariance.set(0, 0, 2);
184
covariance.set(0, 1, -3);
185
covariance.set(1, 0, -4);
186
covariance.set(1, 1, 5);
187
if (argv.length > 0) {
188
covariance.set(0, 0, Double.valueOf(argv[0]).doubleValue());
190
if (argv.length > 1) {
191
covariance.set(0, 1, Double.valueOf(argv[1]).doubleValue());
193
if (argv.length > 2) {
194
covariance.set(1, 0, Double.valueOf(argv[2]).doubleValue());
196
if (argv.length > 3) {
197
covariance.set(1, 1, Double.valueOf(argv[3]).doubleValue());
199
if (argv.length > 4) {
200
delta = Double.valueOf(argv[4]).doubleValue();
202
if (argv.length > 5) {
203
xmean = Double.valueOf(argv[5]).doubleValue();
206
MahalanobisEstimator newEst = new MahalanobisEstimator(covariance,
208
if (argv.length > 6) {
209
lower = Double.valueOf(argv[6]).doubleValue();
210
if (argv.length > 7) {
211
upper = Double.valueOf(argv[7]).doubleValue();
213
double increment = (upper - lower) / 50;
214
for(double current = lower; current <= upper; current+= increment)
215
System.out.println(current + " " + newEst.getProbability(current));
217
System.out.println("Covariance Matrix\n" + covariance);
218
System.out.println(newEst);
220
} catch (Exception e) {
221
System.out.println(e.getMessage());