private static INode GetNodeFromData(string[] nodeData) { switch (nodeData[1]) { case "Begin": var startingNode = new StartingNode(int.Parse(nodeData[0])); startingNode.AddFollowingNode(int.Parse(nodeData[2])); return(startingNode); case "End": return(new EndingNode(int.Parse(nodeData[0]))); case "Decis": var decisionNode = new DecisionNode(int.Parse(nodeData[0])); decisionNode.AddLeftNode(int.Parse(nodeData[3]), nodeData[5]); decisionNode.AddRightNode(int.Parse(nodeData[2]), nodeData[4]); return(decisionNode); case "Proc": var processNode = new ProcessNode(int.Parse(nodeData[0])); processNode.AddFollowingNode(int.Parse(nodeData[2])); return(processNode); default: return(null); } }
public Node DecisionNodeToNodeClass(DecisionNode root) { Node result = new Node(); DecisionNodeToNodeClass(root, result); return(result); }
private static INode GetNodeFromGSAData(string[] nodeData) { var nodeType = nodeData[1].ToLower(); if (nodeType == "begin") { var startingNode = new StartingNode(int.Parse(nodeData[0])); startingNode.AddFollowingNode(int.Parse(nodeData[2])); return(startingNode); } else if (nodeType == "end") { return(new EndingNode(int.Parse(nodeData[0]))); } else if (new Regex(@"y[0-9]+").IsMatch(nodeType)) { var processNode = new ProcessNode(int.Parse(nodeData[0])); processNode.AddFollowingNode(int.Parse(nodeData[2])); return(processNode); } else if (new Regex(@"x[0-9]+").IsMatch(nodeType)) { var decisionNode = new DecisionNode(int.Parse(nodeData[0])); decisionNode.AddLeftNode(int.Parse(nodeData[3])); decisionNode.AddRightNode(int.Parse(nodeData[2])); return(decisionNode); } else { return(null); } }
private void clearCache(DecisionNode current) { foreach (var node in tree.Traverse(DecisionTreeTraversal.BreadthFirst, current)) { subsets[node].Clear(); } }
private void trackDecisions(DecisionNode current, double[][] input) { for (int i = 0; i < input.Length; i++) { trackDecisions(current, input[i], i); } }
/// <summary> /// Creates a new <see cref="DecisionRule"/> from a <see cref="DecisionTree"/>'s /// <see cref="DecisionNode"/>. This node must be a leaf, cannot be the root, and /// should have one output value. /// </summary> /// /// <param name="node">A <see cref="DecisionNode"/> from a <see cref="DecisionTree"/>.</param> /// /// <returns>A <see cref="DecisionRule"/> representing the given <paramref name="node"/>.</returns> /// public static DecisionRule FromNode(DecisionNode node) { if (node == null) { throw new ArgumentNullException("node"); } if (!node.IsLeaf || node.IsRoot || !node.Value.HasValue) { throw new InvalidOperationException( "Only leaf nodes that have a parent can be converted to rules."); } DecisionNode current = node; DecisionTree owner = current.Owner; double output = current.Output.Value; var antecedents = new List <Antecedent>(); while (current.Parent != null) { int index = current.Parent.Branches.AttributeIndex; ComparisonKind comparison = current.Comparison; double value = current.Value.Value; antecedents.Insert(0, new Antecedent(index, comparison, value)); current = current.Parent; } return(new DecisionRule(node.Owner.Attributes, output, antecedents)); }
private void createCache(DecisionNode current) { foreach (var node in tree.Traverse(DecisionTreeTraversal.BreadthFirst, current)) { subsets[node] = new List <int>(); } }
/// <summary> /// Returns the next hidingspot from the current DecisionTree for the AI to check, based on the probability of the HidingSpots /// </summary> /// <returns> The next hidingspot to check from the current DecisionTree</returns> public DecisionNode GetNextHidingSpot() { DecisionNode place = Tree.RootNode.GetNodeOfHighestProbability(); DecisionNode spot = place.GetRandomHidingSpot(); return(spot); }
public virtual void dumpDot(TextWriter printWriter) { printWriter.Write("digraph \"CART Tree\" {\n"); printWriter.Write("rankdir = LR\n"); foreach (Node n in cart) { printWriter.WriteLine("\tnode" + Math.Abs(n.GetHashCode()) + " [ label=\"" + n + "\", color=" + dumpDotNodeColor(n) + ", shape=" + dumpDotNodeShape(n) + " ]\n"); if (n is DecisionNode) { DecisionNode dn = (DecisionNode)n; if (dn.qtrue < cart.Length && cart[dn.qtrue] != null) { printWriter.Write("\tnode" + Math.Abs(n.GetHashCode()) + " -> node" + Math.Abs(cart[dn.qtrue].GetHashCode()) + " [ label=" + "TRUE" + " ]\n"); } if (dn.qfalse < cart.Length && cart[dn.qfalse] != null) { printWriter.Write("\tnode" + Math.Abs(n.GetHashCode()) + " -> node" + Math.Abs(cart[dn.qfalse].GetHashCode()) + " [ label=" + "FALSE" + " ]\n"); } } } printWriter.Write("}\n"); printWriter.Close(); }
public static string GenerateAForgivingXpath(DecisionNode dn, int phasesLimit = 1000) { // return "//*[" + DecisionTreeToXpath(dn, new HashSet<Feature>(), 1) + "]"; List <double> precisionLevels = FindInterestingPrecisionLevels(dn); string fullCondition = ""; string lastCondition = ""; string conditionClosing = ""; foreach (double pl in precisionLevels) { string currCondition = ""; string beforeCondition = ""; if (!lastCondition.Equals("")) { beforeCondition = " | /*[not(." + lastCondition + ")]"; } string condInside = DecisionTreeToXpath(dn, new HashSet <Feature>(), pl); currCondition = "//*" + (condInside.Equals("") ? "" : ("[" + condInside + "]")); fullCondition = fullCondition + beforeCondition + currCondition; conditionClosing = conditionClosing + ""; //set lastCondition to curr for the next iteration lastCondition = currCondition; } return(fullCondition);//+conditionClosing+"]"; }
private void trackDecisions(DecisionNode root, double[] input, int index) { DecisionNode current = root; while (current != null) { subsets[current].Add(index); if (current.IsLeaf) { actual[index] = current.Output.HasValue ? current.Output.Value : -1; return; } int attribute = current.Branches.AttributeIndex; DecisionNode nextNode = null; foreach (DecisionNode branch in current.Branches) { if (branch.Compute(input[attribute])) { nextNode = branch; break; } } current = nextNode; } // Normal execution should not reach here. throw new InvalidOperationException("The tree is degenerated."); }
public static List <double> FindInterestingPrecisionLevels(DecisionNode dn, int roughlimit = 7) { if (dn == null) { return(new List <double>()); } List <double> left = FindInterestingPrecisionLevels(dn.SetNotSelected); List <double> right = FindInterestingPrecisionLevels(dn.SetSelected); HashSet <double> res = new HashSet <double>(left); res.UnionWith(right); res.Add(dn.precision); List <double> resSorted = new List <double>(res); //Descending resSorted.Sort((a, b) => - 1 * a.CompareTo(b)); if (resSorted.Count() > roughlimit) { int skipLevel = resSorted.Count() / roughlimit; List <double> resFinal = new List <double>(); for (int i = 0; i < resSorted.Count(); i++) { if (i % skipLevel == 0) { if (resSorted.ElementAt(i) > 0) { resFinal.Add(resSorted.ElementAt(i)); } } } return(resFinal); } return(resSorted); }
/// <summary> /// Returns a DecisionNode randomly based on the HidingSpot's probability. /// A HidingSpot with a higher probability has a higher chans of being choosen. /// </summary> /// <returns> Returns the randomly selected DecisionNode. Returns null if the node do not have any children </returns> public DecisionNode GetRandomHidingSpot() { if (Children == null) { Spot.DisableUI(); Parent.Children.Remove(this); Debug.LogWarning("this should not happen"); return(null); } int totalsum = 0; foreach (DecisionNode node in Children) { totalsum += node.Spot.Probability; } int index = UnityEngine.Random.Range(0, totalsum) + 1; int sum = 0; int i = -1; while (sum < index) { sum += Children[i + 1].Spot.Probability; i++; } DecisionNode returnNode = Children[Mathf.Max(0, i)]; return(returnNode); }
/// <summary> /// Returns the DecisionNode that contains the HidingSpot that has the highest probability. /// If there is mulitple HidingSpots with the same probability ït will return one of the randomly. /// </summary> /// <returns> The DecisionNode that contains the HidingSpot with the highest probability, or one of the DecisionNode if there are more that one.</returns> public DecisionNode GetNodeOfHighestProbability() { DecisionNode currentBest = null; List <DecisionNode> sameNodes = new List <DecisionNode>(); DecisionNode nodeToRemove = null; foreach (DecisionNode node in Children) { if (node.Children == null || node.Children.Count == 0) { continue; } if (currentBest == null || currentBest.Spot.Probability < node.Spot.Probability) { currentBest = node; sameNodes.Clear(); sameNodes.Add(currentBest); } else if (currentBest.Spot.Probability == node.Spot.Probability) { sameNodes.Add(node); } } return(sameNodes[Random.Range(0, sameNodes.Count)]); }
private void DecisionNodeToNodeClass(DecisionNode decisionNode, Node currentNode) { if (!decisionNode.IsRoot) { string comparation = decisionNode.ToString(); string[] aux = comparation.Split(' '); currentNode.parent.value = int.Parse(aux[0]) + 1; int column = int.Parse(aux[0]) + 1; if (column == 1) { string comparator = Math.Floor(double.Parse(aux[2])) == 0 ? "30" : "60"; currentNode.message = Patient.getNamesColums(column) + " " + aux[1] + " " + comparator; } else if (column == 2) { string comparator = aux[1].Contains(">") ? "M" : "F"; currentNode.message = Patient.getNamesColums(column) + " " + comparator; } else if (column == 8) { currentNode.message = "Value " + aux[1] + " " + Math.Floor(double.Parse(aux[2])); } else if (column == 6) { string comparator = "120 mg/dl"; currentNode.message = Patient.getNamesColums(column) + " " + aux[1] + " " + comparator; } else { currentNode.message = Patient.getNamesColums(column) + " " + aux[1] + " " + Math.Floor(double.Parse(aux[2])); } } else { currentNode.height = 1; } currentNode.answer = decisionNode.Output; currentNode.nodes = new Node[decisionNode.Branches.Count]; int distX = 2 * Visualization.SIZE + 10 * currentNode.nodes.Length; currentNode.distX = distX; int i = 0; foreach (DecisionNode childNode in decisionNode.Branches) { Node newNode = new Node(); currentNode.nodes[i] = newNode; newNode.parent = currentNode; newNode.height = newNode.parent.height + 1; newNode.posY = newNode.parent.posY + Visualization.DIST_Y; DecisionNodeToNodeClass(childNode, newNode); i++; } if (decisionNode.IsLeaf) { currentNode.value = null; currentNode.answer = currentNode.answer == null ? -1 : currentNode.answer; } }
public override void Execute() { State = (condition.IsTrue()) ? eState.ConditionTrue : eState.ConditionFalse; DecisionNode node = (State == eState.ConditionTrue) ? trueNode : falseNode; node?.Execute(); }
internal bool IsBetterThanParent(DecisionNode parent) { var betterBranch = Left.MeasureValue + Right.MeasureValue; return(parent is SplitDecisionNode node && betterBranch - node.SplitInformation.MeasureValue > 0.1); }
private static void Serialize(string prefix, DecisionNode splitter, string suffix, CodeWriter writer) { writer.AppendLine("{0}N({1},", prefix, SerializePartitioner(splitter.Partitioner)); using (writer.Indent()) { Serialize("", splitter.Left, ",", writer); Serialize("", splitter.Right, ")" + suffix, writer); } }
/// <summary> /// Used to set up the defender type tree /// </summary> void SetupDefender() { DecisionNode isHealthLow = new DecisionNode(Decisions.Shared_IsHealthLow, this); ActionNode findPickup = new ActionNode(Actions.Shared_SearchForHealthpack, this); DecisionNode enemyInRadiusNode = new DecisionNode(Decisions.Shared_IsEnemyInAttackRadius, this); isHealthLow.AddSuccessNode(findPickup); isHealthLow.AddFailureNode(enemyInRadiusNode); DecisionNode enemyHasFlag = new DecisionNode(Decisions.Defender_DoesEnemyHaveTeamFlag, this); ActionNode attackTarget = new ActionNode(Actions.Shared_AttackEnemyTarget, this); enemyInRadiusNode.AddFailureNode(enemyHasFlag); enemyInRadiusNode.AddSuccessNode(attackTarget); ActionNode attackEnemyWithFlag = new ActionNode(Actions.Defender_AttackEnemyWithTeamFlag, this); DecisionNode teamFlagOutsideBase = new DecisionNode(Decisions.Defender_IsTeamFlagOutsideBase, this); enemyHasFlag.AddSuccessNode(attackEnemyWithFlag); enemyHasFlag.AddFailureNode(teamFlagOutsideBase); DecisionNode hasTeamFlagInside = new DecisionNode(Decisions.Defender_HasFriendlyFlag, this); DecisionNode hasTeamFlagOutside = new DecisionNode(Decisions.Defender_HasFriendlyFlag, this); teamFlagOutsideBase.AddFailureNode(hasTeamFlagInside); teamFlagOutsideBase.AddSuccessNode(hasTeamFlagOutside); DecisionNode hasSpottedEnemy = new DecisionNode(Decisions.Shared_HasSeenEnemy, this); ActionNode dropTeamFlag = new ActionNode(Actions.Defender_DropTeamFlag, this); hasTeamFlagInside.AddFailureNode(hasSpottedEnemy); hasTeamFlagInside.AddSuccessNode(dropTeamFlag); ActionNode goToTeamBase = new ActionNode(Actions.Defender_ReturnToBase, this); ActionNode attackEnemy = new ActionNode(Actions.Shared_AttackEnemyTarget, this); hasSpottedEnemy.AddFailureNode(goToTeamBase); hasSpottedEnemy.AddSuccessNode(attackEnemy); DecisionNode teamMateHasFriendlyFlag = new DecisionNode(Decisions.Shared_TeamHasFriendlyFlag, this); hasTeamFlagOutside.AddFailureNode(teamMateHasFriendlyFlag); hasTeamFlagOutside.AddSuccessNode(goToTeamBase); ActionNode collectFriendlyFlag = new ActionNode(Actions.Defender_CollectFriendlyFlag, this); DecisionNode hasSpottedEnemyNearFlagCarrier = new DecisionNode(Decisions.Shared_HasSeenEnemy, this); teamMateHasFriendlyFlag.AddSuccessNode(hasSpottedEnemyNearFlagCarrier); teamMateHasFriendlyFlag.AddFailureNode(collectFriendlyFlag); ActionNode followTeamFlagCarrier = new ActionNode(Actions.Defender_FollowTeamMateWithFlag, this); hasSpottedEnemyNearFlagCarrier.AddSuccessNode(attackEnemy); hasSpottedEnemyNearFlagCarrier.AddFailureNode(followTeamFlagCarrier); decTree = new DecisionTree(isHealthLow); }
private bool compute(DecisionNode node) { int[] indices = subsets[node].ToArray(); int[] subset = outputs.Submatrix(indices); int size = indices.Length; int mostCommon = Statistics.Tools.Mode(subset); DecisionNode maxChild = getMaxChild(node); double replace = Double.PositiveInfinity; if (maxChild != null) { replace = computeErrorReplacingSubtrees(node, maxChild); replace = upperBound(replace, size); } double baseline = computeErrorSubtree(indices); double prune = computeErrorWithoutSubtree(node, mostCommon); baseline = upperBound(baseline, size); prune = upperBound(prune, size); bool changed = false; if (Math.Abs(prune - baseline) < limit || Math.Abs(replace - baseline) < limit) { if (replace < prune) { // We should replace the subtree with its maximum child node.Branches = maxChild.Branches; node.Output = maxChild.Output; foreach (var child in node.Branches) { child.Parent = node; } } else { // We should prune the subtree node.Branches = null; node.Output = mostCommon; } changed = true; clearCache(node); trackDecisions(node, inputs); } return(changed); }
private static double[] ComputeEstimates(IDataRow row, DecisionNode node) { var rowValue = row[node.Attribute]; switch (node.Condition) { case PredicateCondition.Equal: if (!row[node.Attribute].Equals(node.ThreshHold)) { return(null); } break; case PredicateCondition.LessThanOrEqual: if ((rowValue == null) || (Convert.ToDouble(rowValue) > Convert.ToDouble(node.ThreshHold))) { return(null); } break; case PredicateCondition.GreaterThan: if ((rowValue == null) || (Convert.ToDouble(rowValue) <= Convert.ToDouble(node.ThreshHold))) { return(null); } break; default: return(null); } if (node.Children != null && node.Children.Any()) { foreach (var child in node.Children) { var estimates = ComputeEstimates(row, child); if (estimates != null) { return(estimates); } } } else { var estimates = new double[node.Statistics.Frequencies.Length]; for (int index = 0; index < estimates.Length; index++) { estimates[index] = node.Statistics.Frequencies[index] / (double)node.Statistics.DatasetLength; } return(estimates); } return(null); }
private static bool GetClass(IDataRow row, DecisionNode node, out string className) { className = node.Class; bool isValid = false; var rowValue = row[node.Attribute]; switch (node.Condition) { case PredicateCondition.Equal: if (row[node.Attribute].Equals(node.ThreshHold)) { isValid = true; } break; case PredicateCondition.LessThanOrEqual: if (rowValue == null) { return(false); } if (Convert.ToDouble(rowValue) <= Convert.ToDouble(node.ThreshHold)) { isValid = true; } break; case PredicateCondition.GreaterThan: if (rowValue == null) { return(false); } if (Convert.ToDouble(rowValue) > Convert.ToDouble(node.ThreshHold)) { isValid = true; } break; default: throw new ArgumentOutOfRangeException(); } if (isValid && node.Children != null) { foreach (var child in node.Children) { if (GetClass(row, child, out className)) { break; } } } return(isValid); }
public static void LoadLeaves(DecisionNode node, List <DecisionNode> leaves) { if (node.IsLeaf) { leaves.Add(node); return; } foreach (var child in node.Children) { LoadLeaves(child, leaves); } }
internal SplitDecisionNode(DecisionTree owner, DecisionNode parent, SplitInformation splitInformation, ComparisonKind comparisonKind, double splitValue, int attributeIndex) : base(owner) { Parent = parent; Value = splitValue; Comparison = comparisonKind; SplitInformation = splitInformation; AttributeIndex = attributeIndex; }
public string Compute(double[] input, DecisionTree tree) { DecisionNode Root = tree.Root; string attributeName; string attributeValue; string rule = ""; if (Root == null) { throw new InvalidOperationException(); } DecisionNode current = Root; // Start reasoning while (current != null) { // Check if this is a leaf if (current.IsLeaf) { // This is a leaf node. The decision proccess thus should stop here. return(rule.Trim()); } // This node is not a leaf. Continue the decisioning proccess following the childs // Get the next attribute to guide reasoning int attribute = current.Branches.AttributeIndex; // Check which child is responsible for dealing which the particular value of the attribute DecisionNode nextNode = null; foreach (DecisionNode branch in current.Branches) { if (branch.Compute(input[attribute])) { // This is the child node responsible for dealing which this particular attribute value. Choose it // to continue reasoning. nextNode = branch; attributeName = nextNode.Owner.Attributes[nextNode.Parent.Branches.AttributeIndex].Name; attributeValue = this.trainningDataTabDianosis.CodificationData.Translate(attributeName, Convert.ToInt32(nextNode.Value)); rule += attributeName + "=" + attributeValue + " "; break; } } current = nextNode; } // Normal execution should not reach here. throw new InvalidOperationException("The tree is degenerated."); }
public static HashSet <List <DecisionNode> > DecisionTreeToPathList(DecisionNode dn, double recallThreshold) { HashSet <List <DecisionNode> > res = new HashSet <List <DecisionNode> >(); if (dn.SetSelected != null) { double covered = dn.SetSelected.InitialNodeSet.Intersect(DomPool.TargetNodes).Count(); double all = DomPool.TargetNodes.Count(); double threshold = 2 / ((double)DomPool.trainingDocsNames.Count()); if (DomPool.trainingDocsNames.Count() == 1) { threshold = 1; } if ((covered / all) < threshold) { return(new HashSet <List <DecisionNode> >() { new List <DecisionNode>() { dn } }); } } if (dn.SetSelected != null) { HashSet <List <DecisionNode> > rightLists = DecisionTreeToPathList(dn.SetSelected, recallThreshold); foreach (List <DecisionNode> l in rightLists) { List <DecisionNode> toadd = new List <DecisionNode>() { dn }; toadd.AddRange(l); res.Add(toadd); } } if (dn.SetNotSelected != null) { HashSet <List <DecisionNode> > leftLists = DecisionTreeToPathList(dn.SetNotSelected, recallThreshold); foreach (List <DecisionNode> l in leftLists) { res.Add(l); } } return(res); }
/// <summary> /// Get the DecisionNode that contains the hidingSpot, if the HidingSpot don't exist in the tree it will reutnr null. /// </summary> /// <param name="hidingSpot"> The HidingSpot that is containd in the returning DecisionNode</param> /// <returns> The DecisionNode that contains hidingSpot if one exists, otherwise returns null </returns> public DecisionNode GetDecisionNode(HidingSpot hidingSpot) { foreach (DecisionNode node in PlaceCreator.Instance.Tree.RootNode.Children) { DecisionNode Cnode = node.GetChild(hidingSpot); if (Cnode != null) { return(Cnode); } } return(null); }
public static void GeneratePseudoCode(DecisionNode node, StringBuilder sb, bool first, int level = 0) { if (node == null) { return; } if (node.Attribute != null) { var firstParam = first ? "if " : "else if "; var attributeParam = node.Attribute; string operatorParam; var sentence = "{0} {1} {2}" + " \"{3}\" then "; switch (node.Condition) { case PredicateCondition.Equal: operatorParam = "="; break; case PredicateCondition.LessThanOrEqual: operatorParam = "<="; break; case PredicateCondition.GreaterThan: operatorParam = ">"; break; default: throw new ArgumentOutOfRangeException(); } AppendNewLine(sb, string.Format(sentence, firstParam, attributeParam, operatorParam, node.ThreshHold), level); level++; } if (node.Class != null && (node.Children == null || !node.Children.Any())) { var ret = "class = " + node.Class; AppendNewLine(sb, ret, level); } else { if (node.Children != null) { var children = node.Children.ToList(); for (int index = 0; index < children.Count; index++) { GeneratePseudoCode(children[index], sb, index == 0, level); } } } }
private TreeModel buildModel(Man man) { var growNode = new ActionNode <Man>("GrowAgeAndHealth"); var goToWork = new DecisionNode <Man>("DecideIFCanWork"); var startDying = new DecisionNode <Man>("DecideIFDye"); var workHard = new ActionNode <Man>("Work"); var deadNode = new ActionNode <Man>("Dead"); var isSportish = new DecisionNode <Man>("IfSportishContext"); var fromManToSportish = new TransformationNode <Man, Sport>("FromManToSport"); var practiceSport = new ActionNode <Sport>("DoSport"); var sportToMan = new TransformationNode <Sport, Man>("SportToMan"); growNode.AddChild(goToWork); growNode.SetAction(m => { m.Age++; m.Health++; }); goToWork.SetCondition(m => m.Age > 18); goToWork.SetYesChild(workHard); goToWork.SetNoChild(growNode); workHard.AddChild(isSportish); workHard.SetAction(m => { m.Health--; m.Age++; }); isSportish.SetNoChild(startDying); isSportish.SetYesChild(fromManToSportish); isSportish.SetCondition(m => m.Age < 60); fromManToSportish.AddChild(practiceSport); fromManToSportish.SetTranslator(m => new Sport(m.Age)); practiceSport.SetAction(s => s.Do()); practiceSport.AddChild(sportToMan); sportToMan.SetTranslator(sport => { man.Health += sport.GainedHealth; return(man); }); sportToMan.AddChild(startDying); startDying.SetCondition(m => m.Health < 5); startDying.SetNoChild(workHard); startDying.SetYesChild(deadNode); var model = new TreeModel(100); model.SetStartNode(growNode); model.SetEndNode(deadNode); Console.WriteLine("Done"); return(model); }
// Regress tree private TreeNode convert(DecisionNode node) { string attributeName; string attributeValue; TreeNode treeNode; // Add root if (node.IsRoot) { treeNode = new TreeNode(node.ToString()); } else { attributeName = node.Owner.Attributes[node.Parent.Branches.AttributeIndex].Name; attributeValue = this.codification.Translate(attributeName, Convert.ToInt32(node.Value)); // Create new treeNode to TreeView treeNode = new TreeNode(attributeName + "=" + attributeValue); } // If node is leaf if (node.IsLeaf) { // If node has value add classifier value if (node.Output.HasValue) { attributeName = TableMetaData.ClassAttribute; attributeValue = this.codification.Translate(attributeName, Convert.ToInt32(node.Output)); treeNode.Nodes.Add(new TreeNode(attributeValue)); } // Add "" else { treeNode.Nodes.Add(new TreeNode(node.Output.ToString())); } } // Regress all child nodes else { foreach (var child in node.Branches) { treeNode.Nodes.Add(convert(child)); } } return(treeNode); }
public static void GeneratePseudoCode(DecisionNode node, StringBuilder sb, bool first, int level = 0) { if (node == null) { return; } if (node.Attribute != null) { var firstParam = first ? "if " : "else if "; var attributeParam = node.Attribute; string operatorParam; var sentence = "{0} {1} {2}" + " \"{3}\" then "; switch (node.Condition) { case PredicateCondition.Equal: operatorParam = "="; break; case PredicateCondition.LessThanOrEqual: operatorParam = "<="; break; case PredicateCondition.GreaterThan: operatorParam = ">"; break; default: throw new ArgumentOutOfRangeException(); } AppendNewLine(sb, string.Format(sentence, firstParam, attributeParam, operatorParam, node.ThreshHold), level); level++; } if (node.Class != null && (node.Children == null || !node.Children.Any())) { var ret = "class = " + node.Class; AppendNewLine(sb, ret, level); } else { if (node.Children != null) { var children = node.Children.ToList(); for (int index = 0; index < children.Count; index++) { GeneratePseudoCode(children[index], sb, index == 0, level); } } } }
private double computeErrorWithoutSubtree(DecisionNode tree, int mostCommon) { var branches = tree.Branches; var output = tree.Output; tree.Branches = null; tree.Output = mostCommon; double error = computeError(); tree.Branches = branches; tree.Output = output; return error; }
private void split(DecisionNode root, double[][] input, int[] output) { // 2. If all examples are for the same class, return the single-node // tree with the output label corresponding to this common class. double entropy = Statistics.Tools.Entropy(output, outputClasses); if (entropy == 0) { if (output.Length > 0) root.Output = output[0]; return; } // 3. If number of predicting attributes is empty, then return the single-node // tree with the output label corresponding to the most common value of // the target attributes in the examples. int predictors = attributes.Count(x => x == false); if (predictors <= attributes.Length - maxHeight) { root.Output = Statistics.Tools.Mode(output); return; } // 4. Otherwise, try to select the attribute which // best explains the data sample subset. double[] scores = new double[predictors]; double[] entropies = new double[predictors]; double[] thresholds = new double[predictors]; int[][][] partitions = new int[predictors][][]; // Retrieve candidate attribute indices int[] candidates = new int[predictors]; for (int i = 0, k = 0; i < attributes.Length; i++) if (!attributes[i]) candidates[k++] = i; // For each attribute in the data set #if SERIAL for (int i = 0; i < scores.Length; i++) #else Parallel.For(0, scores.Length, i => #endif { scores[i] = computeGainRatio(input, output, candidates[i], entropy, out partitions[i], out thresholds[i]); } #if !SERIAL ); #endif // Select the attribute with maximum gain ratio int maxGainIndex; scores.Max(out maxGainIndex); var maxGainPartition = partitions[maxGainIndex]; var maxGainEntropy = entropies[maxGainIndex]; var maxGainAttribute = candidates[maxGainIndex]; var maxGainRange = inputRanges[maxGainAttribute]; var maxGainThreshold = thresholds[maxGainIndex]; // Mark this attribute as already used attributes[maxGainAttribute] = true; double[][] inputSubset; int[] outputSubset; // Now, create next nodes and pass those partitions as their responsibilities. if (tree.Attributes[maxGainAttribute].Nature == DecisionVariableKind.Discrete) { // This is a discrete nature attribute. We will branch at each // possible value for the discrete variable and call recursion. DecisionNode[] children = new DecisionNode[maxGainPartition.Length]; // Create a branch for each possible value for (int i = 0; i < children.Length; i++) { children[i] = new DecisionNode(tree) { Parent = root, Value = i + maxGainRange.Min, Comparison = ComparisonKind.Equal, }; inputSubset = input.Submatrix(maxGainPartition[i]); outputSubset = output.Submatrix(maxGainPartition[i]); split(children[i], inputSubset, outputSubset); // recursion } root.Branches.AttributeIndex = maxGainAttribute; root.Branches.AddRange(children); } else if (maxGainPartition.Length > 1) { // This is a continuous nature attribute, and we achieved two partitions // using the partitioning scheme. We will branch on two possible settings: // either the value is higher than a currently detected optimal threshold // or it is lesser. DecisionNode[] children = { new DecisionNode(tree) { Parent = root, Value = maxGainThreshold, Comparison = ComparisonKind.LessThanOrEqual }, new DecisionNode(tree) { Parent = root, Value = maxGainThreshold, Comparison = ComparisonKind.GreaterThan } }; // Create a branch for lower values inputSubset = input.Submatrix(maxGainPartition[0]); outputSubset = output.Submatrix(maxGainPartition[0]); split(children[0], inputSubset, outputSubset); // Create a branch for higher values inputSubset = input.Submatrix(maxGainPartition[1]); outputSubset = output.Submatrix(maxGainPartition[1]); split(children[1], inputSubset, outputSubset); root.Branches.AttributeIndex = maxGainAttribute; root.Branches.AddRange(children); } else { // This is a continuous nature attribute, but all variables are equal // to a constant. If there is only a constant value as the predictor // and there are multiple output labels associated with this constant // value, there isn't much we can do. This node will be a leaf. // We will set the class label for this node as the // majority of the currently selected output classes. outputSubset = output.Submatrix(maxGainPartition[0]); root.Output = Statistics.Tools.Mode(outputSubset); } attributes[maxGainAttribute] = false; }
private double computeErrorReplacingSubtrees(DecisionNode tree, DecisionNode child) { var branches = tree.Branches; var output = tree.Output; tree.Branches = child.Branches; tree.Output = child.Output; double error = computeError(); tree.Branches = branches; tree.Output = output; return error; }
private void clearCache(DecisionNode current) { foreach (var node in tree.Traverse(DecisionTreeTraversal.BreadthFirst, current)) subsets[node].Clear(); }
private DecisionNode getMaxChild(DecisionNode tree) { DecisionNode max = null; int maxCount = 0; foreach (var child in tree.Branches) { var list = subsets[child]; if (list.Count > maxCount) { max = child; maxCount = list.Count; } } return max; }
private void trackDecisions(DecisionNode root, double[] input, int index) { DecisionNode current = root; while (current != null) { info[current].subset.Add(index); if (current.IsLeaf) { actual[index] = current.Output.HasValue ? current.Output.Value : -1; return; } int attribute = current.Branches.AttributeIndex; DecisionNode nextNode = null; foreach (DecisionNode branch in current.Branches) { if (branch.Compute(input[attribute])) { nextNode = branch; break; } } current = nextNode; } // Normal execution should not reach here. throw new InvalidOperationException("The tree is degenerated."); }
private static bool GetClass(IDataRow row, DecisionNode node, out string className) { className = node.Class; bool isValid = false; var rowValue = row[node.Attribute]; switch (node.Condition) { case PredicateCondition.Equal: if (row[node.Attribute].Equals(node.ThreshHold)) { isValid = true; } break; case PredicateCondition.LessThanOrEqual: if (rowValue == null) { return false; } if (Convert.ToDouble(rowValue) <= Convert.ToDouble(node.ThreshHold)) { isValid = true; } break; case PredicateCondition.GreaterThan: if (rowValue == null) { return false; } if (Convert.ToDouble(rowValue) > Convert.ToDouble(node.ThreshHold)) { isValid = true; } break; default: throw new ArgumentOutOfRangeException(); } if (isValid && node.Children != null) { foreach (var child in node.Children) { if (GetClass(row, child, out className)) { break; } } } return isValid; }
private void split(DecisionNode root, int[][] input, int[] output) { // 2. If all examples are for the same class, return the single-node // tree with the output label corresponding to this common class. double entropy = Statistics.Tools.Entropy(output, outputClasses); if (entropy == 0) { if (output.Length > 0) root.Output = output[0]; return; } // 3. If number of predicting attributes is empty, then return the single-node // tree with the output label corresponding to the most common value of // the target attributes in the examples. int predictors = attributes.Count(x => x == false); if (predictors == 0) { root.Output = Statistics.Tools.Mode(output); return; } // 4. Otherwise, try to select the attribute which // best explains the data sample subset. double[] scores = new double[predictors]; double[] entropies = new double[predictors]; int[][][] partitions = new int[predictors][][]; // Retrieve candidate attribute indices int[] candidates = new int[predictors]; for (int i = 0, k = 0; i < attributes.Length; i++) if (!attributes[i]) candidates[k++] = i; // For each attribute in the data set Parallel.For(0, scores.Length, i => { scores[i] = computeGainRatio(input, output, candidates[i], entropy, out partitions[i]); }); // Select the attribute with maximum gain ratio int maxGainIndex; scores.Max(out maxGainIndex); var maxGainPartition = partitions[maxGainIndex]; var maxGainEntropy = entropies[maxGainIndex]; var maxGainAttribute = candidates[maxGainIndex]; var maxGainRange = inputRanges[maxGainAttribute]; attributes[maxGainAttribute] = true; // Now, create next nodes and pass those partitions as their responsabilities. DecisionNode[] children = new DecisionNode[maxGainPartition.Length]; for (int i = 0; i < children.Length; i++) { children[i] = new DecisionNode(tree); children[i].Parent = root; children[i].Comparison = ComparisonKind.Equal; children[i].Value = i + maxGainRange.Min; int[][] inputSubset = input.Submatrix(maxGainPartition[i]); int[] outputSubset = output.Submatrix(maxGainPartition[i]); split(children[i], inputSubset, outputSubset); // recursion } attributes[maxGainAttribute] = false; root.Branches = new DecisionBranchNodeCollection(maxGainAttribute, children); }
private DecisionNode getMaxChild(DecisionNode tree) { DecisionNode max = null; int maxCount = 0; foreach (var child in tree.Branches) { if (child.Branches != null) { foreach (var node in child.Branches) { var list = subsets[node]; if (list.Count > maxCount) { max = node; maxCount = list.Count; } } } } return max; }
private bool compute(DecisionNode node) { int[] indices = subsets[node].ToArray(); int[] subset = outputs.Submatrix(indices); int size = indices.Length; int mostCommon = Statistics.Tools.Mode(subset); DecisionNode maxChild = getMaxChild(node); double replace = Double.PositiveInfinity; if (maxChild != null) { replace = computeErrorReplacingSubtrees(node, maxChild); replace = upperBound(replace, size); } double baseline = computeErrorSubtree(indices); double prune = computeErrorWithoutSubtree(node, mostCommon); baseline = upperBound(baseline, size); prune = upperBound(prune, size); bool changed = false; if (Math.Abs(prune - baseline) < limit || Math.Abs(replace - baseline) < limit) { if (replace < prune) { // We should replace the subtree with its maximum child node.Branches = maxChild.Branches; node.Output = maxChild.Output; foreach (var child in node.Branches) child.Parent = node; } else { // We should prune the subtree node.Branches = null; node.Output = mostCommon; } changed = true; clearCache(node); trackDecisions(node, inputs); } return changed; }
private void split(DecisionNode root, int[][] input, int[] output) { // 2. If all examples are for the same class, return the single-node // tree with the output label corresponding to this common class. double entropy = Statistics.Tools.Entropy(output, outputClasses); if (entropy == 0) { if (output.Length > 0) root.Output = output[0]; return; } // 3. If number of predicting attributes is empty, then return the single-node // tree with the output label corresponding to the most common value of // the target attributes in the examples. int predictors = attributes.Count(x => x == false); if (predictors <= attributes.Length - maxHeight) { root.Output = Statistics.Tools.Mode(output); return; } // 4. Otherwise, try to select the attribute which // best explains the data sample subset. double[] scores = new double[predictors]; double[] entropies = new double[predictors]; int[][][] partitions = new int[predictors][][]; // Retrieve candidate attribute indices int[] candidates = new int[predictors]; for (int i = 0, k = 0; i < attributes.Length; i++) if (!attributes[i]) candidates[k++] = i; // For each attribute in the data set #if SERIAL for (int i = 0; i < scores.Length; i++) #else Parallel.For(0, scores.Length, i => #endif { scores[i] = computeGainRatio(input, output, candidates[i], entropy, out partitions[i]); } #if !SERIAL ); #endif // Select the attribute with maximum gain ratio int maxGainIndex; scores.Max(out maxGainIndex); var maxGainPartition = partitions[maxGainIndex]; var maxGainEntropy = entropies[maxGainIndex]; var maxGainAttribute = candidates[maxGainIndex]; var maxGainRange = inputRanges[maxGainAttribute]; attributes[maxGainAttribute] = true; // Now, create next nodes and pass those partitions as their responsibilities. DecisionNode[] children = new DecisionNode[maxGainPartition.Length]; for (int i = 0; i < children.Length; i++) { children[i] = new DecisionNode(tree); children[i].Parent = root; children[i].Comparison = ComparisonKind.Equal; children[i].Value = i + maxGainRange.Min; int[][] inputSubset = input.Submatrix(maxGainPartition[i]); int[] outputSubset = output.Submatrix(maxGainPartition[i]); split(children[i], inputSubset, outputSubset); // recursion if (children[i].IsLeaf) { // If the resulting node is a leaf, and it has not // been assigned a value because there were no available // output samples in this category, we will be assigning // the most common label for the current node to it. if (!Rejection && !children[i].Output.HasValue) children[i].Output = Statistics.Tools.Mode(output); } } attributes[maxGainAttribute] = false; root.Branches.AttributeIndex = maxGainAttribute; root.Branches.AddRange(children); }
public static void LoadLeaves(DecisionNode node, List<DecisionNode> leaves) { if (node.IsLeaf) { leaves.Add(node); return; } foreach (var child in node.Children) { LoadLeaves(child, leaves); } }
/// <summary> /// Attempts to prune a node's subtrees. /// </summary> /// /// <returns>Whether the current node was changed or not.</returns> /// private bool compute(DecisionNode node) { int[] indices = subsets[node].ToArray(); int[] outputSubset = outputs.Get(indices); if (indices.Length == 0) { // The rule employed by this node doesn't cover // any input points. This node could be removed. node.Branches = null; node.Output = null; return true; } int size = indices.Length; double baselineError = computeError(); baselineError = upperBound(baselineError, size); int mostCommon = outputSubset.Mode(); double pruneError = computeErrorWithoutSubtree(node, mostCommon); pruneError = upperBound(pruneError, size); DecisionNode maxChild = getMaxChild(node); double replaceError = computeErrorReplacingSubtrees(node, maxChild); replaceError = upperBound(replaceError, size); bool changed = false; if (Math.Abs(pruneError - baselineError) < limit || Math.Abs(replaceError - baselineError) < limit) { if (replaceError < pruneError) { // We should replace the subtree with its maximum child node.Branches = maxChild.Branches; node.Output = maxChild.Output; foreach (var child in node.Branches) child.Parent = node; } else { // We should prune the subtree node.Branches = null; node.Output = mostCommon; } changed = true; foreach (var child in node) subsets[child].Clear(); double[][] inputSubset = inputs.Get(indices); for (int i = 0; i < inputSubset.Length; i++) trackDecisions(node, inputSubset[i], i); } return changed; }
private void Prune(DecisionNode node) { if (node.Children != null) { var children = node.Children.ToList(); for (int index = children.Count - 1; index >= 0; index--) { var child = children[index]; if (child.Statistics.DatasetLength < Options.MinItemsOnNode || (child.Depth > Options.MaxTreeDepth && Options.MaxTreeDepth > 0)) { children.Remove(child); } else { Prune(child); } } node.Children = children.ToArray(); } }
private double computeError(DecisionNode node) { List<int> indices = info[node].subset; int error = 0; foreach (int i in indices) if (outputs[i] != actual[i]) error++; return error / (double)indices.Count; }
private void createCache(DecisionNode current) { foreach (var node in tree.Traverse(DecisionTreeTraversal.BreadthFirst, current)) subsets[node] = new List<int>(); }
private double computeGain(DecisionNode node) { if (node.IsLeaf) return Double.NegativeInfinity; // Compute the sum of misclassifications at the children double sum = 0; foreach (var child in node.Branches) sum += info[child].error; // Get the misclassifications at the current node double current = info[node].error; // Compute the expected gain at the current node: return sum - current; }
public DecisionTree(Minion owner, DecisionNode root) { _root = root; _owner = owner; }
private void trackDecisions(DecisionNode current, double[][] input) { for (int i = 0; i < input.Length; i++) trackDecisions(current, input[i], i); }
private static double[] ComputeEstimates(IDataRow row, DecisionNode node) { var rowValue = row[node.Attribute]; switch (node.Condition) { case PredicateCondition.Equal: if (!row[node.Attribute].Equals(node.ThreshHold)) { return null; } break; case PredicateCondition.LessThanOrEqual: if ((rowValue == null) || (Convert.ToDouble(rowValue) > Convert.ToDouble(node.ThreshHold))) { return null; } break; case PredicateCondition.GreaterThan: if ((rowValue == null) || (Convert.ToDouble(rowValue) <= Convert.ToDouble(node.ThreshHold))) { return null; } break; default: return null; } if (node.Children != null && node.Children.Any()) { foreach (var child in node.Children) { var estimates = ComputeEstimates(row, child); if (estimates != null) { return estimates; } } } else { var estimates = new double[node.Statistics.Frequencies.Length]; for (int index = 0; index < estimates.Length; index++) { estimates[index] = node.Statistics.Frequencies[index]/(double) node.Statistics.DatasetLength; } return estimates; } return null; }