I am aware that I haven’t posted anything new for a few days now, and that is simply because I’ve been making too much progress to slow down and write about what’s going on. All in all the auto-generated code portion is essentially complete. I have added some functionality to allow the generated code to also include comments which make the if/else branch structure nearly as easy to read and follow as the graphical tree generated in Processing. The idea is for future students to make trees by hand and compare their work to the generated code, or to simply take the generated code and write about how and why it works or to possibly implement a task with an Arduino that will require a decision tree to make choices. The comments amount to explaining what the numbers correspond to in the if/else branches and what the decisions are and why.
In addition to adding commenting to the the auto-generated code I decided to also add the random number generation that was occurring in Processing to the Arduino code. In general the decision tree attempts to traverse down a given branch gaining information the whole time and reducing entropy to zero, at which point there is only one option left, the decision. However, it is possible for a decision branch to check all the attributes and still be unsure (not yet at zero entropy). If this occurs my decision tree randomly chooses a leaf node to place on the end of the branch (if there were no training examples on this branch) or else randomly chooses a weighted leaf node to place on the branch (if there were training examples on this branch). What this means is, if a branch has never occurred in training then the decision is randomly made (because there is not enough data to make an inference), and it should be correct 1/n*100% of the time, where n is the total number of possible decisions. However, if there were examples on that branch then the random choice is weighted in favor of examples that have occurred more often. For example if in training there were examples for a given non-zero entropy branch of a, a, b then the decision a should be chosen twice as often as decision b.
I have chosen to allow non-zero entropy random branches to exist in my decision tree implementation because in general some randomness can be desirable in mobile robots and other applications with noisy data that can be prone to local minima. For this reason I have chosen to move the random decision generation to the Arduino. If the random choice was made in Processing then for the duration the tree is loaded on the Ardunio the same decision will always be made for that branch. With the random number generation on the Arduino it has the ability to make different decisions each time an undetermined condition occurs. Further testing will be necessary to determine if this design choice is valid. For now I will leave you with some of the generated code with comments and random number generation included.
/* play_tennis decision Tree file for Arduino */
/* Date: 20 Feb 2012 */
/* Time: 14:50:24 */
#ifndef play_tennis_H
#define play_tennis_H
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
// Output (Decision):
// play_tennis levels: 0 = No 1 = Yes
// Input (Attributes):
// Outlook levels: 0 = Overcast 1 = Rain 2 = Sunny
// Temp levels: 0 = Cool 1 = Mild 2 = Hot
// Humidity levels: 0 = Normal 1 = High
// Wind levels: 0 = Weak 1 = Strong
int play_tennis(int Outlook, int Temp, int Humidity, int Wind, int random_seed){
randomSeed(random_seed); // seed the psuedo random number generator
if(Outlook == 0){ // Outlook == Overcast?
return 1; // play_tennis = Yes
}
else if(Outlook == 1){ // Outlook == Rain?
if(Wind == 0){ // Wind == Weak?
return 1; // play_tennis = Yes
}
else if(Wind == 1){ // Wind == Strong?
return 0; // play_tennis = No
}
}
else if(Outlook == 2){ // Outlook == Sunny?
if(Humidity == 0){ // Humidity == Normal?
if(Temp == 0){ // Temp == Cool?
return 1; // play_tennis = Yes
}
else if(Temp == 1){ // Temp == Mild?
return 1; // play_tennis = Yes
}
else if(Temp == 2){ // Temp == Hot?
if(Wind == 0){ // Wind == Weak?
return random(2); // play_tennis = random choice
}
else if(Wind == 1){ // Wind == Strong?
int random_choices[] = {0, 1};
return random_choices[random(2)]; // play_tennis = weighted random choice
}
}
}
else if(Humidity == 1){ // Humidity == High?
return 0; // play_tennis = No
}
}
}
#endif