* @author Jens Jahnke
* <p>berschrift: Sequential Floating Forward Search</p>
* <p>Beschreibung: Fhrt eine SFFS auf den gegebenen Daten durch.</p>
* <p>Copyright: Copyright (c) 2005/06</p>
* <p>Organisation: Fraunhofer IGD </p>
* @version 0.9
public class sffs {
final static boolean DEBUGFLAG = false;
final static boolean VERBOSE = false;
protected Instances m_data_train;
protected Instances m_data_test;
protected int maxAttributes = 13; // maximum number of attributes that should be used protected StringBuffer m_SelectedAttributes; // contains the selected attributes protected StringBuffer m_Attributes; // contains all attributes
protected StringBuffer m_ClassAttributes; // attributes that shall not be removed protected double m_delta = 0.0025; // break indicator
protected double m_error = -1; // buffer for last calculated error protected double m_correctly = 0; // correctly classified instances (%) protected double m_incorrectly = 0; // incorrectly classified instances (%) private StringBuffer m_States;
protected Filter m_Filter = null;
protected int m_classifier = 0; // classifier
protected int m_Folds = 6; // number of folds for cross validation public sffs(String attrs, String classattrs, int maxAttrs) {
m_classifier = 0; // set to default (Naive Bayes) m_data_train = null;
m_data_test = null;
m_SelectedAttributes = new StringBuffer();
m_Attributes = new StringBuffer(attrs);
m_ClassAttributes = new StringBuffer(classattrs);
m_States = new StringBuffer();
maxAttributes = maxAttrs;
m_delta = 0.0025;
m_error = -1;
} // constructor
/**
* Returns the value of m_delta, that influences the sffs algorithm.
* @return (double)
*/
public double getDelta() { return (m_delta);
} /**
* Sets the value of m_delta, that influences the sffs algorithm.
* @param delta (double value (default: 0.0025))
*/
public void setDelta(double delta) { m_delta = delta;
} /**
* Returns the percentage of correctly classified instances.
* @return (double)
*/
public double getCorrectly() {
double percentage = m_correctly * 100 / (m_correctly + m_incorrectly);
percentage = Math.rint(percentage * 100.0) / 100.0; // rounding to 2 digits return (percentage);
} /**
* Returns the percentage of incorrectly classified instances.
* @return (double)
*/
public double getIncorrectly() {
double percentage = m_incorrectly * 100 / (m_correctly + m_incorrectly);
percentage = Math.rint(percentage * 100.0) / 100.0; // rounding to 2 digits return (percentage);
} /**
* set classifier to use to "i"
* @param i
*/
public void setClassifier(int i) { if ((i > -1) && (i < 4)) {
public int getClassifier() { return (m_classifier);
} /**
* Do some init stuff before the run.
*
*/
public void initRun() {
m_SelectedAttributes = new StringBuffer();
m_States = new StringBuffer();
m_error = -1;
m_correctly = 0;
m_incorrectly = 0;
} /**
* Sets the class attribute.
* @param classattrs
*/
public void setClassAttribute(int classattrs) {
if (classattrs > 0 && classattrs < m_data_train.numAttributes()) m_ClassAttributes = new StringBuffer(String.valueOf(classattrs));
} /**
* Sets the maximum number of desired attributes.
* @param num_attrs
*/
public void setNumberOfAttributes(int num_attrs) {
if (num_attrs > 0 && num_attrs < m_data_train.numAttributes()) maxAttributes = num_attrs;
} /**
* sets the filter to use
* @param name the classname of the filter
* @param options the options for the filter
*/
private void setFilter(String name, String[] options) throws Exception { m_Filter = (Filter) Class.forName(name).newInstance();
if (m_Filter instanceof OptionHandler)
((OptionHandler) m_Filter).setOptions(options);
} /**
* Executes the filter "filtername" with the given parameters.
*
* @param filtername contains the "exact" name of the weka filter to use.
* @param filteropts a list of filter options.
* @param source weka instance source
*/
private Instances prepare_data(String filtername, String filteropts[], Instances source) {
try {
// set filtername
this.setFilter(filtername, filteropts);
if (DEBUGFLAG && VERBOSE) {
System.err.println("Applying filter.");
}
m_Filter.setInputFormat(source);
Instances filtered = Filter.useFilter(source, m_Filter);
return (filtered);
} catch (Exception e) {
System.err.println("An error occured during the execution of the following filter: \n"
+ "\tName: " + filtername);
System.err.println(e.getLocalizedMessage());
* Sets the given weka instance as data instance.
* @param data (Weka-Instance)
* @param folds (numer of desired folds for cross validation)
*/
public void setInstance(Instances data, int folds) { try {
m_Folds = folds;
m_data_train = data;
m_data_test = data;
} catch (Exception e) {
System.err.println(e.getLocalizedMessage());
// set the max number of attributes
public int setMaxAttributes(int attributes) { if (attributes > 0) {
maxAttributes = attributes;
* Returns the number of selected attributes.
* @return
*/
public int getNumberOfSelectedAttributes() { int nr;
if (m_SelectedAttributes.length() < 1) nr = 0;
else {
StringTokenizer strtok = new StringTokenizer(m_SelectedAttributes.toString(), ",");
nr = strtok.countTokens();
public String getSelectedAttributes() { try {
return (m_SelectedAttributes.toString());
} catch (Exception e) {
System.err.println(e.getStackTrace());
return ("");
} } /**
* Checks if the given state is present in the states buffer.
* @param State
* @return true or false
*/
private boolean isInStates(String State) { String tmp = m_States.toString();
if (tmp.contains(State)) { return(true);
} else { return(false);
}
} /**
* Adds the given state to the states buffer.
* @param State
*/
private void addState(String State) { m_States.append(State);
m_States.append(" "); // divide the states by adding a blank }
/**
* Checks if findme is contained within searchme. Returns true or false.
* @param findme
* @param searchme
* @return
*/
private boolean isInString(String findme, String searchme) { boolean isIt = false;
String tmp = "";
StringTokenizer st = new StringTokenizer(searchme, ",");
try {
} catch (Exception e) {
System.err.println(e.getLocalizedMessage());
private String m(String m1, String m2) { StringBuffer match = new StringBuffer();
String tmp = "";
StringTokenizer genAttributes = new StringTokenizer(m1, ",");
if (m2.length() == 0) { match.append(m1);
} else { try {
while (genAttributes.hasMoreTokens()) { tmp = genAttributes.nextToken(); // get token if (!isInString(tmp, m2)) {
match.append(tmp);
match.append(",");
}
} // while (genAttributes.hasMoreTokens()) if (match.length() > 0) {
match.deleteCharAt(match.length() - 1); // delete last ","
}
} catch (Exception e) {
System.err.println(e.getLocalizedMessage());
* Creates the union of m1 and m2.
* @param m1
* @param m2
* @return m1 (union) m2
*/
private String union(String m1, String m2) { String tmp = "";
StringBuffer m = new StringBuffer();
StringTokenizer st = new StringTokenizer(m2, ",");
if (m1.length() == 0) {
if (!isInString(tmp, m1)) { m.append(tmp);
m.append(",");
} }
m.deleteCharAt(m.length() - 1);
} catch (Exception e) {
System.err.println(e.getLocalizedMessage());
* Adds the attribute attr to the list of selected attributes.
* @param attr
*/
private void addAttribute(String attr) { if (m_SelectedAttributes.length() > 0) { m_SelectedAttributes.append(",");
}
m_SelectedAttributes.append(attr);
} /**
* Randomly removes an entry from the list of selected attributes.
*
*/
private String remAttribute(String Attributes, boolean randomize, boolean last) { int i,j,k;
Random zufall = new Random();
StringBuffer tmpBuf = new StringBuffer();
String stmp = "";
// save attribs to tokenizer
StringTokenizer tmp = new StringTokenizer(Attributes, ",");
k = tmp.countTokens();
j = 0;
if (randomize && k > 1) { // use random remove function // avoid the last entry i = zufall.nextInt(k - 1);
} else {
// remove other entry
i = k - 2; // second last one //i = 0; // first one
}
// remove last entry if (last) i = k - 1;
// remove entry if (k > 1) { if (DEBUGFLAG) {
System.err.println("Removing entry " + (i+1) + " from " + k);
System.err.println(Attributes);
* Tries to find the best attribute.
* @param attrs
* @return
*/
private String argmin(String attrs) { String selAttr = "";
String tmpAttr = "";
double tmpTest, tmpTest2 = 0;
StringTokenizer st = new StringTokenizer(attrs, ",");
try {
if (tmpTest2 < tmpTest) {
if (DEBUGFLAG) { System.out.println(tmpTest2 + " < " + tmpTest); }
selAttr = tmpAttr;
tmpTest = tmpTest2;
} }
} catch (Exception e) {
System.err.println("Error in argmin function: ");
System.err.println(e.getLocalizedMessage());
* The main SFFS algorithm.
*
*/
public void runSFFS() { double f = 0;
double g = 0;
double buf = 100;
double delta = 0;
int n = 0;
StringBuffer tmpAttrib = new StringBuffer();
String tmp = "";
String fm = "";
while (n < maxAttributes) {
System.out.print("."); // give some output if (m_SelectedAttributes.length() > 1) buf = Test(m_SelectedAttributes.toString());
// create m = F \ Fs
tmpAttrib = new StringBuffer();
tmp = "";
tmp = m(m_Attributes.toString(), m_SelectedAttributes.toString());
if (DEBUGFLAG) { System.err.println("Generated {m} : { " + tmp + " }"); } fm = argmin(tmp);
tmpAttrib.append(fm);
if (DEBUGFLAG) { System.err.println("Generated argmin({m}) : { " + tmpAttrib.toString() + " }"); }
// create Fs (union) {m}
tmp = union(m_SelectedAttributes.toString(), tmpAttrib.toString());
if (DEBUGFLAG) { System.err.println("Generated Fs U {m} : { " + tmp + " }"); } addAttribute(tmpAttrib.toString());
// save state
addState(m_SelectedAttributes.toString());
n++;
if (DEBUGFLAG) { System.err.println(m_SelectedAttributes.toString()); } // backward steps
while (true) {
System.out.print("."); // give some output
tmp = m(m_Attributes.toString(), m_SelectedAttributes.toString());
// f = Test(Fs \ {m})
fm = m(m_SelectedAttributes.toString(), tmp);
f = Test(fm);
// remove an attribute
tmpAttrib = new StringBuffer();
tmpAttrib.append(remAttribute(m_SelectedAttributes.toString(), true, false));
// if (Test(Fs \ {f}) < Test(Fs) AND ((Fs \ {f}) is not element of States)) g = Test(tmpAttrib.toString());
if ((g < f) && (!(isInStates(tmpAttrib.toString())))) { f = g;
// Fs = Fs \ {f}
m_SelectedAttributes = tmpAttrib;
// save state
addState(m_SelectedAttributes.toString());
if (DEBUGFLAG) { System.err.println(m_SelectedAttributes.toString()); } n--;
} else { break;
}
} // while (true)
delta = Math.abs(buf - f);
if (delta <= m_delta && buf < 100) { tmpAttrib = new StringBuffer();
tmpAttrib.append(remAttribute(m_SelectedAttributes.toString(), false, true));
m_SelectedAttributes = tmpAttrib;
if (DEBUGFLAG)
System.err.println("Last modification did not improve result (d = " + delta + ").");
break;
} //n++;
if (DEBUGFLAG && VERBOSE) { System.err.println("n = " + n);
System.err.println("Delta = " + delta);
}
} // while (n < maxAttributes)
m_error = buf; // buffer last calculated error if (DEBUGFLAG) {
System.out.println("Error : " + String.valueOf(buf));
}
System.out.print("+"); // give some output }
/**
* This function is the essential part. It pipes the given dataset into the
* Naive Bayes classification net and returns the relative absolute error.
*
* @param attributes (a string that contains a comma seperated list of attributes.)
* @return A double value that represents the error rate of the naive bayes net.
*/
private double Test(String attributes) { double result = 0;
// filteroptions for the remove filter:
String[] filter_pars = new String[3];
filter_pars[0] = "-V"; // invert remove selection filter_pars[1] = "-R";
filter_pars[2] = m_ClassAttributes.toString() + "," + attributes; // columns to keep // remove all except the attributes specified in "String attributes"
Instances training_data = prepare_data("weka.filters.unsupervised.attribute.Remove", filter_pars, m_data_train);
training_data.setClassIndex(0);
try {
Random random = new Random();
Evaluation myTest = null;
switch (m_classifier) { case 0:
// use naive bayes
//Classifier myClassifier = (Classifier)new NaiveBayes();
NaiveBayes myClassifier = new NaiveBayes();
// train the classifier
myClassifier.buildClassifier(training_data);
// test the classifier
myTest = new Evaluation(training_data);
//myTest.evaluateModel(myClassifier, training_data);
myTest.crossValidateModel(myClassifier, training_data, m_Folds, random);
// get error
result = myTest.meanAbsoluteError();
result = Math.rint(result * 10000.0) / 10000.0; // rounding to 4 digits // get number of correctly and incorrectly classified instances
m_correctly = myTest.correct();
m_incorrectly = myTest.incorrect();
break;
case 1:
// use bayes net
BayesNet myBayesNet = new BayesNet();
// train the classifier
myBayesNet.buildClassifier(training_data);
// test the classifier
myTest = new Evaluation(training_data);
//myTest.evaluateModel(myBayesNet, training_data);
myTest.crossValidateModel(myBayesNet, training_data, m_Folds, random);
// get error
result = myTest.meanAbsoluteError();
result = Math.rint(result * 10000.0) / 10000.0; // rounding to 4 digits // get number of correctly and incorrectly classified instances
m_correctly = myTest.correct();
// train the classifier
myJ48.buildClassifier(training_data);
// test the classifier
myTest = new Evaluation(training_data);
//myTest.evaluateModel(myJ48, training_data);
myTest.crossValidateModel(myJ48, training_data, m_Folds, random);
// get error
result = myTest.meanAbsoluteError();
result = Math.rint(result * 10000.0) / 10000.0; // rounding to 4 digits // get number of correctly and incorrectly classified instances
m_correctly = myTest.correct();
m_incorrectly = myTest.incorrect();
break;
default:
System.err.println("Error in Test function: No valid classifier set!");
System.exit(1);
}
} catch (Exception e) {
System.err.println("Error in Test function:");
System.err.println(e.getCause());
return(result);
} /**
* returns buffered error
* @return
*/
public double getError() { return(m_error);
} /**
* @param args
*/
public static void main(String[] args) { long startms = 0;
long startRun = 0;
long stopms = 0;
long zeit = 0;
String filename = "";
int classifier = 0;
int maxattribs = 0;
int classes = 0;
String classattributes = "";
String fieldattributes = "";
if (args.length < 5) {
System.err.println("Please specify filename (arff format),
classification method, max number of attributes, fieldattributes and class attributes!");
System.err.println("<filename> <0|1|2> <no. of attributes> <fa1,fa2,fa3,...>
<ca1,ca2,ca3,...>");
System.err.println("Classifiers:");
System.err.println("\t0 : Naive Bayes\n\t1 : BayesNet\n\t 2 : J48\n\t3 : Fisherprojection");
System.exit(1);
sffs m_SFFS = new sffs(fieldattributes,classattributes, maxattribs);
m_SFFS.setClassifier(classifier);
System.out.print("Using Classifier: ");
classifier = m_SFFS.getClassifier();
switch (classifier) { case 0:
System.out.println("0 - Naive Bayes");
break;
case 1:
System.out.println("1 - Bayes Net");
break;
case 2:
System.out.println("2 - J48");
break;
default:
System.err.println("No valid classifier set!");
System.exit(1);
}
System.out.println("Allowed maximum number of attributes: " + maxattribs);
System.out.println("Class attributes: " + classattributes);
try {
Instances data = new Instances(
new BufferedReader(
new FileReader(filename)));
//Instances filtered_data = null;
// setting class attribute
data.setClassIndex(data.numAttributes() - 1);
// set instance and split it into 6 folds
m_SFFS.setInstance(data, 6); // TODO: create command line argument for that } catch (IOException ioe) {
System.err.println("An IO error occured!");
ioe.printStackTrace();
System.exit(1);
}
double[] fehlerwerte = new double[10];
double[] correct = new double[10];
double[] incorrect = new double[10];
String[] attribute = new String[10];
String[] emotionen = new String[10];
emotionen[0] = "valence";
StringTokenizer st = new StringTokenizer(classattributes, ",");
String tmpAttribute = "";
classes = st.countTokens();
int i = 0;
while (st.hasMoreTokens()) { tmpAttribute = st.nextToken();
startRun = System.currentTimeMillis();
m_SFFS.setDelta(0.0015); // TODO: Test only!
m_SFFS.setClassAttribute(Integer.parseInt(tmpAttribute));
zeit = stopms - startRun;
zeit = zeit / 1000;
System.out.print(" (time : " + zeit + " s) ");
}
stopms = System.currentTimeMillis();
zeit = stopms - startms;
zeit = zeit / 1000;
System.out.println("");
System.out.println("SFFS completed on file " + filename + " in " + zeit + " seconds with delta value " + m_SFFS.getDelta() + ".");
for (i=0; i<classes; i++) {
System.out.println(emotionen[i] + ": error rate = " + fehlerwerte[i]
+ " (" + correct[i] + "% vs. " + incorrect[i] + "%) -> attributes {"
+ attribute[i] + "}");
}
* @author Jens Jahnke
* <p>berschrift: Werkzeugkiste</p>
* <p>Beschreibung: Validiert eine gegebene Relation auf den gegebenen Testmengen.</p>
* <p>Copyright: Copyright (c) 2005/06</p>
* <p>Organisation: Fraunhofer IGD </p>
* @version 0.1
public class werkzeugkiste {
protected String m_Trainingsdaten = "";
protected String[] m_Testdaten = null;
protected int m_NumberOfTestfiles = 0;
protected String m_Removerelation = "";
protected double m_Correctly = 0;
protected double m_Incorrectly = 0;
protected double m_Error = 0;
protected double[] m_Errors = null;
protected double[] m_Prozente = null;
protected Instances m_data_train;
protected Instances m_data_test;
protected Filter m_Filter = null;
protected int m_classifier = 0; // classifier /**
* Konstruktor
* @param remove (String) relation for the weka remove filter
* @param training (String) name of the arff file used for training
* @param test (StringBuffer) comma separated list of arff files for testing
*/
public werkzeugkiste(String remove, String training, StringBuffer test) { m_Correctly = 0;
m_Incorrectly = 0;
m_classifier = 0;
m_Removerelation = remove;
m_Trainingsdaten = training;
StringTokenizer st = new StringTokenizer(test.toString(), ",");