决策树模型概述以及实例代码讲解

决策树模型概述

决策树是一种常见的机器学习模型,广泛用于分类和回归任务。其核心思想是通过一系列规则对数据进行拆分,从而达到预测目的。以下是决策树的基本概念和特性。

1. 基本结构

决策树由节点和分支构成,主要包括三种类型的节点:

  • 根节点:不依赖于任何特征条件,代表整个数据集的起点。
  • 内部节点:对应于特征的测试条件,根据测试结果将数据分流到不同的分支。
  • 叶节点(或决策节点):表示决策结果,每个叶节点都对应一个预测类别或回归值。
2. 构建过程

决策树的构建通常是一个递归过程,涉及以下几个步骤:

  • 选择最优特征:根据某种准则(如信息增益、基尼不纯度)从当前数据集中选择最优的特征进行分割。
  • 分割数据:根据选定的特征和其阈值,将数据分割为两个或多个子集。
  • 递归构建:对分割后的每个子集递归地重复上述过程,直到满足某个停止条件(如达到最大深度、节点中的数据量少于某个阈值、不再能显著增加信息增益等)。
3. 停止条件

决策树的构建过程需要明确的停止条件,常见的有:

  • 达到最大深度:预先定义树的最大深度。
  • 节点最小样本数:当节点中的样本数小于设定值时停止分割。
  • 纯度提升阈值:当进一步分割不能显著提升节点纯度时停止。
4. 优点与缺点

优点

  • 直观易懂:模型的决策过程清晰,易于解释。
  • 不需特征缩放:不像一些算法那样需要数据标准化或归一化。
  • 适用于特征间有交互作用的情况:能够捕捉特征之间的复杂关系。

缺点

  • 容易过拟合:特别是当树的深度非常大时,容易学习到数据中的噪声。
  • 不稳定性:小的数据变动可能导致生成完全不同的树。
  • 偏向于多数类:在类分布不平衡时,决策树可能偏向于多数类。

决策树可以独立使用,也经常作为其他复杂模型如随机森林和梯度提升树的基本构建块。通过集成方法,可以有效克服单一决策树的一些缺点,提高模型的泛化能力和稳定性。

决策树构建过程中的数据分割原理

1. 计算熵值(Entropy Calculation)

熵是衡量数据集随机性(或混乱度)的一个指标。在决策树中,熵用来衡量数据集中类别分布的均匀性。熵越高,数据集的混乱程度越大,类别分布越均匀;熵越低,数据集越有序,某一类别的占比越高。

2. 计算信息增益(Information Gain Calculation)

信息增益是衡量在特定条件下不确定性减少的量。在决策树中,它用于选择最佳的分割属性,即那个在其条件下将使得生成的子节点总体熵最小的属性。信息增益是父节点的熵与其所有子节点熵的加权和的差。

3. 选择最佳的特征和阈值进行数据分割(Choosing the Best Feature and Threshold for Splitting)

通过计算每个特征的所有可能的分割点的信息增益,选择信息增益最大的特征和对应的阈值作为分割点。这个步骤是决定树如何生长的关键,确保每次分割都尽可能提高子节点的纯度,使决策树对训练数据的拟合更加精确。

选择流程:

  • 对每个特征:
    • 对每个可能的阈值:
      • 分割数据为两个子集(左子节点和右子节点)。
      • 计算信息增益。
    • 选择产生最大信息增益的阈值。
  • 选择在所有特征中产生最大信息增益的特征和阈值作为最佳分割。

这些步骤共同作用,使得决策树能够有效地对数据进行分类或回归预测。通过这样的迭代分割,决策树逐渐增长并形成复杂的决策路径,以适应各种数据特征和结构。

基于随机森林实现鸢尾花分类中的树模型详解

初始化 (__init__)
def __init__(self, max_depth=None):
    self.max_depth = max_depth
  • 参数max_depth 是树的最大深度,如果为 None,则树可以无限制地增长。
  • 作用:初始化决策树对象,设置最大深度。
拟合模型(fit
def fit(self, X, y):
    self.n_classes_ = len(np.unique(y))
    self.n_features_ = X.shape[1]
    self.tree_ = self._grow_tree(X, y)
  • 作用:训练模型构建决策树。
  • 过程
    • 首先,计算数据的类别数 (n_classes_) 和特征数 (n_features_)。
    • 调用 _grow_tree 方法递归地构建决策树。
计算信息增益 (_info_gain)
def _entropy(self, y):
    """计算给定标签数组的熵。"""
    hist = np.bincount(y)
    ps = hist / np.sum(hist)
    return -np.sum([p * np.log2(p) for p in ps if p > 0])

def _info_gain(self, y, left_y, right_y):
    """计算信息增益"""
    parent_entropy = self._entropy(y)
    left_entropy = self._entropy(left_y)
    right_entropy = self._entropy(right_y)
    n = len(y)
    n_left = len(left_y)
    n_right = len(right_y)
    weighted_entropy = (n_left / n) * left_entropy + (n_right / n) * right_entropy
    return parent_entropy - weighted_entropy

  • 作用:计算信息增益,即父节点熵与加权子节点熵之差。
  • 熵计算:使用 _entropy 方法计算给定标签集的熵。
寻找最佳分割条件 (_best_criteria)
# 根据给定的特征和阈值分割数据集为左右子集。

def _split(self, feature, threshold):
    left_indices = np.where(feature <= threshold)[0]
    right_indices = np.where(feature > threshold)[0]
    return left_indices, right_indices

def _best_criteria(self, X, y, feature_indices):
    # X:特征数据集  y:目标变量  feature_indices:虑用于分割的特征索引列表
    
    best_gain = -np.inf    # 初始化最佳信息增益为负无穷大
    best_feature, best_threshold = None, None  # 最佳特征和阈值
    
    for feature in feature_indices:
        thresholds = np.unique(X[:, feature])
        if len(thresholds) == 0:
            continue #如果没有就跳过
        # 获取该特征所有可能的阈值(唯一值)
        for threshold in thresholds:
            left_indices, right_indices = self._split(X[:, feature], threshold)
            # 遍历每个特征的的每个阈值,使用_split函数根据当前阈值分割数据集,获取左子集和右子集的索引
            if len(left_indices) == 0 or len(right_indices) == 0:
                continue
                # 如果任一子集为空(即所有数据都在一个子集中),则跳过该阈值
            gain = self._info_gain(y, y[left_indices], y[right_indices])
            # 计算信息增益
            if gain > best_gain:
                best_gain = gain
                best_feature = feature
                best_threshold = threshold
    if best_feature is None:
        best_feature = np.random.choice(feature_indices)
        best_threshold = np.median(X[:, best_feature])
        # 如果遍历结束后没有找到任何有效的分割(即所有可能的分割都不增加信息量),则随机选择一个特征,并使用该特征的中位数作为阈值。
    return best_feature, best_threshold

  • 作用:找到最优的分割特征和阈值。
  • 算法:
    • 遍历候选特征,对每个特征计算所有可能阈值的信息增益。
    • 选择信息增益最大的特征和阈值作为最优分割条件。
递归构建树 (_grow_tree)
def _grow_tree(self, X, y, depth=0):
    # X: 数据集 y: 相应的标签数组 depth: 当前树的深度
    n_samples, n_features = X.shape
    n_labels = len(np.unique(y))
    
    # 终止条件
    if (self.max_depth is not None and depth >= self.max_depth) or n_labels == 1 or n_samples < 2:
        leaf_value = self._most_common_label(y)
        # 数据集中最频繁的标签
        return {'type': 'leaf', 'value': leaf_value}
    
    feature_indices = np.random.choice(n_features, int(np.sqrt(n_features)), replace=False)
    # 随机选择一部分特征进行分割,通常选择特征数的平方根。
    best_feature, best_threshold = self._best_criteria(X, y, feature_indices)
    # 寻找最佳分割特征和阈值
    
    left_indices, right_indices = self._split(X[:, best_feature], best_threshold)
    
    # 检查是否有空的子集
    if len(left_indices) == 0 or len(right_indices) == 0:
        leaf_value = self._most_common_label(y)
        return {'type': 'leaf', 'value': leaf_value}
    
    # 递归构建子树
    left_tree = self._grow_tree(X[left_indices, :], y[left_indices], depth + 1)
    right_tree = self._grow_tree(X[right_indices, :], y[right_indices], depth + 1)
    
    return {'type': 'split', 'feature': best_feature, 'threshold': best_threshold,
            'left': left_tree, 'right': right_tree}

  • 作用:递归构建决策树。
  • 终止条件:
    • 达到最大深度 (max_depth)。
    • 节点内的样本属于同一类别 (n_labels == 1)。
    • 样本数量小于2 (n_samples < 2)。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值