# Path: mla/ensemble/base.py
# def split(X, y, value):
#     left_mask = X < value
#     right_mask = X >= value
#     return y[left_mask], y[right_mask]
# 
# def split_dataset(X, target, column, value, return_X=True):
#     left_mask, right_mask = get_split_mask(X, column, value)
# 
#     left, right = {}, {}
#     for key in target.keys():
#         left[key] = target[key][left_mask]
#         right[key] = target[key][right_mask]
# 
#     if return_X:
#         left_X, right_X = X[left_mask], X[right_mask]
#         return left_X, right_X, left, right
#     else:
#         return left, right
# 
# def xgb_criterion(y, left, right, loss):
#     left = loss.gain(left["actual"], left["y_pred"])
#     right = loss.gain(right["actual"], right["y_pred"])
#     initial = loss.gain(y["actual"], y["y_pred"])
#     gain = left + right - initial
#     return gain


import random
import numpy as np
from scipy import stats
from mla.ensemble.base import split, split_dataset, xgb_criterion

    @property
    def is_terminal(self):
        return not bool(self.left_child and self.right_child)

    def _find_splits(self, X):
        """Find all possible split values."""
        split_values = set()

        # Get unique values in a sorted order
        x_unique = list(np.unique(X))
        for i in range(1, len(x_unique)):
            # Find a point between two values
            average = (x_unique[i - 1] + x_unique[i]) / 2.0
            split_values.add(average)

        return list(split_values)

    def _find_best_split(self, X, target, n_features):
        """Find best feature and value for a split. Greedy algorithm."""

        # Sample random subset of features
        subset = random.sample(list(range(0, X.shape[1])), n_features)
        max_gain, max_col, max_val = None, None, None

        for column in subset:
            split_values = self._find_splits(X[:, column])
            for value in split_values:
                if self.loss is None:
                    # Random forest

# Path: mla/ensemble/base.py
# def split(X, y, value):
#     left_mask = X < value
#     right_mask = X >= value
#     return y[left_mask], y[right_mask]
# 
# def split_dataset(X, target, column, value, return_X=True):
#     left_mask, right_mask = get_split_mask(X, column, value)
# 
#     left, right = {}, {}
#     for key in target.keys():
#         left[key] = target[key][left_mask]
#         right[key] = target[key][right_mask]
# 
#     if return_X:
#         left_X, right_X = X[left_mask], X[right_mask]
#         return left_X, right_X, left, right
#     else:
#         return left, right
# 
# def xgb_criterion(y, left, right, loss):
#     left = loss.gain(left["actual"], left["y_pred"])
#     right = loss.gain(right["actual"], right["y_pred"])
#     initial = loss.gain(y["actual"], y["y_pred"])
#     gain = left + right - initial
#     return gain


# Path: mla/ensemble/tree.py
import random
import numpy as np
from scipy import stats
from mla.ensemble.base import split, split_dataset, xgb_criterion


    @property
    def is_terminal(self):
        return not bool(self.left_child and self.right_child)

    def _find_splits(self, X):
        """Find all possible split values."""
        split_values = set()

        # Get unique values in a sorted order
        x_unique = list(np.unique(X))
        for i in range(1, len(x_unique)):
            # Find a point between two values
            average = (x_unique[i - 1] + x_unique[i]) / 2.0
            split_values.add(average)

        return list(split_values)

    def _find_best_split(self, X, target, n_features):
        """Find best feature and value for a split. Greedy algorithm."""

        # Sample random subset of features
        subset = random.sample(list(range(0, X.shape[1])), n_features)
        max_gain, max_col, max_val = None, None, None

        for column in subset:
            split_values = self._find_splits(X[:, column])
            for value in split_values:
                if self.loss is None:
                    # Random forest

                    splits = split(X[:, column], target["y"], value)