source: src/main/java/weka/estimators/MahalanobisEstimator.java @ 4

Last change on this file since 4 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 6.9 KB
Line 
1/*
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.
6 *
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.
11 *
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.
15 */
16
17/*
18 *    MahalanobisEstimator.java
19 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.estimators;
24
25import weka.core.Capabilities.Capability;
26import weka.core.matrix.Matrix;
27import weka.core.Capabilities;
28import weka.core.RevisionUtils;
29import weka.core.Utils;
30
31/**
32 * Simple probability estimator that places a single normal distribution
33 * over the observed values.
34 *
35 * @author Len Trigg (trigg@cs.waikato.ac.nz)
36 * @version $Revision: 5490 $
37 */
38public class MahalanobisEstimator extends Estimator implements IncrementalEstimator {
39 
40  /** for serialization  */
41  private static final long serialVersionUID = 8950225468990043868L;
42 
43  /** The inverse of the covariance matrix */
44  private Matrix m_CovarianceInverse;
45 
46  /** The determinant of the covariance matrix */
47  private double m_Determinant;
48 
49  /**
50   * The difference between the conditioning value and the conditioning mean
51   */
52  private double m_ConstDelta;
53 
54  /** The mean of the values */
55  private double m_ValueMean;
56 
57  /** 2 * PI */
58  private static double TWO_PI = 2 * Math.PI;
59 
60  /**
61   * Returns value for normal kernel
62   *
63   * @param x the argument to the kernel function
64   * @param variance the variance
65   * @return the value for a normal kernel
66   */
67  private double normalKernel(double x) {
68   
69    Matrix thisPoint = new Matrix(1, 2);
70    thisPoint.set(0, 0, x);
71    thisPoint.set(0, 1, m_ConstDelta);
72    return Math.exp(-thisPoint.times(m_CovarianceInverse).
73        times(thisPoint.transpose()).get(0, 0) 
74        / 2) / (Math.sqrt(TWO_PI) * m_Determinant);
75  }
76 
77  /**
78   * Constructor
79   *
80   * @param covariance
81   * @param constDelta
82   * @param valueMean
83   */
84  public MahalanobisEstimator(Matrix covariance, double constDelta,
85      double valueMean) {
86   
87    m_CovarianceInverse = null;
88    if ((covariance.getRowDimension() == 2) && (covariance.getColumnDimension() == 2)) {
89      double a = covariance.get(0, 0);
90      double b = covariance.get(0, 1);
91      double c = covariance.get(1, 0);
92      double d = covariance.get(1, 1);
93      if (a == 0) {
94        a = c; c = 0;
95        double temp = b;
96        b = d; d = temp;
97      }
98      if (a == 0) {
99        return;
100      }
101      double denom = d - c * b / a;
102      if (denom == 0) {
103        return;
104      }
105      m_Determinant = covariance.get(0, 0) * covariance.get(1, 1)
106      - covariance.get(1, 0) * covariance.get(0, 1);
107      m_CovarianceInverse = new Matrix(2, 2);
108      m_CovarianceInverse.set(0, 0, 1.0 / a + b * c / a / a / denom);
109      m_CovarianceInverse.set(0, 1, -b / a / denom);
110      m_CovarianceInverse.set(1, 0, -c / a / denom);
111      m_CovarianceInverse.set(1, 1, 1.0 / denom);
112      m_ConstDelta = constDelta;
113      m_ValueMean = valueMean;
114    }
115  }
116 
117  /**
118   * Add a new data value to the current estimator. Does nothing because the
119   * data is provided in the constructor.
120   *
121   * @param data the new data value
122   * @param weight the weight assigned to the data value
123   */
124  public void addValue(double data, double weight) {
125   
126  }
127 
128  /**
129   * Get a probability estimate for a value
130   *
131   * @param data the value to estimate the probability of
132   * @return the estimated probability of the supplied value
133   */
134  public double getProbability(double data) {
135   
136    double delta = data - m_ValueMean;
137    if (m_CovarianceInverse == null) {
138      return 0;
139    }
140    return normalKernel(delta);
141  }
142 
143  /** Display a representation of this estimator */
144  public String toString() {
145   
146    if (m_CovarianceInverse == null) {
147      return "No covariance inverse\n";
148    }
149    return "Mahalanovis Distribution. Mean = "
150    + Utils.doubleToString(m_ValueMean, 4, 2)
151    + "  ConditionalOffset = "
152    + Utils.doubleToString(m_ConstDelta, 4, 2) + "\n"
153    + "Covariance Matrix: Determinant = " + m_Determinant
154    + "  Inverse:\n" + m_CovarianceInverse;
155  }
156 
157  /**
158   * Returns default capabilities of the classifier.
159   *
160   * @return      the capabilities of this classifier
161   */
162  public Capabilities getCapabilities() {
163    Capabilities result = super.getCapabilities();
164    result.disableAll();
165   
166    // class
167    if (!m_noClass) {
168      result.enable(Capability.NOMINAL_CLASS);
169      result.enable(Capability.MISSING_CLASS_VALUES);
170    } else {
171      result.enable(Capability.NO_CLASS);
172    }
173   
174    // attributes
175    result.enable(Capability.NUMERIC_ATTRIBUTES);
176    return result;
177  }
178 
179  /**
180   * Returns the revision string.
181   *
182   * @return            the revision
183   */
184  public String getRevision() {
185    return RevisionUtils.extract("$Revision: 5490 $");
186  }
187 
188  /**
189   * Main method for testing this class.
190   *
191   * @param argv should contain a sequence of numeric values
192   */
193  public static void main(String [] argv) {
194   
195    try {
196      double delta = 0.5;
197      double xmean = 0;
198      double lower = 0;
199      double upper = 10;
200      Matrix covariance = new Matrix(2, 2);
201      covariance.set(0, 0, 2);
202      covariance.set(0, 1, -3);
203      covariance.set(1, 0, -4);
204      covariance.set(1, 1, 5);
205      if (argv.length > 0) {
206        covariance.set(0, 0, Double.valueOf(argv[0]).doubleValue());
207      }
208      if (argv.length > 1) {
209        covariance.set(0, 1, Double.valueOf(argv[1]).doubleValue());
210      }
211      if (argv.length > 2) {
212        covariance.set(1, 0, Double.valueOf(argv[2]).doubleValue());
213      }
214      if (argv.length > 3) {
215        covariance.set(1, 1, Double.valueOf(argv[3]).doubleValue());
216      }
217      if (argv.length > 4) {
218        delta = Double.valueOf(argv[4]).doubleValue();
219      }
220      if (argv.length > 5) {
221        xmean = Double.valueOf(argv[5]).doubleValue();
222      }
223     
224      MahalanobisEstimator newEst = new MahalanobisEstimator(covariance,
225          delta, xmean);
226      if (argv.length > 6) {
227        lower = Double.valueOf(argv[6]).doubleValue();
228        if (argv.length > 7) {
229          upper = Double.valueOf(argv[7]).doubleValue();
230        }
231        double increment = (upper - lower) / 50;
232        for(double current = lower; current <= upper; current+= increment)
233          System.out.println(current + "  " + newEst.getProbability(current));
234      } else {
235        System.out.println("Covariance Matrix\n" + covariance);
236        System.out.println(newEst);
237      }
238    } catch (Exception e) {
239      System.out.println(e.getMessage());
240    }
241  }
242}
Note: See TracBrowser for help on using the repository browser.