云计算百科
云计算领域专业知识百科平台

第21课:scikit-learn|决策树分类原理、基尼系数、信息熵与剪枝策略

在这里插入图片描述

文章目录

    • 课前导读
    • 学习目标
    • 知识点理论讲解
      • 一、决策树的基本概念
      • 二、分裂准则:如何选择最佳特征?
        • 1. 基尼系数(Gini Impurity)
        • 2. 信息熵(Information Entropy)
        • 3. 信息增益
      • 三、决策树的停止条件与剪枝
      • 四、决策树的优缺点
    • 核心原理通俗拆解
      • 决策树:20个问题游戏
      • 基尼系数 vs 信息熵
    • 底层数学逻辑
      • 1. 二分类情况下的基尼系数
      • 2. 信息增益的计算示例
      • 3. 代价复杂度剪枝
    • scikit-learn API详解
      • DecisionTreeClassifier
    • 环境配置与依赖安装
    • 完整代码实战(带详细注释)
      • 实战1:决策树基础——鸢尾花分类与可视化
      • 实战2:基尼系数 vs 信息熵对比
      • 实战3:预剪枝参数对过拟合的影响
      • 实战4:特征重要性分析
      • 实战5:后剪枝——代价复杂度剪枝(CCP)
      • 实战6:多参数网格搜索(预剪枝 + 后剪枝)
      • 实战7:决策树回归(DecisionTreeRegressor)
    • 案例实操演示
      • 案例:信用卡违约预测(决策树二分类)
    • 常见报错与避坑指南
      • 报错1:`ValueError: min_samples_split must be an integer`
      • 报错2:树太大,`plot_tree` 显示模糊
      • 报错3:特征重要性全为零或某些特征重要性异常
      • 报错4:`RuntimeError: Tree is too large` 在可视化时
      • 避坑总结
    • 知识点总结
      • 原理
      • API
      • 可视化与解释
      • 扩展
    • 课后练习题
      • 选择题
      • 填空题
      • 实操题
      • 思考题
  • 🔗《30节课 scikit-learn 从入门到精通》系列课程导航

课前导读

欢迎来到第21课!如果你问“最像人类决策过程的机器学习算法是什么”,答案一定是决策树。想象医生诊断病情:体温超过38°C吗?咳嗽吗?血常规白细胞高吗?每次回答“是/否”就沿着树往下走,最终到达一个结论(流感、普通感冒或其他)。决策树就是模仿这一过程——从根节点开始,每个内部节点是一个特征上的测试(如“年龄<30?”),每个分支是测试结果,叶子节点是类别标签。

决策树的优点是天然可解释,不需要“黑箱”,你可以直观地看到为什么某个样本被分类到某一类。本课将详细讲解决策树的构建核心:如何选择最佳分裂特征?常用的衡量标准有基尼系数和信息熵,两者都能评估子节点的“纯度”。你还会学到如何通过限制树的高度、节点最少样本数等参数进行预剪枝,以及通过后剪枝(ccp_alpha)进一步压缩树的结构,防止过拟合。通过可视化决策树和提取特征重要性,你将能向业务人员清晰地解释模型决策过程。

学习目标

完成本课学习后,你将能够:

  • 解释 决策树的构建过程:从根节点开始,递归选择最佳特征分裂,直至满足停止条件
  • 理解 基尼系数和信息熵的数学定义及其作为分裂准则的作用
  • 使用 DecisionTreeClassifier 进行训练、预测和评估
  • 掌握 关键参数:criterion(‘gini’/‘entropy’)、max_depth、min_samples_split、min_samples_leaf、max_features、ccp_alpha
  • 可视化 决策树结构(plot_tree 或 export_graphviz)
  • 提取 特征重要性,分析哪些特征对分类贡献最大
  • 实施 预剪枝和后剪枝(代价复杂度剪枝)来防止过拟合
  • 知识点理论讲解

    一、决策树的基本概念

    决策树是一种树形结构的分类模型,由以下元素组成:

    • 根节点:包含全部样本,是分裂的起点。
    • 内部节点:对应一个特征上的测试(如 X[2] <= 1.5)。
    • 分支:测试结果的输出(如“是/否”或多种取值)。
    • 叶子节点:最终分类结果(类别标签)。

    构建决策树的过程是一个递归划分过程:每次选择一个特征和阈值,将当前节点样本集划分为两个(或多个)子集,使得子集中的样本“纯度”尽可能高。当子集已经纯净(全部同一类)或满足停止条件时,停止划分。

    二、分裂准则:如何选择最佳特征?

    分裂的目标是让划分后的子节点“最纯”,即包含尽可能多同一类别的样本。衡量纯度的指标有:

    1. 基尼系数(Gini Impurity)

    衡量一个节点中随机抽取两个样本类别不一致的概率。节点

    t

    t

    t 的基尼系数为:

    G

    i

    n

    i

    (

    t

    )

    =

    1

    k

    =

    1

    K

    p

    t

    k

    2

    Gini(t) = 1 – \\sum_{k=1}^{K} p_{tk}^2

    Gini(t)=1k=1Kptk2

    其中

    p

    t

    k

    p_{tk}

    ptk 是节点

    t

    t

    t 中第

    k

    k

    k 类样本的比例。基尼系数越小,节点越纯(当所有样本属于同一类时,Gini=0)。

    对于二分类,

    G

    i

    n

    i

    =

    1

    (

    p

    2

    +

    (

    1

    p

    )

    2

    )

    =

    2

    p

    (

    1

    p

    )

    Gini = 1 – (p^2 + (1-p)^2) = 2p(1-p)

    Gini=1(p2+(1p)2)=2p(1p),最大值在 p=0.5 时为 0.5。

    2. 信息熵(Information Entropy)

    熵也度量不确定性:

    E

    n

    t

    r

    o

    p

    y

    (

    t

    )

    =

    k

    =

    1

    K

    p

    t

    k

    log

    2

    p

    t

    k

    Entropy(t) = -\\sum_{k=1}^{K} p_{tk} \\log_2 p_{tk}

    Entropy(t)=k=1Kptklog2ptk

    当节点纯时,熵=0;当各类等比例时,熵最大(二分类时最大为1)。

    3. 信息增益

    选择分裂特征时,我们计算分裂前的熵(或基尼)与分裂后子节点熵的加权平均值之间的差异,即信息增益:

    I

    G

    =

    E

    n

    t

    r

    o

    p

    y

    (

    p

    a

    r

    e

    n

    t

    )

    j

    n

    j

    n

    E

    n

    t

    r

    o

    p

    y

    (

    c

    h

    i

    l

    d

    j

    )

    IG = Entropy(parent) – \\sum_{j} \\frac{n_j}{n} Entropy(child_j)

    IG=Entropy(parent)jnnjEntropy(childj)

    选择使信息增益最大的特征。

    在 scikit-learn 中,criterion='gini' 使用基尼系数,criterion='entropy' 使用信息熵。通常两者差异不大,基尼系数计算稍快,信息熵对分布更敏感。

    三、决策树的停止条件与剪枝

    如果不加限制,决策树会一直分裂直到每个叶子节点都是纯的,这会导致过拟合——模型在训练集上完美分类,但在测试集上表现差。

    预剪枝:在构建过程中提前停止分裂,例如:

    • max_depth:限制树的最大深度。
    • min_samples_split:节点至少包含多少样本才分裂。
    • min_samples_leaf:叶子节点最少样本数。
    • min_impurity_decrease:分裂带来的纯度提升至少达到阈值。

    后剪枝:先让树充分生长,然后自底向上剪去不重要的分支。scikit-learn 提供代价复杂度剪枝(Cost Complexity Pruning, CCP),通过参数 ccp_alpha 控制剪枝强度。ccp_alpha 越大,剪枝越强,树越小。

    四、决策树的优缺点

    优点缺点
    易于理解和解释,可可视化 容易过拟合(需剪枝)
    不需要特征缩放(树模型对尺度不敏感) 对数据微小变化敏感(方差大)
    可处理数值和类别特征 可能产生有偏树(当某些特征取值多时)
    隐式进行特征选择 学习能力有限(不如集成模型)
    可输出特征重要性 外推能力差(不能预测超出训练集范围的值)

    核心原理通俗拆解

    决策树:20个问题游戏

    想象你在玩“20个问题”游戏:心里想一个动物,对方通过问“是/否”问题来猜。例如“它是否生活在水中?”、“是否有羽毛?”、“是否吃肉?”。每次问题都将可能性空间一分为二,直到锁定答案。决策树就是这种提问策略的数学化:选择哪个问题先问(根节点)能使不确定性降低最快,这就是信息增益。

    基尼系数 vs 信息熵

    基尼系数可以理解为“错误分类的风险”。如果节点中80%是猫,20%是狗,那么随机猜一个是猫的错误概率是20%(假设猜多数类)。基尼系数稍微复杂些,但核心思想类似。信息熵则来自于信息论,衡量“不确定性”,两者在大多数情况下表现相似。

    底层数学逻辑

    1. 二分类情况下的基尼系数

    设节点中正例比例

    p

    p

    p,负例比例

    1

    p

    1-p

    1p

    G

    i

    n

    i

    =

    1

    (

    p

    2

    +

    (

    1

    p

    )

    2

    )

    =

    2

    p

    (

    1

    p

    )

    Gini = 1 – (p^2 + (1-p)^2) = 2p(1-p)

    Gini=1(p2+(1p)2)=2p(1p)

    p

    =

    0

    p=0

    p=0

    p

    =

    1

    p=1

    p=1 时,Gini=0;

    p

    =

    0.5

    p=0.5

    p=0.5 时,Gini=0.5。

    2. 信息增益的计算示例

    假设父节点有10个正例、10个负例,熵 = -0.5log₂0.5 -0.5log₂0.5 = 1。按特征A分成两个子节点:左子节点5正1负(熵= -5/6 log₂5/6 -1/6 log₂1/6 ≈ 0.65),右子节点5正9负(熵 ≈ 0.94)。加权平均熵 = (6/20)*0.65 + (14/20)*0.94 ≈ 0.85。信息增益 = 1 – 0.85 = 0.15。

    3. 代价复杂度剪枝

    CCP 定义子树的代价复杂度为

    R

    α

    (

    T

    )

    =

    R

    (

    T

    )

    +

    α

    T

    ~

    R_\\alpha(T) = R(T) + \\alpha |\\tilde{T}|

    Rα(T)=R(T)+αT~,其中

    R

    (

    T

    )

    R(T)

    R(T) 是树在训练集上的误差(如基尼不纯度),

    T

    ~

    |\\tilde{T}|

    T~ 是叶子节点数,

    α

    \\alpha

    α 是惩罚系数。对于每个

    α

    \\alpha

    α,可以找到最小化该损失的最优子树。

    α

    \\alpha

    α 越大,树越小。

    scikit-learn API详解

    DecisionTreeClassifier

    from sklearn.tree import DecisionTreeClassifier

    dt = DecisionTreeClassifier(
    criterion='gini', # 分裂准则: 'gini' 或 'entropy'
    splitter='best', # 'best' 或 'random'
    max_depth=None, # 树的最大深度
    min_samples_split=2, # 内部节点再分裂所需最少样本数
    min_samples_leaf=1, # 叶子节点最少样本数
    min_weight_fraction_leaf=0.0,
    max_features=None, # 寻找最佳分裂时考虑的特征数
    random_state=None,
    max_leaf_nodes=None, # 最大叶子节点数
    min_impurity_decrease=0.0, # 分裂所需的最小不纯度降低
    class_weight=None, # 类别权重(处理不平衡)
    ccp_alpha=0.0 # 后剪枝复杂度参数(>=0)
    )

    常用属性:

    • feature_importances_:特征重要性(归一化后和为1)
    • tree_:底层Tree对象,可获取树结构
    • classes_、n_classes_、n_features_in_

    方法:fit, predict, predict_proba, score

    可视化:

    from sklearn.tree import plot_tree
    plot_tree(dt, filled=True, feature_names=feature_names, class_names=class_names)

    环境配置与依赖安装

    本课需要安装 graphviz(用于 export_graphviz 高级可视化,可选)。基本绘图可用 plot_tree。

    conda activate sklearn_tutorial
    pip install graphviz # 可选

    完整代码实战(带详细注释)

    实战1:决策树基础——鸢尾花分类与可视化

    # -*- coding: utf-8 -*-
    """
    决策树分类:鸢尾花数据集,可视化树结构
    """

    import matplotlib.pyplot as plt
    from sklearn.datasets import load_iris
    from sklearn.model_selection import train_test_split
    from sklearn.tree import DecisionTreeClassifier, plot_tree
    from sklearn.metrics import accuracy_score, confusion_matrix
    import seaborn as sns

    # 加载数据
    iris = load_iris()
    X, y = iris.data, iris.target
    feature_names = iris.feature_names
    class_names = iris.target_names

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    # 训练决策树(不剪枝)
    dt = DecisionTreeClassifier(random_state=42)
    dt.fit(X_train, y_train)

    y_pred = dt.predict(X_test)
    acc = accuracy_score(y_test, y_pred)
    print(f"决策树准确率: {acc:.4f}")
    print(f"树的深度: {dt.tree_.max_depth}")
    print(f"叶子节点数: {dt.tree_.n_leaves}")

    # 可视化决策树
    plt.figure(figsize=(20, 10))
    plot_tree(dt, filled=True, feature_names=feature_names, class_names=class_names, rounded=True)
    plt.title("鸢尾花决策树(未剪枝)")
    plt.show()

    # 混淆矩阵
    cm = confusion_matrix(y_test, y_pred)
    plt.figure(figsize=(5,4))
    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=class_names, yticklabels=class_names)
    plt.title('混淆矩阵')
    plt.xlabel('预测')
    plt.ylabel('真实')
    plt.show()

    实战2:基尼系数 vs 信息熵对比

    # -*- coding: utf-8 -*-
    """
    对比 criterion='gini' 和 'entropy' 在不同数据集上的表现
    使用红酒数据集
    """

    from sklearn.datasets import load_wine
    from sklearn.model_selection import cross_val_score
    from sklearn.tree import DecisionTreeClassifier
    import numpy as np

    wine = load_wine()
    X, y = wine.data, wine.target

    # 5折交叉验证
    cv = 5
    scores_gini = cross_val_score(DecisionTreeClassifier(criterion='gini', random_state=42), X, y, cv=cv)
    scores_entropy = cross_val_score(DecisionTreeClassifier(criterion='entropy', random_state=42), X, y, cv=cv)

    print(f"基尼系数 平均准确率: {scores_gini.mean():.4f} (+/- {scores_gini.std():.4f})")
    print(f"信息熵 平均准确率: {scores_entropy.mean():.4f} (+/- {scores_entropy.std():.4f})")
    print("通常两者差异不大,基尼系数稍快。")

    实战3:预剪枝参数对过拟合的影响

    # -*- coding: utf-8 -*-
    """
    演示预剪枝(max_depth, min_samples_split)如何防止过拟合
    使用生成的数据(训练集噪声大)
    """

    from sklearn.datasets import make_classification
    from sklearn.model_selection import train_test_split
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.metrics import accuracy_score
    import matplotlib.pyplot as plt

    # 生成复杂数据(有噪声)
    X, y = make_classification(n_samples=500, n_features=10, n_informative=8,
    n_redundant=2, flip_y=0.1, random_state=42)
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    # 不同深度
    depths = range(1, 21)
    train_acc = []
    test_acc = []

    for depth in depths:
    dt = DecisionTreeClassifier(max_depth=depth, random_state=42)
    dt.fit(X_train, y_train)
    train_acc.append(accuracy_score(y_train, dt.predict(X_train)))
    test_acc.append(accuracy_score(y_test, dt.predict(X_test)))

    plt.figure(figsize=(10, 6))
    plt.plot(depths, train_acc, 'o-', label='训练准确率')
    plt.plot(depths, test_acc, 's-', label='测试准确率')
    plt.xlabel('最大深度 max_depth')
    plt.ylabel('准确率')
    plt.title('决策树深度与过拟合')
    plt.legend()
    plt.grid(True)
    plt.show()

    print(f"最佳深度: {depths[test_acc.index(max(test_acc))]}")

    实战4:特征重要性分析

    # -*- coding: utf-8 -*-
    """
    提取决策树的特征重要性,并可视化
    使用红酒数据集
    """

    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn.datasets import load_wine
    from sklearn.tree import DecisionTreeClassifier

    wine = load_wine()
    X, y = wine.data, wine.target
    feature_names = wine.feature_names

    dt = DecisionTreeClassifier(random_state=42)
    dt.fit(X, y)

    importances = dt.feature_importances_
    indices = np.argsort(importances)[::1]

    plt.figure(figsize=(10, 6))
    plt.barh(range(len(importances)), importances[indices], align='center')
    plt.yticks(range(len(importances)), np.array(feature_names)[indices])
    plt.xlabel('特征重要性')
    plt.title('决策树特征重要性(红酒数据集)')
    plt.gca().invert_yaxis()
    plt.show()

    print("特征重要性排序:")
    for i in range(len(importances)):
    print(f"{i+1}. {feature_names[indices[i]]}: {importances[indices[i]]:.4f}")

    实战5:后剪枝——代价复杂度剪枝(CCP)

    # -*- coding: utf-8 -*-
    """
    使用 ccp_alpha 进行代价复杂度后剪枝
    对比不同 ccp_alpha 的树复杂度与准确率
    """

    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn.datasets import make_classification
    from sklearn.model_selection import train_test_split
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.metrics import accuracy_score

    X, y = make_classification(n_samples=500, n_features=10, random_state=42)
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    # 先训练一棵完全生长的树(不剪枝)
    dt_full = DecisionTreeClassifier(random_state=42)
    dt_full.fit(X_train, y_train)
    print(f"完全生长树深度: {dt_full.tree_.max_depth}, 叶子数: {dt_full.tree_.n_leaves}")
    print(f"训练集准确率: {accuracy_score(y_train, dt_full.predict(X_train)):.4f}")
    print(f"测试集准确率: {accuracy_score(y_test, dt_full.predict(X_test)):.4f}")

    # 尝试不同的 ccp_alpha
    alphas = np.linspace(0, 0.05, 20)
    train_scores = []
    test_scores = []
    depths = []
    leaves = []

    for alpha in alphas:
    dt = DecisionTreeClassifier(ccp_alpha=alpha, random_state=42)
    dt.fit(X_train, y_train)
    depths.append(dt.tree_.max_depth)
    leaves.append(dt.tree_.n_leaves)
    train_scores.append(accuracy_score(y_train, dt.predict(X_train)))
    test_scores.append(accuracy_score(y_test, dt.predict(X_test)))

    best_idx = np.argmax(test_scores)
    print(f"\\n最佳 ccp_alpha = {alphas[best_idx]:.4f}")
    print(f"对应深度: {depths[best_idx]}, 叶子节点数: {leaves[best_idx]}")
    print(f"测试准确率: {test_scores[best_idx]:.4f}")

    # 绘制性能随 ccp_alpha 变化曲线
    fig, axes = plt.subplots(1, 2, figsize=(12, 5))
    axes[0].plot(alphas, train_scores, 'o-', label='训练准确率')
    axes[0].plot(alphas, test_scores, 's-', label='测试准确率')
    axes[0].set_xlabel('ccp_alpha')
    axes[0].set_ylabel('准确率')
    axes[0].set_title('准确率 vs 剪枝强度')
    axes[0].legend()
    axes[0].grid(True)

    axes[1].plot(alphas, depths, 'o-', label='树深度')
    axes[1].plot(alphas, leaves, 's-', label='叶子节点数')
    axes[1].set_xlabel('ccp_alpha')
    axes[1].set_ylabel('复杂度')
    axes[1].set_title('树复杂度 vs 剪枝强度')
    axes[1].legend()
    axes[1].grid(True)
    plt.tight_layout()
    plt.show()

    实战6:多参数网格搜索(预剪枝 + 后剪枝)

    # -*- coding: utf-8 -*-
    """
    使用 GridSearchCV 联合调优决策树的预剪枝参数和 ccp_alpha
    """

    from sklearn.datasets import load_iris
    from sklearn.model_selection import GridSearchCV, train_test_split
    from sklearn.tree import DecisionTreeClassifier

    X, y = load_iris(return_X_y=True)
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    param_grid = {
    'max_depth': [3, 5, 7, None],
    'min_samples_split': [2, 5, 10],
    'min_samples_leaf': [1, 2, 4],
    'ccp_alpha': [0, 0.005, 0.01, 0.02]
    }

    dt = DecisionTreeClassifier(random_state=42)
    grid = GridSearchCV(dt, param_grid, cv=5, scoring='accuracy', n_jobs=1)
    grid.fit(X_train, y_train)

    print("最佳参数:", grid.best_params_)
    print("最佳交叉验证准确率: {:.4f}".format(grid.best_score_))
    print("测试集准确率: {:.4f}".format(grid.score(X_test, y_test)))

    实战7:决策树回归(DecisionTreeRegressor)

    # -*- coding: utf-8 -*-
    """
    决策树回归:拟合带噪声的正弦曲线
    对比不同深度
    """

    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn.tree import DecisionTreeRegressor

    # 生成数据
    np.random.seed(42)
    X = np.sort(5 * np.random.rand(200, 1), axis=0)
    y = np.sin(X).ravel() + np.random.normal(0, 0.1, X.shape[0])

    X_train, X_test = X[:150], X[150:]
    y_train, y_test = y[:150], y[150:]

    depths = [2, 5, 20]
    plt.figure(figsize=(12, 4))
    for i, depth in enumerate(depths):
    dt_reg = DecisionTreeRegressor(max_depth=depth, random_state=42)
    dt_reg.fit(X_train, y_train)
    y_pred = dt_reg.predict(X_test)
    mse = np.mean((y_test y_pred)**2)

    plt.subplot(1, 3, i+1)
    plt.scatter(X_train, y_train, alpha=0.5, label='训练数据')
    plt.scatter(X_test, y_test, alpha=0.5, marker='x', label='测试数据')
    X_plot = np.linspace(0, 5, 300).reshape(1, 1)
    y_plot = dt_reg.predict(X_plot)
    plt.plot(X_plot, y_plot, 'r-', label=f'depth={depth}, MSE={mse:.4f}')
    plt.xlabel('X')
    plt.ylabel('y')
    plt.legend()
    plt.tight_layout()
    plt.show()

    案例实操演示

    案例:信用卡违约预测(决策树二分类)

    # 模拟信用卡违约数据(真实案例可替换)
    from sklearn.datasets import make_classification
    from sklearn.model_selection import train_test_split
    from sklearn.tree import DecisionTreeClassifier, plot_tree
    import matplotlib.pyplot as plt

    # 生成数据(特征:收入、年龄、负债比、信用记录长度等)
    X, y = make_classification(n_samples=2000, n_features=8, n_informative=6,
    n_redundant=2, flip_y=0.05, random_state=42)
    feature_names = ['收入', '年龄', '负债比', '信用记录长度', '使用率', '逾期次数', '查询次数', '额度利用率']
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    dt = DecisionTreeClassifier(max_depth=5, min_samples_split=20, ccp_alpha=0.01, random_state=42)
    dt.fit(X_train, y_train)
    print(f"训练集准确率: {dt.score(X_train, y_train):.4f}")
    print(f"测试集准确率: {dt.score(X_test, y_test):.4f}")

    # 可视化(限制深度后树较小)
    plt.figure(figsize=(15, 8))
    plot_tree(dt, filled=True, feature_names=feature_names, class_names=['不违约', '违约'], rounded=True)
    plt.title('信用卡违约预测决策树')
    plt.show()

    常见报错与避坑指南

    报错1:ValueError: min_samples_split must be an integer

    原因:min_samples_split 应设置为整数(最小样本数),不能是分数。

    解决:确保使用整数。

    报错2:树太大,plot_tree 显示模糊

    原因:树深度大、叶子多,图形超出显示范围。

    解决:限制 max_depth 或使用 figsize 调整画布大小,或改用 export_graphviz 输出到文件。

    报错3:特征重要性全为零或某些特征重要性异常

    原因:数据中存在大量无关特征,或树深度太浅。

    解决:检查数据,或增加树复杂度。

    报错4:RuntimeError: Tree is too large 在可视化时

    解决:先剪枝(设置 max_depth 较小,如3~5),或导出为文本。

    避坑总结

  • 决策树容易过拟合:务必使用预剪枝(max_depth, min_samples_split)或后剪枝(ccp_alpha)。
  • 对数据微小变化敏感:可采用集成方法(随机森林)提高稳定性。
  • 类别不平衡:设置 class_weight='balanced'。
  • 特征尺度不影响决策树,不需要标准化。
  • 可视化前先限制深度,否则树过于庞大无法阅读。
  • 知识点总结

    本课系统讲解了决策树分类算法的核心原理与实践:

    原理

  • 构建过程:递归选择最优特征分裂,直到节点纯或满足停止条件。
  • 分裂准则:基尼系数(gini)和信息熵(entropy),两者都度量节点的不纯度。
  • 剪枝:预剪枝(限制深度、最少样本数)和后剪枝(代价复杂度剪枝 ccp_alpha)防止过拟合。
  • API

  • DecisionTreeClassifier 核心参数:criterion, max_depth, min_samples_split, min_samples_leaf, ccp_alpha, class_weight。
  • 方法:fit, predict, predict_proba, score。
  • 属性:feature_importances_, tree_。
  • 可视化与解释

  • plot_tree 直接绘制决策树。
  • feature_importances_ 输出特征重要性。
  • 扩展

  • DecisionTreeRegressor 用于回归任务,原理类似(分裂准则为方差减少)。
  • 决策树是随机森林、梯度提升等集成模型的基础。
  • 课后练习题

    选择题

  • 决策树分裂时,基尼系数为0表示: A. 节点包含单一类别 B. 节点中各类比例相等 C. 节点样本数为0 D. 分裂增益最大

  • 以下哪个参数属于后剪枝参数? A. max_depth B. min_samples_split C. ccp_alpha D. min_samples_leaf

  • 决策树对特征缩放的态度是: A. 必须标准化 B. 必须归一化 C. 不需要 D. 取决于数据类型

  • 填空题

    from sklearn.tree import DecisionTreeClassifier

    # 1. 创建决策树,使用熵作为分裂准则,最大深度5
    dt = DecisionTreeClassifier(criterion='________', max_depth=________)

    # 2. 训练
    dt.fit(X_train, y_train)

    # 3. 预测概率
    proba = dt.________(X_test)

    # 4. 获取特征重要性
    importance = dt.________

    实操题

  • 基尼 vs 熵:在红酒数据集上,分别用基尼和信息熵训练决策树(不剪枝),比较交叉验证准确率。同时计算两种树的深度和叶子节点数,分析差异原因。

  • 预剪枝调优:使用 GridSearchCV 在鸢尾花数据集上搜索 max_depth 和 min_samples_split 的最佳组合,输出最佳参数和测试准确率。

  • 特征重要性分析:在 load_breast_cancer 数据集上训练决策树(max_depth=3),打印特征重要性,并解释哪个特征最重要。

  • 思考题

    决策树的特征重要性是基于分裂时带来的不纯度降低的总和计算的。思考:如果一个特征与目标高度相关,但在树中位于较深层(因为上层有另一个特征更强),它的重要性分数会不会被低估?请说明你的观点。


    下一课预告:第22课我们将学习支持向量机(SVM)——强大的分类器,通过核技巧处理线性不可分数据。你将掌握核函数选择、参数调优等核心技能。敬请期待!


    🔗《30节课 scikit-learn 从入门到精通》系列课程导航

    去订阅

    第一部分:基础入门 & 环境准备(1-6 课) 第二部分:数据预处理 & 数据集操作(7-12 课) 第三部分:传统机器学习回归算法(13-17 课) 第四部分:分类算法精讲(18-23 课) 第五部分:聚类 & 降维 & 集成学习(24-29 课) 第六部分:结业大型项目实战(第 30 课)

    🌟 感谢您耐心阅读到这里! 💡 如果本文对您有所启发欢迎: 👍 点赞📌 收藏 📤 分享给更多需要的伙伴。 🗣️ 期待在评论区看到您的想法, 共同进步。 🔔 关注我,持续获取更多干货内容~ 🤗 我们下篇文章见~

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 第21课:scikit-learn|决策树分类原理、基尼系数、信息熵与剪枝策略
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!