/*
this classifier does none of the transformations. It simply loads the
* problems it is told to. In build classifier it can load the CV weights or find them,
* by default through LOOCV. For classifiers, it defaults to a standard set with default
* parameters. Alternatively, you can set the classifiers and for certain types set the
* parameters through CV.
*/
package weka.classifiers.meta.timeseriesensembles;
import java.util.ArrayList;
import java.util.Random;
import weka.classifiers.*;
import weka.classifiers.bayes.NaiveBayes;
import weka.classifiers.functions.SMO;
import weka.classifiers.functions.supportVector.PolyKernel;
import weka.classifiers.lazy.kNN;
import weka.classifiers.meta.RotationForest;
import weka.classifiers.trees.J48;
import weka.classifiers.trees.RandomForest;
import weka.core.*;
/**
*
* @author ajb
*/
public class WeightedEnsemble extends AbstractClassifier{
//The McNemar test requires the actual predictions of each classifier. The others can be found directly
//from the CV accuracy.
Instances train;
Classifier[] c;
ArrayList<String> classifierNames;
double[] weights;
boolean loadCVWeights=false;
public static int MAX_NOS_FOLDS=500;
enum WeightType{EQUAL,BEST,PROPORTIONAL,SIGNIFICANT_BINOMIAL,SIGNIFICANT_MCNEMAR};
WeightType w;
public WeightedEnsemble(){
w=WeightType.PROPORTIONAL;
classifierNames=new ArrayList<String>();
c=setDefaultClassifiers(classifierNames);
weights=new double[c.length];
}
public WeightedEnsemble(Classifier[] cl,ArrayList<String> names){
w=WeightType.PROPORTIONAL;
setClassifiers(cl,names);
weights=new double[c.length];
}
public void setWeightType(WeightType a){w=a;}
public void setWeightType(String s){
String str=s.toUpperCase();
w=WeightType.EQUAL;
/* switch(str){
case "EQUAL": case "EQ": case "E":
w=WeightType.EQUAL;
break;
case "BEST": case "B":
w=WeightType.BEST;
break;
case "PROPORTIONAL": case "PROP": case "P":
w=WeightType.PROPORTIONAL;
break;
case "SIGNIFICANT_BINOMIAL": case "SIGB": case "SIG": case "S":
w=WeightType.SIGNIFICANT_BINOMIAL;
break;
case "SIGNIFICANT_MCNEMAR": case "SIGM": case "SM":
w=WeightType.SIGNIFICANT_MCNEMAR;
break;
}
*/
}
//Default to kNN, Naive Bayes, C4.5, SVML, SVMQ, RandForest200, RotForest50
final public Classifier[] setDefaultClassifiers(ArrayList<String> names){
ArrayList<Classifier> sc2=new ArrayList<Classifier>();
sc2.add(new kNN(1));
names.add("NN");
Classifier c;
sc2.add(new NaiveBayes());
names.add("NB");
sc2.add(new J48());
names.add("C45");
c=new SMO();
PolyKernel kernel = new PolyKernel();
kernel.setExponent(1);
((SMO)c).setKernel(kernel);
sc2.add(c);
names.add("SVML");
c=new SMO();
kernel = new PolyKernel();
kernel.setExponent(2);
((SMO)c).setKernel(kernel);
sc2.add(c);
names.add("SVMQ");
c=new RandomForest();
((RandomForest)c).setNumTrees(100);
sc2.add(c);
names.add("RandF200");
c=new RotationForest();
sc2.add(c);
names.add("RotF50");
Classifier[] sc=new Classifier[sc2.size()];
for(int i=0;i<sc.length;i++)
sc[i]=sc2.get(i);
return sc;
}
final public void setClassifiers(Classifier[] cl, ArrayList<String> names){
c=cl;
classifierNames=new ArrayList<String>(names);
}
@Override
public void buildClassifier(Instances data) throws Exception {
train = data;
//HERE: Offer the option of loading CV, classifiers and parameter sets
//NOT IMPLEMENTED YET
//Parameter optimisation first,
//NOT IMPLEMENTED YET
//Train the classifiers
for(int i=0;i<c.length;i++)
c[i].buildClassifier(train);
//Find the weights of the classifier through CV
if(w!=WeightType.EQUAL){
Evaluation eval=new Evaluation(train);
for(int i=0;i<c.length;i++){
Random r= new Random();
r.setSeed(1234);
//Assume LOOCV, but set the max number of folds to 500
int folds=train.numInstances();
if(folds>MAX_NOS_FOLDS)
folds=MAX_NOS_FOLDS;
eval.crossValidateModel(c[i],train,folds,r);
weights[i]=1-eval.errorRate();
}
}
else{
for(int i=0;i<c.length;i++)
weights[i]=1/(double)c.length;
}
if(w==WeightType.BEST){ //Find largest, set to one and others to zero.
int bestPos=0;
for(int i=1;i<weights.length;i++){
if(weights[i]>weights[bestPos])
bestPos=i;
}
for(int i=0;i<weights.length;i++){
if(i==bestPos)
weights[i]=1;
else
weights[i]=0;
}
}
}
@Override
public double[] distributionForInstance(Instance ins) throws Exception{
double[] preds=new double[ins.numClasses()];
for(int i=0;i<c.length;i++){
int p=(int)c[i].classifyInstance(ins);
// System.out.println(" Classifier "+classifierNames.get(i)+" predicts class "+p+" with weight "+weights[i]);
preds[p]+=weights[i];
}
double sum=preds[0];
for(int i=1;i<preds.length;i++)
sum+=preds[i];
for(int i=0;i<preds.length;i++)
preds[i]/=sum;
return preds;
}
public ArrayList<String> getNames(){ return classifierNames;}
//Test for the ensemble in the spectral data
/* public static void testSpectrum() throws Exception{
Instances train=ClassifierTools.loadData("C:\\Users\\ajb\\Dropbox\\Power Spectrum Transformed TSC Problems\\PSItalyPowerDemand\\PSItalyPowerDemand_TRAIN");
Instances test=ClassifierTools.loadData("C:\\Users\\ajb\\Dropbox\\Power Spectrum Transformed TSC Problems\\PSItalyPowerDemand\\PSItalyPowerDemand_TEST");
WeightedEnsemble w=new WeightedEnsemble();
w.buildClassifier(train);
System.out.println(" Accuracy ="+ClassifierTools.accuracy(test, w));
}
*/ public static void main(String[] args){
try{
// testSpectrum();
}catch(Exception e){
}
}
}