/// <summary> /// перебор дерева по веткам /// </summary> /// <param name="D_Node"></param> /// <param name="D_B_N_C"></param> /// <param name="l"></param> public void recursion(DecisionNode D_Node, DecisionBranchNodeCollection D_B_N_C, int l) { int j; if (D_B_N_C != null) { for (j = 0; j < D_B_N_C.Count; j++) { dinosaurs.Add(D_B_N_C[j].ToString()); str.AppendLine(D_B_N_C[j].ToString()); recursion(D_B_N_C[j].Parent, D_B_N_C[j].Branches, j); } dinosaurs.Add("E"); dinosaurs.Add(D_Node.ToString()); str.AppendLine("E"); str.AppendLine(D_Node.ToString()); } str.AppendLine(D_Node.Branches[l].Output.ToString()); dinosaurs.Add(D_Node.Branches[l].Output.ToString()); dinosaurs.Add("WER"); str.AppendLine("WER"); dinosaurs.Add(D_Node.ToString()); str.AppendLine(D_Node.ToString()); }
/// <summary> /// Computes the decision for a given input. /// </summary> /// /// <param name="input">The input data.</param> /// /// <returns>A predicted class for the given input.</returns> /// public int Compute(double[] input) { 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(current.Output.Value); } // 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; break; } } current = nextNode; } // Normal execution should not reach here. throw new InvalidOperationException("The tree is degenerated."); }
private TreeNode convert(DecisionNode node) { TreeNode treeNode = new TreeNode(node.ToString()); if (node.IsLeaf) { treeNode.Nodes.Add(new TreeNode(node.Output.ToString())); } else { foreach (var child in node.Branches) treeNode.Nodes.Add(convert(child)); } return treeNode; }
/// <summary> /// Post-order tree traversal method. /// </summary> /// /// <remarks> /// Adapted from John Cowan (1998) recommendation. /// </remarks> /// public static IEnumerator <DecisionNode> PostOrder(DecisionNode tree) { var cursor = new Dictionary <DecisionNode, int>(); DecisionNode currentNode = tree; while (currentNode != null) { // Move down to first child DecisionNode nextNode = null; if (currentNode.Branches != null) { nextNode = currentNode.Branches.FirstOrDefault(); } if (nextNode != null) { currentNode = nextNode; continue; } // No child nodes, so walk tree while (currentNode != null) { yield return(currentNode); // post order // Move to sibling if possible. nextNode = GetNextSibling(cursor, currentNode); if (nextNode != null) { currentNode = nextNode; break; } // Move up if (currentNode == nextNode) { currentNode = null; } else { currentNode = currentNode.Parent; } } } }
private void create(DecisionNode node, int depth) { string indent = new string(' ', depth * 4); if (!node.IsLeaf) { int attributeIndex = node.Branches.AttributeIndex; // Create all comparison expressions for (int i = 0; i < node.Branches.Count; i++) { DecisionNode child = node.Branches[i]; string cmp = ComparisonExtensions.ToString(child.Comparison); if (i == 0) { writer.Write(indent + "if "); } else { writer.Write(indent + "else if "); } string value = child.Value.Value.ToString(CultureInfo.InvariantCulture); writer.Write("(input[{0}] {1} {2}) {{", attributeIndex, cmp, value); writer.WriteLine(); create(child, depth + 1); writer.WriteLine(indent + "}"); } writer.WriteLine(indent + "else throw new ArgumentException(\"input\", \"Unexpected value at position " + attributeIndex + ".\");"); } else // node is a leaf { if (node.Output.HasValue) { string value = node.Output.Value.ToString(CultureInfo.InvariantCulture); writer.WriteLine(indent + "return " + value + ";"); } else { writer.WriteLine(indent + "return -1;"); } } }
/// <summary> /// Depth-first traversal method. /// </summary> /// public static IEnumerator<DecisionNode> DepthFirst(DecisionNode tree) { if (tree == null) yield break; var stack = new Stack<DecisionNode>(new[] { tree }); while (stack.Count != 0) { DecisionNode current = stack.Pop(); yield return current; if (current.Branches != null) for (int i = current.Branches.Count - 1; i >= 0; i--) stack.Push(current.Branches[i]); } }
/// <summary> /// Breadth-first traversal method. /// </summary> /// public static IEnumerator<DecisionNode> BreadthFirst(DecisionNode tree) { if (tree == null) yield break; var queue = new Queue<DecisionNode>(new[] { tree }); while (queue.Count != 0) { DecisionNode current = queue.Dequeue(); yield return current; if (current.Branches != null) { foreach (var child in current.Branches) queue.Enqueue(child); } } }
private void CreateRuleList(DecisionNode node, string stringTemp) { string attributeName; string attributeValue; string connectSymbol = ""; if (node.IsLeaf) { attributeName = TableMetaData.ClassAttribute; attributeValue = this.codification.Translate(attributeName, Convert.ToInt32(node.Output)); if (node.Output.HasValue) { if (attributeValue.Equals(TableMetaData.PositiveString)) { textBoxYesRules.Text += stringTemp + " ==> " + attributeValue + Environment.NewLine + Environment.NewLine; } else { textBoxNoRules.Text += stringTemp + " ==> " + attributeValue + Environment.NewLine + Environment.NewLine; } } } else { foreach (var child in node.Branches) { attributeName = child.Owner.Attributes[child.Parent.Branches.AttributeIndex].Name; attributeValue = this.codification.Translate(attributeName, Convert.ToInt32(child.Value)); connectSymbol = stringTemp.Equals("") ? "" : " & "; CreateRuleList(child, stringTemp + connectSymbol + attributeName + " = " + attributeValue); } } }
/// <summary> /// Depth-first traversal method. /// </summary> /// public static IEnumerator <DecisionNode> DepthFirst(DecisionNode tree) { if (tree == null) { yield break; } var stack = new Stack <DecisionNode>(new[] { tree }); while (stack.Count != 0) { DecisionNode current = stack.Pop(); yield return(current); if (current.Branches != null) { for (int i = current.Branches.Count - 1; i >= 0; i--) { stack.Push(current.Branches[i]); } } } }
/// <summary> /// Breadth-first traversal method. /// </summary> /// public static IEnumerator <DecisionNode> BreadthFirst(DecisionNode tree) { if (tree == null) { yield break; } var queue = new Queue <DecisionNode>(new[] { tree }); while (queue.Count != 0) { DecisionNode current = queue.Dequeue(); yield return(current); if (current.Branches != null) { foreach (var child in current.Branches) { queue.Enqueue(child); } } } }
private void create(DecisionNode node, int depth) { string indent = new string(' ', depth * 4); if (!node.IsLeaf) { int attributeIndex = node.Branches.AttributeIndex; // Create all comparison expressions for (int i = 0; i < node.Branches.Count; i++) { DecisionNode child = node.Branches[i]; string cmp = ComparisonExtensions.ToString(child.Comparison); if (i == 0) writer.Write(indent + "if "); else writer.Write(indent + "else if "); writer.Write("(input[{0}] {1} {2}) {{", attributeIndex, cmp, child.Value); writer.WriteLine(); create(child, depth + 1); writer.WriteLine(indent + "}"); } writer.WriteLine(indent + "else throw new ArgumentException(\"input\", \"Unexpected value at position " + attributeIndex + ".\");"); } else // node is a leaf { if (node.Output.HasValue) writer.WriteLine(indent + "return " + node.Output.Value + ";"); else writer.WriteLine(indent + "return -1;"); } }
private TreeNode convert(DecisionNode node) { TreeNode treeNode = (codebook == null) ? new TreeNode(node.ToString()) : new TreeNode(node.ToString(codebook)); if (!node.IsLeaf) { foreach (var child in node.Branches) treeNode.Nodes.Add(convert(child)); return treeNode; } if (codebook == null || !node.Output.HasValue) { treeNode.Nodes.Add(new TreeNode(node.Output.ToString())); return treeNode; } int index = node.Parent.Branches.AttributeIndex; var attrib = treeSource.Attributes[index]; if (attrib.Nature != DecisionVariableKind.Discrete) { treeNode.Nodes.Add(new TreeNode(node.Output.ToString())); return treeNode; } string value = codebook.Translate(attrib.Name, node.Output.Value); treeNode.Nodes.Add(new TreeNode(value)); return treeNode; }
internal static DecisionNode GetNextSibling(Dictionary<DecisionNode, int> cursors, DecisionNode node) { var parent = node.Parent; if (parent == null) return null; // Get current node index int index; if (!cursors.TryGetValue(node, out index)) cursors[node] = index = 0; int nextIndex = index + 1; if (nextIndex < parent.Branches.Count) { var sibling = parent.Branches[nextIndex]; cursors[sibling] = nextIndex; return sibling; } return null; }
/// <summary> /// Post-order tree traversal method. /// </summary> /// /// <remarks> /// Adapted from John Cowan (1998) recommendation. /// </remarks> /// public static IEnumerator<DecisionNode> PostOrder(DecisionNode tree) { var cursor = new Dictionary<DecisionNode, int>(); DecisionNode currentNode = tree; while (currentNode != null) { // Move down to first child DecisionNode nextNode = null; if (currentNode.Branches != null) nextNode = currentNode.Branches.FirstOrDefault(); if (nextNode != null) { currentNode = nextNode; continue; } // No child nodes, so walk tree while (currentNode != null) { yield return currentNode; // post order // Move to sibling if possible. nextNode = GetNextSibling(cursor, currentNode); if (nextNode != null) { currentNode = nextNode; break; } // Move up if (currentNode == nextNode) currentNode = null; else currentNode = currentNode.Parent; } } }
private Expression create(DecisionNode node) { if (!node.IsLeaf) { int attributeIndex = node.Branches.AttributeIndex; // Create all comparison expressions BinaryExpression[] comparisons = new BinaryExpression[node.Branches.Count]; Expression[] childExpression = new Expression[node.Branches.Count]; for (int i = 0; i < comparisons.Length; i++) { DecisionNode child = node.Branches[i]; var expr = Expression.ArrayIndex(inputs, Expression.Constant(attributeIndex)); var cons = Expression.Constant(child.Value); switch (child.Comparison) { case ComparisonKind.Equal: comparisons[i] = Expression.Equal(expr, cons); break; case ComparisonKind.GreaterThan: comparisons[i] = Expression.GreaterThan(expr, cons); break; case ComparisonKind.GreaterThanOrEqual: comparisons[i] = Expression.GreaterThanOrEqual(expr, cons); break; case ComparisonKind.LessThan: comparisons[i] = Expression.LessThan(expr, cons); break; case ComparisonKind.LessThanOrEqual: comparisons[i] = Expression.LessThanOrEqual(expr, cons); break; case ComparisonKind.NotEqual: comparisons[i] = Expression.NotEqual(expr, cons); break; default: throw new InvalidOperationException("Unexpected node comparison type."); } childExpression[i] = create(node.Branches[i]); } // Create expression for else expressions ConstructorInfo ex = typeof(ArgumentException).GetConstructor(new[] { typeof(string), typeof(string) }); var lastElse = Expression.IfThenElse(comparisons[comparisons.Length - 1], childExpression[comparisons.Length - 1], Expression.Throw(Expression.New(ex, Expression.Constant("Input contains a value outside of expected ranges."), Expression.Constant("input")))); ConditionalExpression currentIf = null; for (int i = comparisons.Length - 2; i >= 0; i--) { currentIf = Expression.IfThenElse(comparisons[i], childExpression[i], lastElse); lastElse = currentIf; } return(currentIf); } else // node is a leaf { if (node.Output.HasValue) { return(Expression.Return(label, Expression.Constant(node.Output.Value), typeof(int))); } return(Expression.Return(label, Expression.Constant(-1), typeof(int))); } }
private Expression create(DecisionNode node) { if (!node.IsLeaf) { int attributeIndex = node.Branches.AttributeIndex; // Create all comparison expressions BinaryExpression[] comparisons = new BinaryExpression[node.Branches.Count]; Expression[] childExpression = new Expression[node.Branches.Count]; for (int i = 0; i < comparisons.Length; i++) { DecisionNode child = node.Branches[i]; var expr = Expression.ArrayIndex(inputs, Expression.Constant(attributeIndex)); var cons = Expression.Constant(child.Value); switch (child.Comparison) { case ComparisonKind.Equal: comparisons[i] = Expression.Equal(expr, cons); break; case ComparisonKind.GreaterThan: comparisons[i] = Expression.GreaterThan(expr, cons); break; case ComparisonKind.GreaterThanOrEqual: comparisons[i] = Expression.GreaterThanOrEqual(expr, cons); break; case ComparisonKind.LessThan: comparisons[i] = Expression.LessThan(expr, cons); break; case ComparisonKind.LessThanOrEqual: comparisons[i] = Expression.LessThanOrEqual(expr, cons); break; case ComparisonKind.NotEqual: comparisons[i] = Expression.NotEqual(expr, cons); break; default: throw new InvalidOperationException("Unexpected node comparison type."); } childExpression[i] = create(node.Branches[i]); } // Create expression for else expressions ConstructorInfo ex = typeof(ArgumentException).GetConstructor(new[] { typeof(string), typeof(string) }); var lastElse = Expression.IfThenElse(comparisons[comparisons.Length - 1], childExpression[comparisons.Length - 1], Expression.Throw(Expression.New(ex, Expression.Constant("Input contains a value outside of expected ranges."), Expression.Constant("input")))); ConditionalExpression currentIf = null; for (int i = comparisons.Length - 2; i >= 0; i--) { currentIf = Expression.IfThenElse(comparisons[i], childExpression[i], lastElse); lastElse = currentIf; } return currentIf; } else // node is a leaf { if (node.Output.HasValue) return Expression.Return(label, Expression.Constant(node.Output.Value), typeof(int)); return Expression.Return(label, Expression.Constant(-1), typeof(int)); } }
internal static DecisionNode GetNextSibling(Dictionary <DecisionNode, int> cursors, DecisionNode node) { var parent = node.Parent; if (parent == null) { return(null); } // Get current node index int index; if (!cursors.TryGetValue(node, out index)) { cursors[node] = index = 0; } int nextIndex = index + 1; if (nextIndex < parent.Branches.Count) { var sibling = parent.Branches[nextIndex]; cursors[sibling] = nextIndex; return(sibling); } return(null); }
private void split(DecisionNode root, int[][] input, int[] output) { double entropy = Accord.Statistics.Tools.Entropy(output, outputClasses); if (entropy == 0) { if (output.Length > 0) root.Output = output[0]; return; } int predictors = attributes.Count(x => x == false); if (predictors < attributes.Length - maxHeight) { root.Output = Accord.Statistics.Tools.Mode(output); return; } 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=44; //scores.Max(out maxGainIndex); var maxGainPartition = partitions[maxGainIndex]; var maxGainEntropy = entropies[maxGainIndex]; var maxGainAttribute = candidates[maxGainIndex]; var maxGainRange = inputRanges[maxGainAttribute]; attributes[maxGainAttribute] = true; 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; int[] outputSubset = output; split(children[i], inputSubset, outputSubset); // recursion } attributes[maxGainAttribute] = false; root.Branches.AttributeIndex = maxGainAttribute; root.Branches.AddRange(children); }
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 = Accord.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 = Accord.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; var maxGainPartition = partitions[6]; var maxGainEntropy = entropies[3]; var maxGainAttribute = candidates[2]; var maxGainRange = inputRanges[4]; var maxGainThreshold = thresholds[5]; // 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 = Accord.Statistics.Tools.Mode(outputSubset); } attributes[maxGainAttribute] = false; }
// 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; }