private void btnCheat_Click(object sender, EventArgs e) { //generate 15 random answers for (int n = 0; n < 15; n++) { string[] simulations = new string[10]; for (int q = 0; q < 10; q++) { List <string> possibilities = set1.Possibilities[q]; int randomIndex = r.Next(possibilities.Count); string generatedAnswer; if (possibilities.Count != 0) { generatedAnswer = possibilities[randomIndex]; } else { generatedAnswer = "random free answer"; } if (q == 0) { simulations[q] = "SUNNY"; } else { simulations[q] = generatedAnswer; } } Answer ans = new Answer(set1, simulations); answers.Add(ans); AddAnswerRow(ans); lblNumberCount.Text = answers.Count.ToString(); } lblNumberCount.Text = answers.Count.ToString(); //if (answers.Count > 0) lblNumberCount.Text = answers[answers.Count-1].entries[0]; inputs = new string[10]; if (answers.Count >= 15) { decisionTree = new Tree(); decisionTree.Root = Tree.Learn(answersTable, ""); currentNode = decisionTree.Root; id3enabled = true; } if (!id3enabled) { CurrentQuestionIndex = 0; } else { CurrentQuestionIndex = IndexFromFactor(currentNode.Name); } }
private DecisionTree.TreeNode NextNodeFromAnswer(string answer, DecisionTree.TreeNode parentNode) { foreach (DecisionTree.TreeNode n in parentNode.ChildNodes) { if (n.Edge == answer) { return(n); } } return(new DecisionTree.TreeNode(true, "newpath", "")); //if this is a new case }
/// <summary> /// Recursive down the decision tree using the example's attributes /// until we hit a leaf node, which has the class label /// </summary> private static string GetClassLabel(TreeNode decisionTree, Example testExample) { if (decisionTree.ClassLabel != null) { return decisionTree.ClassLabel; } var exampleAttrVal = testExample.Attributes[decisionTree.ColNum]; var subTree = decisionTree.Children[exampleAttrVal]; return GetClassLabel(subTree, testExample); }
/// <summary> /// Recursively construct decision tree from examples and attributes /// </summary> private static TreeNode LearnInternal(ICollection<Example> examples, ICollection<DataAttribute> attributes, IEnumerable<Example> parentExamples) { // if no examples, use parent plurality if (examples.Count == 0) { return PluralityValue(parentExamples); } // if all examples have same classification, use it if (examples.Select(x => x.ClassLabel).Distinct().Count() == 1) { return new TreeNode { ClassLabel = examples.First().ClassLabel, }; } // if no attributes, use plurality if (attributes.Count == 0) { return PluralityValue(examples); } // pick most important attribute var attr = attributes.OrderByDescending(x => Importance(examples, x)).First(); // get other attributes var remainingAttrs = attributes.Where(x => x != attr).ToList(); // group the examples by their value for selected attribute var examplesByAttrValue = examples.ToLookup(x => x.Attributes[attr.ColNum]); // construct a decision tree for this attribute var tree = new TreeNode { ColNum = attr.ColNum, }; // for each value, recursively construct a sub-tree foreach (var attrValue in attr.Values) { var childExamples = examplesByAttrValue[attrValue].ToList(); var subTree = LearnInternal(childExamples, remainingAttrs, examples); tree.Children.Add(attrValue, subTree); } return tree; }
/// <summary> /// Serializes the decision tree and writes it into the classifier main program /// </summary> private static void ReplaceSerializedTreeLine(string mainFilePath, TreeNode decisionTree) { // double serialize the tree to escape " characters var serializedTree = JsonConvert.SerializeObject(JsonConvert.SerializeObject(decisionTree)); // find the line in the file where we should stick the serialized tree const string serializedTreeLine = @"const string serializedDecisionTree = "; var fileContents = File.ReadAllText(mainFilePath); var lineToReplace = fileContents.Split(new[] { "\r\n" }, StringSplitOptions.None).Single(x => x.Contains(serializedTreeLine)); // stick the serialized tree in that line var newLine = lineToReplace.Substring(0, lineToReplace.IndexOf(serializedTreeLine) + serializedTreeLine.Length) + serializedTree + ";"; var newContents = fileContents.Replace(lineToReplace, newLine); File.WriteAllText(mainFilePath, newContents); }
private void newAnswer() { usedQuestions.Clear(); Answer newAnswer = new Answer(set1, inputs); bool IsNewAnswer = true; foreach (Answer a in answers) { if (a.IsSameAnswer(newAnswer)) { IsNewAnswer = false; } } if (IsNewAnswer) { answers.Add(newAnswer); AddAnswerRow(newAnswer); lblNumberCount.Text = answers.Count.ToString(); } //if (answers.Count > 0) lblNumberCount.Text = answers[answers.Count-1].entries[0]; inputs = new string[10]; if (answers.Count >= 15) { decisionTree = new Tree(); decisionTree.Root = Tree.Learn(answersTable, ""); currentNode = decisionTree.Root; id3enabled = true; } if (!id3enabled) { CurrentQuestionIndex = 0; } else { CurrentQuestionIndex = IndexFromFactor(currentNode.Name); } }
/// <summary> /// Creates a DecisionTreeClassifier.exe from a decision tree, returning the file path of the new exe /// </summary> public static string CompileClassifier(TreeNode decisionTree) { var assemblyLocation = Assembly.GetExecutingAssembly().Location; var assemblyDirectory = new FileInfo(assemblyLocation).DirectoryName ?? ""; var classifierDir = Path.Combine(assemblyDirectory, "DecisionTreeClassifier"); var projFullPath = Path.Combine(classifierDir, "DecisionTreeClassifier.csproj"); var mainFullPath = Path.Combine(classifierDir, "Program.cs"); ReplaceSerializedTreeLine(mainFullPath, decisionTree); // load up the classifier project var proj = new Project(projFullPath); // set project to compile special DecisionTree config proj.SetProperty("Configuration", "DecisionTree"); // set the output path proj.SetProperty("DecisionTreeOutputPath", assemblyDirectory); // make a logger to catch possible build errors var logger = new SimpleBuildLogger(); // if we failed to build the classifier, we're screwed if (!proj.Build(logger)) { var sb = new StringBuilder(); sb.AppendLine("***************************************"); sb.AppendLine("**** Failed To Compile Classifier! ****"); sb.AppendLine("***************************************"); foreach (var error in logger.Errors) { sb.AppendLine(error.Message + " " + error.File + ": " + error.LineNumber); } throw new Exception(sb.ToString()); } // return the executable name var exeFileName = proj.GetProperty("AssemblyName").EvaluatedValue + ".exe"; return Path.Combine(assemblyDirectory, exeFileName); }
/// <summary> /// Classifies test data examples using decision tree, and outputs results to stdout. /// </summary> public static void Run(TreeNode decisionTree, DataSet testData) { try { Console.WriteLine(); foreach (var example in testData.Examples) { var classLabel = GetClassLabel(decisionTree, example); var attrs = example.Attributes.OrderBy(x => x.Key).Select(x => x.Value); Console.WriteLine("{0} ==> {1}", string.Join(",", attrs), classLabel); } } catch // we will only get an exception if the inputs were invalid { throw new Exception("Test data cannot be used with decision tree - one of them is invalid."); } }
private void stepButton_Click(object sender, EventArgs e) { inputs[CurrentQuestionIndex] = cbAnswers.Text; if (CurrentQuestionIndex == 9) { if (id3enabled && cbAnswers.Text != currentNode.Name) { AskNextRemainingQuestion(); id3enabled = false; }//if the final answer is not the one in the tree else { newAnswer(); } } else if (!id3enabled) { AskNextRemainingQuestion(); } else { DecisionTree.TreeNode nextNode = NextNodeFromAnswer(inputs[CurrentQuestionIndex], currentNode); if (nextNode.IsLeaf && nextNode.Name != "newpath") { CurrentQuestionIndex = 9; } else if (nextNode.Name == "newpath") { AskNextRemainingQuestion(); id3enabled = false; } else { CurrentQuestionIndex = IndexFromFactor(nextNode.Name); } currentNode = nextNode; } stepButton.Enabled = false; }
public double Compute(double[] inputVals) { currentNode = rootNode; foreach (var val in inputVals) { //if they're equal then use this child... var sameValNode = currentNode.Children.FirstOrDefault(n => n.Value == val); if (sameValNode != null) currentNode = sameValNode; else { //if not get the child with the closest value... //order the set by difference first, then whether or not the tree node is observed. var closestNode = (from node in currentNode.Children select new { Node = node, Diff = Math.Abs(node.Value - val), IsObserved = node is ObservedTreeNode }) .OrderBy(a => a.Diff) .OrderByDescending(a=>a.IsObserved) .First(); currentNode = closestNode.Node; } } //return the child of the last node...there should be exactly one child... if (currentNode.Children.Count == 1) return currentNode.Children.First().Value; else throw new Exception("This tree ain't right."); }
public bool AddBranch(double[] newVals, double answer, bool isObserved) { currentNode = rootNode; foreach (var val in newVals) { var childCount = currentNode.Children.Count; bool addNewNode = false; //if there are no current children in the branch then add the current branch as a child. if (childCount == 0) { addNewNode = true; } else { //if there exist a child with the same value then just move to the next value.. var sameValNode = currentNode.Children.FirstOrDefault(n => n.Value == val); if (sameValNode != null) { if (isObserved) { if (sameValNode is ObservedTreeNode) currentNode = sameValNode; else { var newObserved = new ObservedTreeNode(sameValNode.Parent, sameValNode.Children.ToList(), val); currentNode.Children.Remove(sameValNode); currentNode.Children.Add(newObserved); currentNode = newObserved; } } else { currentNode = sameValNode; } } else //otherwise add the new branch as a child... addNewNode = true; } //add the node if (addNewNode) { TreeNode newChild = null; if (isObserved) newChild = new ObservedTreeNode(currentNode, null, val); else newChild = new TrainedTreeNode(currentNode, null, val); currentNode.Children.Add(newChild); currentNode = newChild; } } //we're at the last value, so now we need to add the answer node... //if any answers already exist then we replace the current answer with this answer. currentNode.Children.Clear(); if (isObserved) currentNode.Children.Add(new ObservedTreeNode(currentNode, null, answer)); else currentNode.Children.Add(new TrainedTreeNode(currentNode, null, answer)); return true; }
public SimpleDecisionTree(TreeNode root) { rootNode = root; currentNode = rootNode; }