统计学习方法学习总结(四):决策树

概念 

分类决策树模型是一种描述对实例进行分类的树形结构。 决策树由结点(node)  和有向边(directed edge)组成。结点有两种类型:内部结 (internal     node) 和叶结(leaf       node)内部结点表示一个特征或属性,叶结点表 示一个类。

用决策树分类,从根结点开始,对实例的某一特征进行测试,根据测试结果,将实 例分配到其子结点;这时,每一个子结点对应着该特征的一个取值。如此递归地对实 例进行测试并分配,直至达到叶结点。最后将实例分到叶结点的类中。

决策树中的学习

 

 

至于决策树的应用领域,它们非常广泛,包括但不限于:

  • 医疗诊断:根据病人的症状和检验结果来诊断疾病。
  • 金融分析:评估贷款申请者的信用风险或预测股票市场。
  • 客户关系管理:根据客户的历史数据预测其未来的购买行为或流失可能性。
  • 故障诊断:在制造业或技术支持中用于诊断设备或系统的故障。
  • 推荐系统:在电子商务中用于根据用户的历史购买和浏览行为推荐产品。

决策树学习过程的基本步骤:

  1. 选择最佳分割属性:在训练的初始阶段,算法会评估数据集中的每个特征,以确定哪个特征最适合作为树的根节点。这通常是通过计算信息增益(Information Gain)、信息增益比(Gain Ratio)或基尼不纯度(Gini Impurity)等标准来实现的。这个特征将被用来分割数据集,形成树的第一个决策点。

  2. 分割数据集:根据选择的特征,数据集被分割成子集。每个子集包含在该特征上具有相同值的数据点。例如,如果选择的特征是“年龄”,则数据可能根据年龄分为“少年”、“青年”、“中年”、“老年”等子集。

  3. 递归构建子树:对每个子集重复上述过程,选择最佳分割属性,然后继续分割。这个递归过程会持续进行,直到满足特定的停止条件,例如达到预定的树深度、节点中数据点的数量小于某个阈值,或者所有数据点都属于同一个类别。

  4. 剪枝:为了防止过拟合(即模型在训练数据上表现很好,但在新数据上表现不佳),通常会对决策树进行剪枝。剪枝可以在树构建过程中(预剪枝)或构建后(后剪枝)进行。它涉及到移除部分子树或叶节点,以简化模型。

  5. 评估和使用:一旦决策树被构建,它可以用来对新的数据实例进行分类或回归预测。评估其性能通常涉及到使用独立的测试数据集,以检验模型的泛化能力。

决策树的特征选择

决策树的特征选择是一个关键步骤,它决定了如何从数据中选择最佳特征来分割节点。主要的特征选择方法有三种:信息增益(Information Gain)、增益率(Gain Ratio)和基尼指数(Gini Index)。 

1. 信息增益(Information Gain)

信息增益是决策树中最常用的特征选择方法,特别是在ID3算法中。它是基于熵的概念,熵是度量数据集中随机性或不确定性的指标。

熵的定义

 

 其中,H(S) 是集合 S 的熵,pi​ 是该集合中第 i 类结果的概率。
信息增益的计算

其中,IG(S,A) 是特征 A 对集合S 的信息增益,T 是特征 A 的所有可能值,St​ 是特征 A 的值为 t 时的子集,∣St​∣ 和 ∣S∣ 分别是子集和原始集合的大小。

用一个简单的例子来解释信息增益的计算过程。假设我们有一个小型数据集,它描述了一些动物是否属于哺乳类。我们的目标是决定“体型”和“有无毛发”这两个特征中哪一个更适合作为决策树的根节点。

数据集如下:

动物体型有无毛发哺乳类
动物1
动物2
动物3
动物4
动物5

首先,我们需要计算整个数据集的熵。在这个例子中,有3个哺乳类和2个非哺乳类。

  • 整个数据集的熵

让我们来计算这个值。

整个数据集的熵 H(S) 约为 0.971。

接下来,我们将分别计算基于“体型”和“有无毛发”这两个特征的信息增益。

1. 以“体型”为特征的信息增益

“体型”这个特征有三个值:大、中、小。我们需要计算每个子集的熵,然后计算信息增益。

  • 体型为大的子集熵:

    • 包含两个样本,一个是哺乳类(动物1),一个不是哺乳类(动物5)。
    • H(体型=大)=−(p哺乳类​log2​(p哺乳类​)+p非哺乳类​log2​(p非哺乳类​))
  • 体型为中的子集熵:

    • 只包含一个样本,是哺乳类(动物3)。
    • H(体型=中)=0 (因为没有不确定性)
  • 体型为小的子集熵:

    • 包含两个样本,一个是哺乳类(动物4),一个不是哺乳类(动物2)。
    • H(体型=小)=−(p哺乳类​log2​(p哺乳类​)+p非哺乳类​log2​(p非哺乳类​))

然后,我们将计算“体型”这个特征的整体熵,最后计算信息增益。

2. 以“有无毛发”为特征的信息增益

这个过程类似,但是我们只有两个子集:“有毛发”和“无毛发”。

让我们先计算基于“体型”特征的信息增益。

# 计算基于“体型”特征的信息增益

# 体型为大的子集熵
p_哺乳类_大 = 1 / 2
p_非哺乳类_大 = 1 / 2
H_体型大 = -(p_哺乳类_大 * math.log2(p_哺乳类_大) + p_非哺乳类_大 * math.log2(p_非哺乳类_大))

# 体型为中的子集熵(只有一个哺乳类,所以熵为0)
H_体型中 = 0

# 体型为小的子集熵
p_哺乳类_小 = 1 / 2
p_非哺乳类_小 = 1 / 2
H_体型小 = -(p_哺乳类_小 * math.log2(p_哺乳类_小) + p_非哺乳类_小 * math.log2(p_非哺乳类_小))

# 体型特征的整体熵
H_体型 = (2 / 5) * H_体型大 + (1 / 5) * H_体型中 + (2 / 5) * H_体型小

# 信息增益
IG_体型 = H_S - H_体型
IG_体型

​​

基于“体型”特征的信息增益 体型IG体型​ 约为 0.171。

现在,我们将计算基于“有无毛发”特征的信息增益。过程与之前相似,只是我们需要考虑的子集是“有毛发”和“无毛发”。

  • 有毛发的子集熵:

    • 包含三个样本,两个是哺乳类(动物1、动物3和动物4),一个不是哺乳类(动物2)。
    • H(有毛发)=−(p哺乳类​log2​(p哺乳类​)+p非哺乳类​log2​(p非哺乳类​))
  • 无毛发的子集熵:

    • 包含两个样本,都不是哺乳类(动物5)。
    • H(无毛发)=0 (因为没有不确定性)

然后,我们将计算“有无毛发”这个特征的整体熵,最后计算信息增益。让我们来计算这个值。

# 计算基于“有无毛发”特征的信息增益

# 有毛发的子集熵
p_哺乳类_有毛发 = 3 / 4
p_非哺乳类_有毛发 = 1 / 4
H_有毛发 = -(p_哺乳类_有毛发 * math.log2(p_哺乳类_有毛发) + p_非哺乳类_有毛发 * math.log2(p_非哺乳类_有毛发))

# 无毛发的子集熵(只有非哺乳类,所以熵为0)
H_无毛发 = 0

# 有无毛发特征的整体熵
H_有无毛发 = (3 / 5) * H_有毛发 + (2 / 5) * H_无毛发

# 信息增益
IG_有无毛发 = H_S - H_有无毛发
IG_有无毛发

​​

基于“有无毛发”特征的信息增益有无毛发IG有无毛发​ 约为 0.484。

比较两个特征的信息增益,我们发现 体型IG有无毛发​>IG体型​,这意味着“有无毛发”这个特征比“体型”更适合用来作为决策树的根节点。因为“有无毛发”在区分哺乳类和非哺乳类方面提供了更多的信息。在实际的决策树构建过程中,我们会选择具有最高信息增益的特征来分割节点。 ​

2. 信息增益比(Gain Ratio)

增益率是对信息增益的一种改进,特别是在C4.5算法中使用。它解决了信息增益偏向于选择具有更多值的特征的问题。

  • 分裂信息的定义wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==编辑

  • 增益比

  • 的计算: 

3. 基尼指数(Gini Index)

基尼指数是另一种常用的特征选择方法,特别是在CART(Classification and Regression Trees)算法中。它是度量数据集的不纯度的指标。

决策树的剪枝

决策树的剪枝是一种减少决策树复杂度、防止过拟合的技术。过拟合是指模型在训练数据上表现很好,但在未见过的数据上表现不佳的情况。剪枝通过减少决策树的大小来提高模型的泛化能力。

决策树剪枝分为两种:预剪枝(Pre-pruning)和后剪枝(Post-pruning)。

预剪枝(Pre-pruning)

预剪枝是在决策树完全生成之前停止树的生长。方法包括:

  1. 限制树的深度:设置树的最大深度。
  2. 限制节点的最小样本数:如果一个节点的样本数少于阈值,就不再继续分割。
  3. 信息增益阈值:如果一个分割的信息增益小于某个阈值,则停止分割。
  4. 验证数据集的性能监控:使用验证集来监控模型性能。如果模型在验证集上的表现不再改善,则停止生长。

预剪枝简单易行,但可能会导致欠拟合,即模型在训练数据上也没有很好的表现。

后剪枝(Post-pruning)

后剪枝是在决策树完全生成后进行的。它通常比预剪枝更能提高模型的泛化能力。方法包括:

  1. 剪除测试:使用独立的验证集来测试剪除某些分支后模型的性能。如果剪除后性能提高或保持不变,则进行剪枝。
  2. 最小错误剪枝:考虑节点的错误率,如果合并子节点后整体错误率降低或保持不变,则合并。
  3. 代价复杂性剪枝:在树的复杂度和预测误差之间寻找最佳平衡。这种方法考虑了树的大小和其性能,寻找最优的剪枝策略。

后剪枝过程更加复杂,计算成本也更高,但通常能获得更好的结果。

 

决策树的算法

1. ID3(Iterative Dichotomiser 3)

  • 特点:ID3是最早的决策树算法之一,由Ross Quinlan在1986年提出。
  • 核心:使用信息增益作为标准来选择分割数据集的特征。
  • 限制:只能处理分类问题,不能直接处理数值型数据和缺失数据。
import numpy as np
import pandas as pd
from collections import Counter

def calculate_entropy(y):
    """
    计算熵
    y: 数据集中的目标变量
    """
    # 统计每个类别的频率
    counts = Counter(y)
    probabilities = [count / len(y) for count in counts.values()]

    # 计算熵
    entropy = -np.sum([p * np.log2(p) for p in probabilities])
    return entropy


def calculate_information_gain(X, y, feature):
    """
    计算信息增益
    X: 数据集
    y: 目标变量
    feature: 要计算信息增益的特征
    """
    # 计算初始熵
    entropy_before = calculate_entropy(y)

    # 按照特征分割数据集
    values = set(X[feature])
    entropy_after = 0
    for value in values:
        y_subset = y[X[feature] == value]
        entropy_after += calculate_entropy(y_subset) * len(y_subset) / len(y)

    # 计算信息增益
    information_gain = entropy_before - entropy_after
    return information_gain


def id3(X, y, features):
    """
       ID3算法的实现
       X: 数据集
       y: 目标变量
       features: 特征列表
    """
    # 如果所有实例都属于同一个类别,则直接返回该类别
    if len(set(y)) == 1:
        return y.iloc[0]  # 修改此处,适用于pandas.Series

    # 如果没有特征可以用来进一步分割数据,返回最多的类别
    if len(features) == 0:
        return Counter(y).most_common(1)[0][0]

    # 计算每个特征的信息增益
    gains = [calculate_information_gain(X, y, feature) for feature in features]

    # 选择信息增益最大的特征
    max_gain_feature = features[np.argmax(gains)]

    # 创建决策树节点
    tree = {max_gain_feature: {}}

    # 移除已选择的特征
    features = [i for i in features if i != max_gain_feature]

    # 递归地构建决策树
    for value in set(X[max_gain_feature]):
        subset_X = X[X[max_gain_feature] == value]
        subset_y = y[X[max_gain_feature] == value]

        # 在这里可以添加剪枝逻辑,例如限制树的深度或节点最小样本数

        tree[max_gain_feature][value] = id3(subset_X, subset_y, features)

    return tree


# 示例数据
data = {
    'Outlook': ['Sunny', 'Sunny', 'Overcast', 'Rain', 'Rain', 'Rain', 'Overcast', 'Sunny', 'Sunny', 'Rain'],
    'Temperature': ['Hot', 'Hot', 'Hot', 'Mild', 'Cool', 'Cool', 'Cool', 'Mild', 'Cool', 'Mild'],
    'Humidity': ['High', 'High', 'High', 'High', 'Normal', 'Normal', 'Normal', 'High', 'Normal', 'Normal'],
    'Wind': ['Weak', 'Strong', 'Weak', 'Weak', 'Weak', 'Strong', 'Strong', 'Weak', 'Weak', 'Weak'],
    'PlayTennis': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes']
}
df = pd.DataFrame(data)

# 构建决策树
tree = id3(df, df['PlayTennis'], list(df.columns[:-1]))
print(tree)

2. C4.5

  • 特点:C4.5是ID3的后继者,也是由Ross Quinlan开发。
  • 核心:引入了增益率(Gain Ratio)来选择特征,以解决ID3倾向于选择拥有更多值的特征的问题。
  • 改进:能够处理连续型数据和缺失数据,支持对生成的树进行剪枝。

3. CART(Classification and Regression Trees)

  • 特点:由Breiman等人于1984年提出,用于分类和回归任务。
  • 核心:使用基尼不纯度(Gini Index)来选择特征。
  • 特性:生成的是二叉树,每个节点只产生两个子节点,适用于更广泛的数据类型。
  • import numpy as np
    import pandas as pd
    from collections import Counter
    
    def calculate_gini(y):
        """
        计算给定数据集的基尼不纯度
        y: 目标变量
        """
        if len(y) == 0:
            return 0
        else:
            counts = Counter(y)
            probabilities = [count / len(y) for count in counts.values()]
            gini = 1 - sum([p**2 for p in probabilities])
            return gini
    
    def calculate_gini_impurity(X, y, feature):
        """
        计算基于特定特征的基尼不纯度
        X: 数据集
        y: 目标变量
        feature: 特征
        """
        unique_values = set(X[feature])
        weighted_gini = 0
        for value in unique_values:
            subset_y = y[X[feature] == value]
            gini = calculate_gini(subset_y)
            weighted_gini += gini * len(subset_y) / len(y)
        return weighted_gini
    
    def cart(X, y, features):
        """
        CART算法的实现
        X: 数据集
        y: 目标变量
        features: 特征列表
        """
        # 如果所有实例都属于同一个类别,返回该类别
        if len(set(y)) == 1:
            return y.iloc[0]
    
        # 如果没有特征可以分割,返回最多的类别
        if len(features) == 0:
            return Counter(y).most_common(1)[0][0]
    
        # 计算每个特征的基尼不纯度
        gini_impurities = [calculate_gini_impurity(X, y, feature) for feature in features]
    
        # 选择基尼不纯度最小的特征
        best_feature = features[np.argmin(gini_impurities)]
    
        # 创建决策树节点
        tree = {best_feature: {}}
    
        # 移除已选择的特征
        features = [i for i in features if i != best_feature]
    
        # 递归地构建决策树
        for value in set(X[best_feature]):
            subset_X = X[X[best_feature] == value]
            subset_y = y[X[best_feature] == value]
            tree[best_feature][value] = cart(subset_X, subset_y, features)
    
        return tree
    
    # 示例数据
    data = {
        'Outlook': ['Sunny', 'Sunny', 'Overcast', 'Rain', 'Rain', 'Rain', 'Overcast', 'Sunny', 'Sunny', 'Rain'],
        'Temperature': ['Hot', 'Hot', 'Hot', 'Mild', 'Cool', 'Cool', 'Cool', 'Mild', 'Cool', 'Mild'],
        'Humidity': ['High', 'High', 'High', 'High', 'Normal', 'Normal', 'Normal', 'High', 'Normal', 'Normal'],
        'Wind': ['Weak', 'Strong', 'Weak', 'Weak', 'Weak', 'Strong', 'Strong', 'Weak', 'Weak', 'Weak'],
        'PlayTennis': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes']
    }
    df = pd.DataFrame(data)
    
    # 构建CART决策树
    tree = cart(df, df['PlayTennis'], list(df.columns[:-1]))
    print(tree)
    

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值