예제 #1
0
        /**
         * Recursively descends through the tree, removing
         * the supplied node and any descendants from
         * the internal node list.
         *
         * @param node The root node of the subtree to remove.
         */
        public void recursiveRemoveSubtree(DecisionTreeNode node)
        {
            if (node == null)
            {
                return;
            }

            // First, recursively remove all the node's children.
            // (This loop doesn't run if the node is a leaf node)
            for (int i = 0; i < node.getArcLabelCount(); i++)
            {
                if (node.getChild(i) != null)
                {
                    recursiveRemoveSubtree(node.getChild(i));
                }
            }

            // Remove this node from the vector.
            Nodes.Remove(node);

            // If the node was a leaf, then we have to update
            // the classification statistics.
            if (node.isLeaf())
            {
                TrainingCorrect -=
                    node.getTrainingEgsCorrectClassUsingBestTrainingIndex();
                TestingCorrect -=
                    node.getTestingEgsCorrectClassUsingBestTrainingIndex();
            }
            else
            {
                InternalNodes--;
            }
        }
예제 #2
0
        /// <summary>
        /// Search through the current tree and return the first
        /// node without a complete set of children.  The arc
        /// number for the first missing child is returned in
        /// position 0 of the arcNum array.
        /// </summary>
        /// <param name="node">The node at which to begin the search.</param>
        /// <param name="arcNum">An integer array of size 1.  The arc
        /// number for the first missing child is
        /// returned in arcNum[0].</param>
        /// <returns>A reference to the first incomplete node
        /// in the tree (farthest left).  The method
        /// returns null if the tree is already complete,
        /// or if the tree is empty.</returns>
        public DecisionTreeNode findIncompleteNode(DecisionTreeNode node, int[] arcNum)
        {
            // The search is recursive - at some point, we
            // may want to change this to a non-recursive
            // algorithm (if we start dealing with extremely
            // large trees?)

            // Base cases.
            if (node == null || node.isLeaf())
            {
                return(null);
            }

            // Recursive case. This node is not a leaf - so descend.
            for (int i = 0; i < node.getArcLabelCount(); i++)
            {
                DecisionTreeNode nextNode;

                if ((nextNode = findIncompleteNode(node.getChild(i), arcNum)) != null)
                {
                    return(nextNode);
                }
            }

            if ((arcNum[0] = node.getFirstMissingChild()) >= 0)
            {
                // We found a node with a missing child, which
                // is already stored in arcNum - so return this
                // node.
                return(node);
            }

            // We searched all the subtrees attached to this
            // node, and didn't find anything, so return null.
            return(null);
        }
        /**
          * An implementation of the recursive decision tree
          * pessimistic pruning algorithm.  Given a parent
          * node, the method will prune all the branches
          * below the node.
          *
          * @param node The root node of the tree to prune.
          *
          * @param error A <code>double</code> array of size 1. The
          *        array is used to store the current error value.
          *
          * @return <code>true</code> if an entire subtree was successfully
          *         pruned, or <code>false</code> otherwise.
          */
        public bool prunePessimisticDT(DecisionTreeNode node, double[] error)
        {
            // Post-order walk through the tree, marking
            // our path as we go along.
            if (node.isLeaf())
            {
                if (node.getTrainingEgsAtNode() == 0)
                {
                    error[0] = 0;
                    return true;
                }
                else
                {
                    // We do the error calculation in two steps -
                    // Here we multiply the error value by the number
                    // of examples that reach the node.  When the method
                    // is called recursively, this value will be divided
                    // by the number of examples that reach the parent
                    // node (thus weighting the error from each child).
                    int errors1 = (int)node.getTrainingEgsAtNode() - node.getTrainingEgsCorrectClassUsingBestTrainingIndex();
                    double p1 = (double)(errors1 + 1.0) / (node.getTrainingEgsAtNode() + 2.0);

                    error[0] = node.getTrainingEgsAtNode() * errorBar(p1, node.getTrainingEgsAtNode()) + errors1;

                    return true;
                }
            }

            // We're at an internal node, so compute the error
            // of the children and use the result to determine
            // if we prune or not.
            double errorSum = 0;

            for (int i = 0; i < node.getArcLabelCount(); i++)
            {
                // Mark our current path.
                Tree.flagNode(node, i);

                if (!prunePessimisticDT(node.getChild(i), error))
                {
                    Tree.flagNode(node, -2);
                    return false;
                }

                errorSum += error[0];
            }

            // Mark the node as our current target.
            Tree.flagNode(node, -1);

            // Get the worst-case performance of this node.
            double errorWorst;

            if (node.getTrainingEgsAtNode() == 0)
            {
                error[0] = 0;
                return true;
            }

            int errors = (int)node.getTrainingEgsAtNode() - node.getTrainingEgsCorrectClassUsingBestTrainingIndex();
            double p = (double)(errors + 1.0) / (node.getTrainingEgsAtNode() + 2.0);

            errorWorst = (double)node.getTrainingEgsAtNode() * errorBar(p, node.getTrainingEgsAtNode()) + errors;

            DecisionTreeNode newNode = node;

            if (errorWorst < errorSum)
            {
                // We need to "prune" this node to a leaf.
                DecisionTreeNode parent = node.getParent();
                int arcNum = -1;

                if (parent != null)
                {
                    arcNum = parent.getChildPosition(node);
                }

                Tree.pruneSubtree(node);

                // Figure out the label for the new leaf.
                String label = null;

                try
                {
                    label = DatasetUse.getTargetAttribute().getAttributeValueByNum(node.getTrainingBestTarget());
                }
                catch (Exception e)
                {
                    // Should never happen.
                    //e.printStackTrace();
                }

                node.getMask().mask(0, node.getTrainingBestTarget());

                newNode =
                  Tree.addLeafNode(parent, arcNum, label,
                    node.getMask(),
                    node.getTrainingEgsAtNode(),
                    node.getTrainingBestTarget(),
                    node.getTrainingEgsCorrectClassUsingBestTrainingIndex(),
                    node.getTestingEgsCorrectClassUsingBestTrainingIndex(),
                    node.getTestingEgsAtNode(),
                    node.getTestingBestTarget(),
                    node.getTestingEgsCorrectClassUsingBestTestingIndex(),
                    node.getTrainingEgsCorrectClassUsingBestTestingIndex());
            }

            // Update the count.
            if (newNode.isLeaf())
            {
                error[0] = errorWorst;
            }
            else
            {
                error[0] = errorSum;
            }

            // All finished, unmark the node if it still exists.
            Tree.flagNode(node, -2);

            return true;
        }
        /**
         * An implementation of the recursive decision tree
         * reduced error pruning algorithm.  Given a parent
         * node, the method will prune all the branches
         * below the node.
         *
         * @param node The root node of the tree to prune.
         *
         * @param error A <code>double</code> array of size 1. The
         *        array is used to store the current error value.
         *
         * @return <code>true</code> if an entire subtree was successfully
         *         pruned, or <code>false</code> otherwise.
         */
        public bool pruneReducedErrorDT(DecisionTreeNode node, double[] error)
        {
            if (node.isLeaf())
            {
                error[0] = node.getTestingEgsAtNode() - node.getTestingEgsCorrectClassUsingBestTrainingIndex();
                return true;
            }

            // We're at an internal node, so compute the error
            // of the children and use the result to determine
            // if we prune or not.
            double errorSum = 0;

            for (int i = 0; i < node.getArcLabelCount(); i++)
            {
                // Mark our current path.
                Tree.flagNode(node, i);

                if (!pruneReducedErrorDT(node.getChild(i), error))
                {
                    Tree.flagNode(node, -2);
                    return false;
                }

                errorSum += error[0];
            }

            // Mark the node as our current target.
            Tree.flagNode(node, -1);

            // Get the best-case performance of this node.
            double errorBest = node.getTestingEgsAtNode() - node.getTestingEgsCorrectClassUsingBestTestingIndex();

            DecisionTreeNode newNode = node;

            if (errorBest < errorSum)
            {
                // We need to "prune" this node to a leaf.
                DecisionTreeNode parent = node.getParent();
                int arcNum = -1;

                if (parent != null)
                {
                    arcNum = parent.getChildPosition(node);
                }

                Tree.pruneSubtree(node);

                // Figure out the label for the new leaf.
                String label = null;

                try
                {
                    label = DatasetUse.getTargetAttribute().getAttributeValueByNum(node.getTestingBestTarget());
                }
                catch (Exception e)
                {
                    // Should never happen.
                    //e.printStackTrace();
                }

                node.getMask().mask(0, node.getTestingBestTarget());

                newNode = Tree.addLeafNode(parent, arcNum, label,
                    node.getMask(),
                    node.getTrainingEgsAtNode(),
                    node.getTestingBestTarget(),
                    node.getTrainingEgsCorrectClassUsingBestTestingIndex(),
                    node.getTestingEgsCorrectClassUsingBestTestingIndex(),
                    node.getTestingEgsAtNode(),
                    node.getTestingBestTarget(),
                    node.getTestingEgsCorrectClassUsingBestTestingIndex(),
                    node.getTrainingEgsCorrectClassUsingBestTestingIndex());
            }

            // Update the count.
            if (newNode.isLeaf())
            {
                error[0] = errorBest;
            }
            else
            {
                error[0] = errorSum;
            }

            // All finished, unmark the node if it still exists.
            Tree.flagNode(node, -2);

            return true;
        }
예제 #5
0
        /**
           * Recursively descends through the tree, removing
           * the supplied node and any descendants from
           * the internal node list.
           *
           * @param node The root node of the subtree to remove.
           */
        public void recursiveRemoveSubtree(DecisionTreeNode node)
        {
            if (node == null) return;

            // First, recursively remove all the node's children.
            // (This loop doesn't run if the node is a leaf node)
            for (int i = 0; i < node.getArcLabelCount(); i++)
                if (node.getChild(i) != null)
                    recursiveRemoveSubtree(node.getChild(i));

            // Remove this node from the vector.
            Nodes.Remove(node);

            // If the node was a leaf, then we have to update
            // the classification statistics.
            if (node.isLeaf())
            {
                TrainingCorrect -=
                  node.getTrainingEgsCorrectClassUsingBestTrainingIndex();
                TestingCorrect -=
                  node.getTestingEgsCorrectClassUsingBestTrainingIndex();
            }
            else
                InternalNodes--;
        }
예제 #6
0
        /// <summary>
        /// Search through the current tree and return the first
        /// node without a complete set of children.  The arc
        /// number for the first missing child is returned in
        /// position 0 of the arcNum array.
        /// </summary>
        /// <param name="node">The node at which to begin the search.</param>
        /// <param name="arcNum">An integer array of size 1.  The arc
        /// number for the first missing child is
        /// returned in arcNum[0].</param>
        /// <returns>A reference to the first incomplete node
        /// in the tree (farthest left).  The method
        /// returns null if the tree is already complete,
        /// or if the tree is empty.</returns>
        public DecisionTreeNode findIncompleteNode(DecisionTreeNode node, int[] arcNum)
        {
            // The search is recursive - at some point, we
            // may want to change this to a non-recursive
            // algorithm (if we start dealing with extremely
            // large trees?)

            // Base cases.
            if (node == null || node.isLeaf())
            {
                return null;
            }

            // Recursive case. This node is not a leaf - so descend.
            for (int i = 0; i < node.getArcLabelCount(); i++)
            {
                DecisionTreeNode nextNode;

                if ((nextNode = findIncompleteNode(node.getChild(i), arcNum)) != null)
                {
                    return nextNode;
                }
            }

            if ((arcNum[0] = node.getFirstMissingChild()) >= 0)
            {
                // We found a node with a missing child, which
                // is already stored in arcNum - so return this
                // node.
                return node;
            }

            // We searched all the subtrees attached to this
            // node, and didn't find anything, so return null.
            return null;
        }