/* * K-L distance for periodograms as defined in * * @ARTICLE{caiado06periodogram, author = {J. CAIADO and N. CRATO and D. PEÑA }, title = {A periodogram-based metric for time series classification}, journal = {Computational Statistics & Data Analysis}, year = {2006}, volume = {50}, pages = {2668--2684} } * where it is stated that the K-L distance in the spectral domain is asymptotically * equivalent to that in the frequence domain. */ package weka.core.spectral_distance_functions; import weka.core.EuclideanDistance; import weka.core.Instance; import weka.core.Instances; import weka.core.neighboursearch.PerformanceStats; import weka.filters.NormalizeCase; /** * * @author ajb */ public class KullbackLeiberDistance extends EuclideanDistance{ private static final long serialVersionUID = 1L; public KullbackLeiberDistance(){ super(); } public KullbackLeiberDistance(Instances data) { super(data); } //Needs overriding to avoid cutoff check public double distance(Instance first, Instance second){ return distance(first, second, Double.POSITIVE_INFINITY, null, false); } public double distance(Instance first, Instance second, PerformanceStats stats) { //debug method pls remove after use return distance(first, second, Double.POSITIVE_INFINITY, stats, false); } public double distance(Instance first, Instance second, double cutOffValue, PerformanceStats stats){ return distance(first,second,cutOffValue,stats,false); } public double distance(Instance first, Instance second, double cutOffValue, PerformanceStats stats, boolean print) { //Get the double arrays return distance(first,second,cutOffValue); } public double distance(Instance first, Instance second, double cutOffValue) { double[] f; double[] s; int fClass=first.classIndex(); if(fClass>=0) { f=new double[first.numAttributes()-1]; int count=0; for(int i=0;i<f.length+1;i++){ if(i!=fClass){ f[count]=first.value(i); count++; } } } else f=first.toDoubleArray(); int sClass=second.classIndex(); if(sClass>=0) { s=new double[second.numAttributes()-1]; int count=0; for(int i=0;i<s.length;i++){ if(i!=sClass){ s[count]=second.value(i); count++; } } } else s=second.toDoubleArray(); if(f.length!=s.length){ //Error here System.out.println("Error in distance calculation for Likelihhod ratio, unequal lengths, exiting program!"); System.exit(0); } if(!m_DontNormalize){ //If the series have been pre normalised, there is no need to do this. try{ NormalizeCase.standardNorm(f); NormalizeCase.standardNorm(s); }catch(Exception e){ System.out.println(" in log norm distance, Exception ="+e); e.printStackTrace(); System.exit(0); } } return distance(f,s,cutOffValue); } /* KL Distance distance * */ public double distance(double[] a,double[] b, double cutoff){ double dist=0; for(int i=0;i<a.length;i++){ dist+=a[i]/b[i]-Math.log(a[i])/Math.log(b[i])-1; if(dist>cutoff) return Double.POSITIVE_INFINITY; } return dist; } public String toString() { return "Likelihood Ratio"; } public String globalInfo() { return "Likelihood Ratio"; } @Override protected double updateDistance(double currDist, double diff) { // TODO Auto-generated method stub return 0; } public String getRevision() { return null; } }