Beispiel #1
0
        /// <summary>
        /// Finds the terminal region (=leaf node) for each sample in X.
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public MathNet.Numerics.LinearAlgebra.Generic.Vector <double> apply(
            MathNet.Numerics.LinearAlgebra.Generic.Matrix <double> x)
        {
            //cdef double* threshold = this.threshold

            uint nSamples = (uint)x.RowCount;

            MathNet.Numerics.LinearAlgebra.Generic.Vector <double> @out = DenseVector.Create((int)nSamples, i => 0.0);

            for (int i = 0; i < nSamples; i++)
            {
                uint nodeId = 0;

                // While node_id not a leaf
                while (ChildrenLeft[nodeId] != _TREE_LEAF)
                {
                    // ... and children_right[node_id] != _TREE_LEAF:
                    if (x[i, (int)Feature[nodeId]] <= Threshold[nodeId])
                    {
                        nodeId = ChildrenLeft[nodeId];
                    }
                    else
                    {
                        nodeId = ChildrenRight[nodeId];
                    }
                }

                @out[i] = nodeId;
            }

            return(@out);
        }
Beispiel #2
0
        /// <summary>
        /// Computes the importance of each feature (aka variable).
        /// </summary>
        /// <param name="normalize"></param>
        public MathNet.Numerics.LinearAlgebra.Generic.Vector <double> ComputeFeatureImportances(bool normalize = true)
        {
            MathNet.Numerics.LinearAlgebra.Generic.Vector <double> importances =
                DenseVector.Create(this.nFeatures, i => 0.0);

            for (uint node = 0; node < NodeCount; node++)
            {
                if (ChildrenLeft[node] != _TREE_LEAF)
                {
                    // ... and children_right[node] != _TREE_LEAF:
                    uint nLeft  = NNodeSamples[ChildrenLeft[node]];
                    uint nRight = NNodeSamples[ChildrenRight[node]];

                    importances[(int)Feature[node]] +=
                        NNodeSamples[node] * Impurity[node]
                        - nLeft * Impurity[ChildrenLeft[node]]
                        - nRight * Impurity[ChildrenRight[node]];
                }
            }

            importances = importances.Divide(this.NNodeSamples[0]);

            if (normalize)
            {
                double normalizer = importances.Sum();

                if (normalizer > 0.0)
                {
                    //   Avoid dividing by zero (e.g., when root is pure)
                    importances /= normalizer;
                }
            }

            return(importances);
        }
Beispiel #3
0
 public static Vector3 ToVector3(MathNet.Numerics.LinearAlgebra.Generic.Vector <float> v)
 {
     return(new Vector3(v[0], v[1], v[2]));
 }
Beispiel #4
0
        /// <summary>
        /// Build a decision tree from the training set (X, y).
        /// </summary>
        public void build(MathNet.Numerics.LinearAlgebra.Generic.Matrix <double> x,
                          MathNet.Numerics.LinearAlgebra.Generic.Matrix <double> y,
                          MathNet.Numerics.LinearAlgebra.Generic.Vector <double> sampleWeight = null)
        {
            // Prepare data before recursive partitioning

            // Initial capacity
            int initCapacity;

            if (this.maxDepth <= 10)
            {
                initCapacity = (int)Math.Pow(2, (this.maxDepth + 1)) - 1;
            }
            else
            {
                initCapacity = 2047;
            }

            this.Resize(initCapacity);

            // Recursive partition (without actual recursion)
            SplitterBase splitter = this.splitter;

            splitter.init(x, y, sampleWeight == null ? null : sampleWeight.ToArray());

            uint stackNValues  = 5;
            uint stackCapacity = 50;

            uint[] stack = new uint[stackCapacity];


            stack[0] = 0;                  // start
            stack[1] = splitter.n_samples; // end
            stack[2] = 0;                  // depth
            stack[3] = _TREE_UNDEFINED;    // parent
            stack[4] = 0;                  // is_left

            uint   pos       = 0;
            uint   feature   = 0;
            double threshold = 0;
            double impurity  = 0;

            while (stackNValues > 0)
            {
                stackNValues -= 5;

                uint start  = stack[stackNValues];
                uint end    = stack[stackNValues + 1];
                uint depth  = stack[stackNValues + 2];
                uint parent = stack[stackNValues + 3];
                bool isLeft = stack[stackNValues + 4] != 0;

                uint nNodeSamples = end - start;
                bool isLeaf       = ((depth >= this.maxDepth) ||
                                     (nNodeSamples < this.minSamplesSplit) ||
                                     (nNodeSamples < 2 * this.minSamplesLeaf));

                splitter.node_reset(start, end, ref impurity);
                isLeaf = isLeaf || (impurity < 1e-7);

                if (!isLeaf)
                {
                    splitter.node_split(ref pos, ref feature, ref threshold);
                    isLeaf = isLeaf || (pos >= end);
                }

                uint nodeId = this.AddNode(parent, isLeft, isLeaf, feature,
                                           threshold, impurity, nNodeSamples);

                if (isLeaf)
                {
                    // Don't store value for internal nodes
                    splitter.node_value(this.Value, nodeId * this.valueStride);
                }
                else
                {
                    if (stackNValues + 10 > stackCapacity)
                    {
                        stackCapacity *= 2;
                        var newStack = new uint[stackCapacity];
                        Array.Copy(stack, newStack, stack.Length);
                        stack = newStack;
                    }

                    // Stack right child
                    stack[stackNValues]     = pos;
                    stack[stackNValues + 1] = end;
                    stack[stackNValues + 2] = depth + 1;
                    stack[stackNValues + 3] = nodeId;
                    stack[stackNValues + 4] = 0;
                    stackNValues           += 5;

                    // Stack left child
                    stack[stackNValues]     = start;
                    stack[stackNValues + 1] = pos;
                    stack[stackNValues + 2] = depth + 1;
                    stack[stackNValues + 3] = nodeId;
                    stack[stackNValues + 4] = 1;
                    stackNValues           += 5;
                }
            }

            this.Resize((int)this.NodeCount);
            this.splitter = null; // Release memory
        }