package weka.classifiers.lazy;
import weka.core.*;
import weka.core.neighboursearch.NearestNeighbourSearch;
/** Nearest neighbour classifier that extends the weka one but can take alternative distance functions.
*
*
*
* @author ajb
* @version 1.0
* @since 5/4/09
*
*
* TO DO:
* 1. Check Euclidean distance works: Check normalised flag works: DONE:
* Notes: Flag for normalise is in EuclideanDistance, NOT in DistributionFunction, which is rubbish. it is default on
* Normalisation is onto fixed interval 0..1 by (x-min)/(max-min)
Done 7/4/09
*
* NOTES ON DESIGN: The class EuclideanDistance by default normalizes to range [0..1] by dividing by max,
*
* This class allows for a built in attribute filter
*
*
* */
public class kNN extends IBk {
protected DistanceFunction dist;
double[][] distMatrix;
boolean storeDistance;
public kNN(){
//Defaults to Euclidean distance
super();
dist=new EuclideanDistance();
super.setKNN(1);
}
public kNN(int k){
super(k);
setDistanceFunction(new EuclideanDistance());
}
public kNN(DistanceFunction df){
super();
setDistanceFunction(df);
}
public final void setDistanceFunction(DistanceFunction df){
dist=df;
NearestNeighbourSearch s = super.getNearestNeighbourSearchAlgorithm();
try{
s.setDistanceFunction(df);
}catch(Exception e){
System.err.println(" Exception thrown setting distance function ="+e+" in "+this);
e.printStackTrace();
System.exit(0);
}
}
//Need to implement the early abandon for the search?
public double distance(Instance first, Instance second) {
return dist.distance(first, second);
}
//Only use with a Euclidean distance method
public void normalise(boolean v){
if(dist instanceof NormalizableDistance)
((NormalizableDistance)dist).setDontNormalize(!v);
else
System.out.println(" Not normalisable");
}
static String path="C:\\Research\\Data\\WekaTest\\";
public double testKNN(Instances test){
return 0;
}
//FILTER CODE
boolean filterAttributes=false;
double propAtts=0.5;
int nosAtts=0;
AttributeFilterBridge af;
public void setFilterAttributes(boolean f){ filterAttributes=f;}
// public void setEvaluator(ASEvaluation a){ eval=a;}
public void setProportion(double f){propAtts=f;}
public void setNumber(int n){nosAtts=n;}
private Instances filter(Instances d){
//Search method: Simple rank, evaluating in isolation
af=new AttributeFilterBridge(d);
af.setProportionToKeep(propAtts);
Instances d2=af.filter();
// Instances d2=new Instances(d);
//Remove all attributes not in the list. Are they sorted??
return d2;
}
@Override
public void buildClassifier(Instances d){
Instances d2=d;
if(filterAttributes){
d2=filter(d);
}
dist.setInstances(d2);
try{
super.buildClassifier(d2);
}catch(Exception e){
System.out.println("Exception thrown in kNN build Classifier = "+e);
e.printStackTrace();
System.exit(0);
}
}
@Override
public double [] distributionForInstance(Instance instance) throws Exception {
if(af!=null){
Instance newInst=af.filterInstance(instance);
return super.distributionForInstance(newInst);
}
else
return super.distributionForInstance(instance);
}
public double[] getPredictions(Instances test){
double[] pred=new double[test.numInstances()];
try{
for(int i=0;i<test.numInstances();i++){
pred[i]=classifyInstance(test.instance(i));
System.out.println("Pred = "+pred[i]);
}
}catch(Exception e){
System.out.println("Exception thrown in getPredictions in kNN = "+e);
e.printStackTrace();
System.exit(0);
}
return pred;
}
public double measureAccuracy(Instances test){
double[] pred=getPredictions(test);
double accuracy=0;
for(int i=0;i<test.numInstances();i++)
if(pred[i]==test.instance(i).classValue())
accuracy++;
return accuracy/test.numInstances();
}
public static void main(String[] args){
// Instances data=ClassifierTools.loadData(path+"iris");
// kNN c=new kNN(new DTW_DistanceBasic());
// kNN c2=new kNN(new DTW_DistanceEfficient());
/* data.randomize(new Random());
Instances train=data.trainCV(3,1);
Instances test=data.testCV(3,1);
c.buildClassifier(train);
c.setKNN(3);
c2.setKNN(3);
c2.buildClassifier(train);
double a1=c.measureAccuracy(test);
double a2=c.measureAccuracy(test);
System.out.println("Accuracy basic = "+a1+" space efficient = "+a2);
// kNN c=new kNN(new EuclideanDistance());
*/
//Test the filter
// kNN c3=new kNN();
// c3.setFilterAttributes(true);
// c3.buildClassifier(data);
// c.normalise(false);
// Instance first=data.instance(0);
// Instance second=data.instance(1);
// System.out.println(" Basic Distance between "+first+" and "+second+" = "+c.distance(first,second));
// System.out.println(" Space Efficient Distance between "+first+" and "+second+" = "+c.distance(first,second));
}
}