/// <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); }
/// <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); }
public static Vector3 ToVector3(MathNet.Numerics.LinearAlgebra.Generic.Vector <float> v) { return(new Vector3(v[0], v[1], v[2])); }
/// <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 }