/*
* 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;
}
}