/**
*
*/
package dt;
import java.util.*;
public class DecisionTree {
/**
* Contains the set of available attributes.
*/
private LinkedHashSet attributes;
/**
* Maps a attribute name to a set of possible decisions for that attribute.
*/
private Map > decisions;
private boolean decisionsSpecified;
/**
* Contains the examples to be processed into a decision tree.
*
* The 'attributes' and 'decisions' member variables should be updated
* prior to adding examples that refer to new attributes or decisions.
*/
private Examples examples;
/**
* Indicates if the provided data has been processed into a decision tree.
*
* This value is initially false, and is reset any time additional data is
* provided.
*/
private boolean compiled;
/**
* Contains the top-most attribute of the decision tree.
*
* For a tree where the decision requires no attributes,
* the rootAttribute yields a boolean classification.
*
*/
private Attribute rootAttribute;
private Algorithm algorithm;
public DecisionTree() {
algorithm = null;
examples = new Examples();
attributes = new LinkedHashSet();
decisions = new HashMap >();
decisionsSpecified = false;
}
private void setDefaultAlgorithm() {
if ( algorithm == null )
setAlgorithm(new ID3Algorithm(examples));
}
public void setAlgorithm(Algorithm algorithm) {
this.algorithm = algorithm;
}
/**
* Saves the array of attribute names in an insertion ordered set.
*
* The ordering of attribute names is used when addExamples is called to
* determine which values correspond with which names.
*
*/
public DecisionTree setAttributes(String[] attributeNames) {
compiled = false;
decisions.clear();
decisionsSpecified = false;
attributes.clear();
for ( int i = 0 ; i < attributeNames.length ; i++ )
attributes.add(attributeNames[i]);
return this;
}
/**
*/
public DecisionTree setDecisions(String attributeName, String[] decisions) {
if ( !attributes.contains(attributeName) ) {
// TODO some kind of warning or something
return this;
}
compiled = false;
decisionsSpecified = true;
Set decisionsSet = new HashSet();
for ( int i = 0 ; i < decisions.length ; i++ )
decisionsSet.add(decisions[i]);
this.decisions.put(attributeName, decisionsSet);
return this;
}
/**
*/
public DecisionTree addExample(String[] attributeValues, boolean classification) throws UnknownDecisionException {
String[] attributes = this.attributes.toArray(new String[0]);
if ( decisionsSpecified )
for ( int i = 0 ; i < attributeValues.length ; i++ )
if ( !decisions.get(attributes[i]).contains(attributeValues[i]) ) {
throw new UnknownDecisionException(attributes[i], attributeValues[i]);
}
compiled = false;
examples.add(attributes, attributeValues, classification);
return this;
}
public DecisionTree addExample(Map attributes, boolean classification) throws UnknownDecisionException {
compiled = false;
examples.add(attributes, classification);
return this;
}
public boolean apply(Map data) throws BadDecisionException {
compile();
return rootAttribute.apply(data);
}
private Attribute compileWalk(Attribute current, Map chosenAttributes, Set usedAttributes) {
// if the current attribute is a leaf, then there are no decisions and thus no
// further attributes to find.
if ( current.isLeaf() )
return current;
// get decisions for the current attribute (from this.decisions)
String attributeName = current.getName();
// remove this attribute from all further consideration
usedAttributes.add(attributeName);
for ( String decisionName : decisions.get(attributeName) ) {
// overwrite the attribute decision for each value considered
chosenAttributes.put(attributeName, decisionName);
// find the next attribute to choose for the considered decision
// build the subtree from this new attribute, pre-order
// insert the newly-built subtree into the open decision slot
current.addDecision(decisionName, compileWalk(algorithm.nextAttribute(chosenAttributes, usedAttributes), chosenAttributes, usedAttributes));
}
// remove the attribute decision before we walk back up the tree.
chosenAttributes.remove(attributeName);
// return the subtree so that it can be inserted into the parent tree.
return current;
}
public void compile() {
// skip compilation if already done.
if ( compiled )
return;
// if no algorithm is set beforehand, select the default one.
setDefaultAlgorithm();
Map chosenAttributes = new HashMap();
Set usedAttributes = new HashSet();
if ( !decisionsSpecified )
decisions = examples.extractDecisions();
// find the root attribute (either leaf or non)
// walk the tree, adding attributes as needed under each decision
// save the original attribute as the root attribute.
rootAttribute = compileWalk(algorithm.nextAttribute(chosenAttributes, usedAttributes), chosenAttributes, usedAttributes);
compiled = true;
}
public String toString() {
compile();
if ( rootAttribute != null )
return rootAttribute.toString();
else
return "";
}
public Attribute getRoot() {
return rootAttribute;
}
}
Ads help maintain this website.