决策树算法

本文介绍了决策树的基本原理,包括其结构、节点表示和构建过程。重点讲解了如何通过信息增益和基尼指数选择最优特征进行划分,以及如何递归构建决策树以进行分类或回归预测。最后给出了一个Python决策树模型的实现示例。
摘要由CSDN通过智能技术生成

决策树原理

决策树是一种树形结构,其中每个节点代表一个特征或属性,每个分支代表一个决策结果,每个叶节点代表一个类别(在分类问题中)或一个数值(在回归问题中)。
决策树的构建过程可以形象地理解为:在每个节点,我们都会考察一个特征,根据这个特征的不同取值,我们选择一个分支继续往下走。这样一直走下去,直到到达一个叶节点,也就是决策结果。
例如,如果我们有一组水果数据,其中包括“外观”、“颜色”、“口感”等特征,我们想根据这些特征来预测水果是否甜美。我们可以构建一个决策树,其中每个节点都是一个特征,每个分支代表一个可能的决策结果(比如“甜”或“不甜”),每个叶节点就是最终的预测结果。
在构建决策树时,我们需要考虑如何选择最佳的特征来进行划分。通常,我们使用一些指标来评估特征划分的好坏,比如信息增益、基尼指数等。这些指标可以衡量划分后的子集的纯度(即每个子集中同类样本的比例)以及划分后的信息熵(即样本的不确定性)。
通过不断选择最优特征进行划分,我们可以构建出一棵最优的决策树,使得每个叶节点的数据尽可能同类聚集,不同类样本尽量分散。这样,我们就可以用这棵决策树来预测新的样本是属于哪个类别或哪个数值。

完整代码

import numpy as np


class DecisionTree:
    def __init__(self):
        self.tree = None

    def entropy(self, y):
        """
        计算信息熵。

        Parameters:
            y (numpy.ndarray): 输出变量,每个元素对应于相应样本的输出。

        Returns:
            float: 信息熵。
        """
        unique, counts = np.unique(y, return_counts=True)
        probabilities = counts / len(y)
        return -np.sum(probabilities * np.log2(probabilities))

    def information_gain(self, X, y, feature_index, threshold):
        """
        计算信息增益。

        Parameters:
            X (numpy.ndarray): 输入特征矩阵,每行代表一个样本,每列代表一个特征。
            y (numpy.ndarray): 输出变量,每个元素对应于相应样本的输出。
            feature_index (int): 特征的索引。
            threshold (float): 特征的阈值。

        Returns:
            float: 信息增益。
        """
        total_entropy = self.entropy(y)

        # 将数据根据特征和阈值划分为两个子集
        left_mask = X[:, feature_index] <= threshold
        right_mask = ~left_mask
        left_entropy = self.entropy(y[left_mask])
        right_entropy = self.entropy(y[right_mask])

        # 计算加权平均的信息熵
        subset_entropy = (len(y[left_mask]) / len(y)) * left_entropy + (len(y[right_mask]) / len(y)) * right_entropy

        return total_entropy - subset_entropy

    def find_best_split(self, X, y):
        """
        寻找最佳的切分特征和阈值。

        Parameters:
            X (numpy.ndarray): 输入特征矩阵,每行代表一个样本,每列代表一个特征。
            y (numpy.ndarray): 输出变量,每个元素对应于相应样本的输出。

        Returns:
            tuple: 包含最佳切分特征的索引和最佳阈值。
        """
        best_feature_index = None
        best_threshold = None
        max_information_gain = -1

        for feature_index in range(X.shape[1]):
            unique_values = np.unique(X[:, feature_index])
            thresholds = (unique_values[:-1] + unique_values[1:]) / 2

            for threshold in thresholds:
                information_gain = self.information_gain(X, y, feature_index, threshold)
                if information_gain > max_information_gain:
                    max_information_gain = information_gain
                    best_feature_index = feature_index
                    best_threshold = threshold

        return best_feature_index, best_threshold

    def build_tree(self, X, y, depth=0, max_depth=None):
        """
        递归地构建决策树。

        Parameters:
            X (numpy.ndarray): 输入特征矩阵,每行代表一个样本,每列代表一个特征。
            y (numpy.ndarray): 输出变量,每个元素对应于相应样本的输出。
            depth (int): 当前节点的深度。
            max_depth (int): 树的最大深度。

        Returns:
            dict: 决策树的节点信息。
        """
        unique, counts = np.unique(y, return_counts=True)
        majority_class = unique[np.argmax(counts)]

        # 如果样本纯净或达到最大深度,则创建叶节点
        if len(unique) == 1 or (max_depth is not None and depth == max_depth):
            return {'class': majority_class, 'depth': depth}

        # 寻找最佳的切分特征和阈值
        best_feature_index, best_threshold = self.find_best_split(X, y)

        # 如果无法找到切分点,则创建叶节点
        if best_feature_index is None:
            return {'class': majority_class, 'depth': depth}

        # 根据最佳切分特征和阈值划分数据
        left_mask = X[:, best_feature_index] <= best_threshold
        right_mask = ~left_mask

        # 递归地构建左右子树
        left_subtree = self.build_tree(X[left_mask], y[left_mask], depth + 1, max_depth)
        right_subtree = self.build_tree(X[right_mask], y[right_mask], depth + 1, max_depth)

        return {
            'feature_index': best_feature_index,
            'threshold': best_threshold,
            'left': left_subtree,
            'right': right_subtree,
            'depth': depth
        }

    def fit(self, X, y, max_depth=None):
        """
        训练决策树模型。

        Parameters:
            X (numpy.ndarray): 输入特征矩阵,每行代表一个样本,每列代表一个特征。
            y (numpy.ndarray): 输出变量,每个元素对应于相应样本的输出。
            max_depth (int): 树的最大深度。

        Returns:
            None
        """
        self.tree = self.build_tree(X, y, max_depth=max_depth)

    def predict_single(self, x, node):
        """
        预测单个样本的类别。

        Parameters:
            x (numpy.ndarray): 单个样本的特征。
            node (dict): 决策树节点信息。

        Returns:
            int: 预测的类别。
        """
        if 'class' in node:
            return node['class']

        if x[node['feature_index']] <= node['threshold']:
            return self.predict_single(x, node['left'])
        else:
            return self.predict_single(x, node['right'])

    def predict(self, X):
        """
        预测多个样本的类别。

        Parameters:
            X (numpy.ndarray): 输入特征矩阵,每行代表一个样本,每列代表一个特征。

        Returns:
            numpy.ndarray: 预测的类别。
        """
        return np.array([self.predict_single(x, self.tree) for x in X])


# 示例用法
if __name__ == "__main__":
    # 准备数据
    X_train = np.array([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]])
    y_train = np.array([0, 0, 1, 1, 1])

    # 创建决策树模型
    model = DecisionTree()

    # 训练模型
    model.fit(X_train, y_train)

    # 预测新数据
    X_new = np.array([[3, 3]])
    predictions = model.predict(X_new)
    print(f'预测类别:{predictions}')
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顽强卖力

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值