/* Recreates the results in @article{gorecki14nonisometric, title={Non-isometric transforms in time series classification using DTW}, author={T. Gorecki and M. Luczak}, journal={Knowledge-Based Systems}, volume={online first}, year={2014} } */ package other_peoples_algorithms; import development.DataSets; import development.TimeSeriesClassification; import static development.TimeSeriesClassification.UCRProblems; import fileIO.InFile; import fileIO.OutFile; import java.text.DecimalFormat; import java.util.logging.Level; import java.util.logging.Logger; import utilities.ClassifierTools; import weka.classifiers.lazy.DTW_kNN; import weka.classifiers.lazy.kNN; import weka.core.DTW_DistanceBasic; import weka.core.Instance; import weka.core.Instances; import weka.filters.timeseries.*; /** Combines DTW distance/DTW distance between derivatives with DTW distance between transforms of time series: cosine, sine and Hilbert transform. Forms a weighted sum of two distances, finding weights by some form of pairwise optimization which might be like the SMO/SVM technique, although this is not that clear, as it then describes setting alpha through cross validation. Add three new BasicFilters in weka.filters.timeseries: Sin, Cosine and Hilbert */ public class Gorecki14nonisometric { //To test the three transforms public static void testTransforms(){ String s="Beef"; OutFile of1 = new OutFile("C:\\Users\\ajb\\Dropbox\\test\\BeefCosine_TRAIN.arff"); OutFile of2 = new OutFile("C:\\Users\\ajb\\Dropbox\\test\\BeefCosine_TEST.arff"); Instances test=utilities.ClassifierTools.loadData(TimeSeriesClassification.path+s+"\\"+s+"_TEST"); Instances train=utilities.ClassifierTools.loadData(TimeSeriesClassification.path+s+"\\"+s+"_TRAIN"); Cosine cosTransform= new Cosine(); Sine sinTransform=new Sine(); Hilbert hilbertTransform= new Hilbert(); System.out.println(" Data set ="+s); try { Instances cosTrain=cosTransform.process(train); Instances cosTest=cosTransform.process(test); of1.writeString(cosTrain+""); of2.writeString(cosTest+""); System.out.println(" Cosine trans complete"); kNN a=new DTW_kNN(1); a.normalise(false); a.buildClassifier(cosTrain); double acc=ClassifierTools.accuracy(cosTest, a); System.out.println(" Cosine acc ="+acc); Instances sinTrain=sinTransform.process(train); Instances sinTest=sinTransform.process(test); System.out.println(" Sine trans complete"); a=new DTW_kNN(1); a.normalise(false); a.buildClassifier(sinTrain); acc=ClassifierTools.accuracy(sinTest, a); System.out.println(" Sine acc ="+acc); Instances hilbertTrain=hilbertTransform.process(train); Instances hilbertTest=hilbertTransform.process(test); System.out.println(" Hilbert trans complete"); a=new DTW_kNN(1); a.normalise(false); a.buildClassifier(hilbertTrain); acc=ClassifierTools.accuracy(hilbertTest, a); System.out.println(" Hilbert acc ="+acc); } catch (Exception ex) { Logger.getLogger(Gorecki14nonisometric.class.getName()).log(Level.SEVERE, null, ex); } } //to recreate columns 6,7, 8 of table 2 //Combine DTW with other transform with a weighting alpha //where alpha in [0,1], searched for increments of 0.01 //Note only find the distances once for each alpha public static void combinedDistanceClassifiersTable2(){ OutFile of = new OutFile("C:\\Users\\ajb\\Dropbox\\Results\\Other Peoples Published Results\\gorecki14nonisometricRecreation.csv"); double[] alphaVals=new double[100]; for(int i=1;i<alphaVals.length;i++) alphaVals[i]=0.01+alphaVals[i]; double[] mistakes=new double[alphaVals.length]; for(String s:DataSets.ucrSmall){ Instances test=utilities.ClassifierTools.loadData(TimeSeriesClassification.path+s+"\\"+s+"_TEST"); Instances train=utilities.ClassifierTools.loadData(TimeSeriesClassification.path+s+"\\"+s+"_TRAIN"); Cosine cosTransform= new Cosine(); Sine sinTransform=new Sine(); Hilbert hilbertTransform= new Hilbert(); of.writeString(s+","); System.out.println(" Data set ="+s); try { Instances cosTrain=cosTransform.process(train); System.out.println(" Cosine trans complete"); Instances sinTrain=sinTransform.process(train); System.out.println(" Sine trans complete"); Instances hilbertTrain=hilbertTransform.process(train); System.out.println(" Hilbert trans complete"); for(int i=0;i<train.numInstances();i++){ // double[] dtwDist=new double[train.numInstances()]; double[] dtwcDist=new double[train.numInstances()]; double[] dtwsDist=new double[train.numInstances()]; double[] dtwhDist=new double[train.numInstances()]; //Find distances between element i and the rest for(int j=0;j<train.numInstances();j++){ // if(i!=j){ // dtwDist[j]=dist; } } } catch (Exception ex) { Logger.getLogger(Gorecki14nonisometric.class.getName()).log(Level.SEVERE, null, ex); } of.writeString("\n"); } } public static void singleDistanceClassifiersTable2(){ OutFile of = new OutFile("C:\\Users\\ajb\\Dropbox\\Results\\Other Peoples Published Results\\gorecki14Table2Combined.csv"); for(String s:DataSets.ucrSmall){ Instances test=utilities.ClassifierTools.loadData(TimeSeriesClassification.path+s+"\\"+s+"_TEST"); Instances train=utilities.ClassifierTools.loadData(TimeSeriesClassification.path+s+"\\"+s+"_TRAIN"); Cosine cosTransform= new Cosine(); Sine sinTransform=new Sine(); Hilbert hilbertTransform= new Hilbert(); of.writeString(s+","); System.out.println(" Data set ="+s); try { Instances cosTrain=cosTransform.process(train); Instances cosTest=cosTransform.process(test); System.out.println(" Cosine trans complete"); kNN a=new DTW_kNN(1); a.normalise(false); a.buildClassifier(cosTrain); double acc=ClassifierTools.accuracy(cosTest, a); of.writeString(acc+","); System.out.println(" Cosine acc ="+acc); Instances sinTrain=sinTransform.process(train); Instances sinTest=sinTransform.process(test); System.out.println(" Sine trans complete"); a=new DTW_kNN(1); a.normalise(false); a.buildClassifier(sinTrain); acc=ClassifierTools.accuracy(sinTest, a); of.writeString(acc+","); System.out.println(" Sine acc ="+acc); Instances hilbertTrain=hilbertTransform.process(train); Instances hilbertTest=hilbertTransform.process(test); System.out.println(" Hilbert trans complete"); a=new DTW_kNN(1); a.normalise(false); a.buildClassifier(hilbertTrain); acc=ClassifierTools.accuracy(hilbertTest, a); of.writeString(acc+","); System.out.println(" Hilbert acc ="+acc); } catch (Exception ex) { Logger.getLogger(Gorecki14nonisometric.class.getName()).log(Level.SEVERE, null, ex); } of.writeString("\n"); } } //Requires derivativeDistanceCVClassifierTable2 to have been run public static void derivativeDistanceTestClassifierTable2(){ InFile inf = new InFile("C:\\Users\\ajb\\Dropbox\\Results\\Other Peoples Published Results\\gorecki14Table2CombinedTrainCVParasFull.csv"); OutFile of = new OutFile("C:\\Users\\ajb\\Dropbox\\Results\\Other Peoples Published Results\\gorecki14Table2DD_Results.csv"); of.writeString("Problem,TrainCVError,TestMistakes,TestError"); for(String s:DataSets.ucrNames){ Instances test=utilities.ClassifierTools.loadData(TimeSeriesClassification.path+s+"\\"+s+"_TEST"); Instances train=utilities.ClassifierTools.loadData(TimeSeriesClassification.path+s+"\\"+s+"_TRAIN"); String problem=inf.readString(); if(!s.equals(problem)){ System.out.println("ERROR: file mismatch: "+s+" and from CV file :"+problem); System.exit(0); } // of.writeLine(s+","+n+","+df.format(bestAlpha)+","+mistakes[bestAlpha]+","+df.format(mistakes[bestAlpha]/(double)n)+","+df.format(alpha[bestAlpha])); int n=inf.readInt(); n=inf.readInt(); n=inf.readInt(); double trainCVError=inf.readDouble(); double alpha=inf.readDouble(); // String rest=inf.readLine(); double a=Math.cos(alpha); double b=Math.sin(alpha); of.writeString(problem+","); int mistakes=0; //Find DTW on test and test differential for(Instance ins:test){ double[] temp=ins.toDoubleArray(); //Recover and remove target class for test instance double testClass=temp[temp.length-1]; double[] testData=new double[temp.length-1]; System.arraycopy(temp, 0, testData, 0, temp.length-1); double[] testDiffs= new double[testData.length-1]; for(int j=0;j<testDiffs.length;j++) testDiffs[j]=testData[j+1]-testData[j]; //Find nearest neighbour in train data double minDist = Double.MAX_VALUE; double pred=0; for(Instance tr:train){ //Recover and remove target class for train instance temp=tr.toDoubleArray(); double trainClass=temp[temp.length-1]; double[] trainData=new double[temp.length-1]; System.arraycopy(temp, 0, trainData, 0, temp.length-1); double[] trainDiffs= new double[trainData.length-1]; for(int j=0;j<trainDiffs.length;j++) trainDiffs[j]=trainData[j+1]-trainData[j]; //Find DTW distance for dataand diffs DTW_DistanceBasic dtw= new DTW_DistanceBasic(); double d1=dtw.distance(testData,trainData,Double.MAX_VALUE); double d2=dtw.distance(testDiffs,trainDiffs,Double.MAX_VALUE);; double dist =a*d1+b*d2; if(dist<minDist){ minDist=dist; pred=trainClass; } } if(pred!=testClass) mistakes++; } of.writeString(trainCVError+","+mistakes+","+(mistakes/(double)test.numInstances())+"\n"); System.out.print(problem+","+trainCVError+","+mistakes+","+(mistakes/(double)test.numInstances())+"\n"); } //Get instance to classify } public static void derivativeDistanceCVClassifierTable2(){ OutFile of = new OutFile("C:\\Users\\ajb\\Dropbox\\Results\\Other Peoples Published Results\\gorecki14Table2CombinedTrainCVParasFull.csv"); DecimalFormat df = new DecimalFormat("###.####"); of.writeString(",bestAlphaIndex,nosMistakes,bestTrainError,bestALphaValue"); for(String s:DataSets.ucrNames){ of.writeString(s+","); Instances test=utilities.ClassifierTools.loadData(TimeSeriesClassification.path+s+"\\"+s+"_TEST"); Instances train=utilities.ClassifierTools.loadData(TimeSeriesClassification.path+s+"\\"+s+"_TRAIN"); double step = 0.01; int k = (int)((Math.PI/2)/step); double[] alpha=new double[k]; for(int i=1;i<alpha.length;i++) alpha[i]=alpha[i-1]+step; double[] a =new double[k]; double[] b =new double[k]; for(int i=0;i<alpha.length;i++){ a[i]=Math.cos(alpha[i]); b[i]=Math.sin(alpha[i]); } int n = train.numInstances(); int[] mistakes=new int[k]; for(int i=0;i<n;i++){ //Get instance to classify double[] temp=train.instance(i).toDoubleArray(); //Recover and remove target class double actual1=temp[temp.length-1]; double[] data1=new double[temp.length-1]; System.arraycopy(temp, 0, data1, 0, temp.length-1); double[] diffs1= new double[data1.length-1]; for(int j=0;j<diffs1.length;j++) diffs1[j]=data1[j+1]-data1[j]; double[] minDists = new double[k]; for(int j=0;j<k;j++) minDists[j]=Double.MAX_VALUE; double[] preds = new double[k]; for(int j=0;j<n;j++){ if(i!=j){ //Recover data2 and diffs2 temp=train.instance(j).toDoubleArray(); //Recover and remove target class double actual2=temp[temp.length-1]; double[] data2=new double[temp.length-1]; System.arraycopy(temp, 0, data2, 0, temp.length-1); double[] diffs2= new double[data2.length-1]; for(int m=0;m<diffs1.length;m++) diffs2[m]=data2[m+1]-data2[m]; //Find the DTW differences DTW_DistanceBasic dtw= new DTW_DistanceBasic(); double d1=dtw.distance(data1,data2,Double.MAX_VALUE); double d2=dtw.distance(diffs1,diffs2,Double.MAX_VALUE);; //Update the min dist so for and the predicted for all weights for(int m=0;m<minDists.length;m++){ double dist=a[m]*d1+b[m]*d2; if(dist<minDists[m]){ minDists[m]=dist; preds[m]=actual2; } } } } //Count whether predictions were correct for each para weight for(int m=0;m<minDists.length;m++){ // System.out.print(preds[m]+","); if(actual1!=preds[m]) mistakes[m]++; } } //Find best alpha, save to file with the training error int bestAlpha=0; for(int m=1;m<mistakes.length;m++){ if(mistakes[m]<mistakes[bestAlpha]) bestAlpha=m; } of.writeLine(s+","+n+","+df.format(bestAlpha)+","+mistakes[bestAlpha]+","+df.format(mistakes[bestAlpha]/(double)n)+","+df.format(alpha[bestAlpha])); System.out.println(s+","+n+","+df.format(bestAlpha)+","+mistakes[bestAlpha]+","+df.format(mistakes[bestAlpha]/(double)n)+","+df.format(alpha[bestAlpha])); } } public static void main(String[] args){ // testTransforms(); // singleDistanceClassifiersTable2(); // derivativeDistanceClassifierTable2(); derivativeDistanceTestClassifierTable2(); } }