stackboost/core.py
def _build_tree(self, X: np.ndarray, y: np.ndarray, current_depth: int = 0) -> DecisionNode:
        """
        Recursive method which builds the decision tree and splits X and respective y
        on the feature of X which best separates the data

        :param X: training data
        :param y: target data
        :param current_depth: current depth of built tree
        :return:
        """

        largest_impurity = 0
        best_criteria = None  # Feature index and threshold
        best_sets = None  # Subsets of the data

        # Check if expansion of y is needed
        if len(np.shape(y)) == 1:
            y = np.expand_dims(y, axis=1)

        # Add y as last column of X
        Xy = np.concatenate((X, y), axis=1)

        n_samples, n_features = np.shape(X)

        if n_samples >= self.min_samples_split and current_depth <= self.max_depth:
            # Calculate the impurity for each feature
            for feature_i in range(n_features):
                # All values of feature_i

                feature_values = np.expand_dims(X[:, feature_i], axis=1)

                quintiles = self.sketch_algorithm(X=feature_values, n_quantiles=self.n_quintiles)

                # print(quintiles)
                for threshold in quintiles:
                    # Divide X and y depending on if the feature value of X at index feature_i
                    # meets the threshold
                    Xy1, Xy2 = divide_on_feature(Xy, feature_i, threshold)

                    if len(Xy1) > 0 and len(Xy2) > 0:
                        # Select the y-values of the two sets
                        y1 = Xy1[:, n_features:]
                        y2 = Xy2[:, n_features:]

                        # Calculate impurity
                        impurity = self._impurity_calculation(y, y1, y2) * self.sample_weight[feature_i]

                        # If this threshold resulted in a higher information gain than previously
                        # recorded save the threshold value and the feature
                        # index
                        if impurity > largest_impurity:
                            largest_impurity = impurity
                            best_criteria = {"feature_i": feature_i,
                                             "threshold": threshold,
                                             "target": y,
                                             "impurity": impurity,
                                             "depth": current_depth}
                            best_sets = {
                                "leftX": Xy1[:, :n_features],  # X of left subtree
                                "lefty": Xy1[:, n_features:],  # y of left subtree
                                "rightX": Xy2[:, :n_features],  # X of right subtree
                                "righty": Xy2[:, n_features:]  # y of right subtree
                            }
                            self.total_gain += impurity

        if largest_impurity > self.min_impurity:
            # Build subtrees for the right and left branches
            true_branch = self._build_tree(best_sets["leftX"], best_sets["lefty"], current_depth + 1)
            false_branch = self._build_tree(best_sets["rightX"], best_sets["righty"], current_depth + 1)
            self.n_nodes += 1
            return DecisionNode(
                feature_i=best_criteria["feature_i"],
                threshold=best_criteria["threshold"],
                true_branch=true_branch,
                false_branch=false_branch,
                target=best_criteria["target"],
                importance=(len(y) / self.n_samples) * best_criteria["impurity"],
                depth=best_criteria["depth"]
            )

        # We're at leaf => determine value
        leaf_value = self._leaf_value_calculation(y)

        return DecisionNode(value=leaf_value, target=y)

        Recursive method which builds the decision tree and splits X and respective y
        on the feature of X which best separates the data

        :param X: training data
        :param y: target data
        :param current_depth: current depth of built tree
        :return:
        
Recursive method which builds the decision tree and splits X and respective y
on the feature of X which best separates the data
Recursive method which builds the decision tree and splits X and respective y on the feature of X which best separates the data
def _build_tree(self, X: np.ndarray, y: np.ndarray, current_depth: int = 0) -> DecisionNode:
        largest_impurity = 0
        best_criteria = None  
        best_sets = None  
        if len(np.shape(y)) == 1:
            y = np.expand_dims(y, axis=1)
        Xy = np.concatenate((X, y), axis=1)
        n_samples, n_features = np.shape(X)
        if n_samples >= self.min_samples_split and current_depth <= self.max_depth:
            for feature_i in range(n_features):
                feature_values = np.expand_dims(X[:, feature_i], axis=1)
                quintiles = self.sketch_algorithm(X=feature_values, n_quantiles=self.n_quintiles)
                for threshold in quintiles:
                    Xy1, Xy2 = divide_on_feature(Xy, feature_i, threshold)
                    if len(Xy1) > 0 and len(Xy2) > 0:
                        y1 = Xy1[:, n_features:]
                        y2 = Xy2[:, n_features:]
                        impurity = self._impurity_calculation(y, y1, y2) * self.sample_weight[feature_i]
                        if impurity > largest_impurity:
                            largest_impurity = impurity
                            best_criteria = {"feature_i": feature_i,
                                             "threshold": threshold,
                                             "target": y,
                                             "impurity": impurity,
                                             "depth": current_depth}
                            best_sets = {
                                "leftX": Xy1[:, :n_features],  
                                "lefty": Xy1[:, n_features:],  
                                "rightX": Xy2[:, :n_features],  
                                "righty": Xy2[:, n_features:]  
                            }
                            self.total_gain += impurity
        if largest_impurity > self.min_impurity:
            true_branch = self._build_tree(best_sets["leftX"], best_sets["lefty"], current_depth + 1)
            false_branch = self._build_tree(best_sets["rightX"], best_sets["righty"], current_depth + 1)
            self.n_nodes += 1
            return DecisionNode(
                feature_i=best_criteria["feature_i"],
                threshold=best_criteria["threshold"],
                true_branch=true_branch,
                false_branch=false_branch,
                target=best_criteria["target"],
                importance=(len(y) / self.n_samples) * best_criteria["impurity"],
                depth=best_criteria["depth"]
            )
        leaf_value = self._leaf_value_calculation(y)
        return DecisionNode(value=leaf_value, target=y)
def _build_tree ( self , X : np . ndarray , y : np . ndarray , current_depth : int = 0 ) -> DecisionNode : largest_impurity = 0 best_criteria = None best_sets = None if len ( np . shape ( y ) ) == 1 : y = np . expand_dims ( y , axis = 1 ) Xy = np . concatenate ( ( X , y ) , axis = 1 ) n_samples , n_features = np . shape ( X ) if n_samples >= self . min_samples_split and current_depth <= self . max_depth : for feature_i in range ( n_features ) : feature_values = np . expand_dims ( X [ : , feature_i ] , axis = 1 ) quintiles = self . sketch_algorithm ( X = feature_values , n_quantiles = self . n_quintiles ) for threshold in quintiles : Xy1 , Xy2 = divide_on_feature ( Xy , feature_i , threshold ) if len ( Xy1 ) > 0 and len ( Xy2 ) > 0 : y1 = Xy1 [ : , n_features : ] y2 = Xy2 [ : , n_features : ] impurity = self . _impurity_calculation ( y , y1 , y2 ) * self . sample_weight [ feature_i ] if impurity > largest_impurity : largest_impurity = impurity best_criteria = { "feature_i" : feature_i , "threshold" : threshold , "target" : y , "impurity" : impurity , "depth" : current_depth } best_sets = { "leftX" : Xy1 [ : , : n_features ] , "lefty" : Xy1 [ : , n_features : ] , "rightX" : Xy2 [ : , : n_features ] , "righty" : Xy2 [ : , n_features : ] } self . total_gain += impurity if largest_impurity > self . min_impurity : true_branch = self . _build_tree ( best_sets [ "leftX" ] , best_sets [ "lefty" ] , current_depth + 1 ) false_branch = self . _build_tree ( best_sets [ "rightX" ] , best_sets [ "righty" ] , current_depth + 1 ) self . n_nodes += 1 return DecisionNode ( feature_i = best_criteria [ "feature_i" ] , threshold = best_criteria [ "threshold" ] , true_branch = true_branch , false_branch = false_branch , target = best_criteria [ "target" ] , importance = ( len ( y ) / self . n_samples ) * best_criteria [ "impurity" ] , depth = best_criteria [ "depth" ] ) leaf_value = self . _leaf_value_calculation ( y ) return DecisionNode ( value = leaf_value , target = y )
Recursive method which builds the decision tree and splits X and respective y
on the feature of X which best separates the data
Recursive method which builds the decision tree and splits X and respective y on the feature of X which best separates the data
"""
        Recursive method which builds the decision tree and splits X and respective y
        on the feature of X which best separates the data

        :param X: training data
        :param y: target data
        :param current_depth: current depth of built tree
        :return:
        """ # Feature index and threshold # Subsets of the data # Check if expansion of y is needed # Add y as last column of X # Calculate the impurity for each feature # All values of feature_i # print(quintiles) # Divide X and y depending on if the feature value of X at index feature_i # meets the threshold # Select the y-values of the two sets # Calculate impurity # If this threshold resulted in a higher information gain than previously # recorded save the threshold value and the feature # index # X of left subtree # y of left subtree # X of right subtree # y of right subtree # Build subtrees for the right and left branches # We're at leaf => determine value
None
self
X
np.ndarray
None
y
np.ndarray
None
current_depth
int
current depth of built tree
current depth of built tree