sklearn中决策树模块的剪枝参数ccp_alpha如何可视化调整

这篇具有很好参考价值的文章主要介绍了sklearn中决策树模块的剪枝参数ccp_alpha如何可视化调整。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor

决策树作为树模型中最经典的算法,根据训练数据生长并分裂叶子结点,容易过拟合。所以一般来说会考虑生长停止后进行剪枝,把一些不必要的叶子结点去掉(让其父结点作为叶子结点),这样或许对其泛化能力有积极作用。

在scikit-learn的决策树模块里,默认是不剪枝的,因为ccp_alpha参数被默认置为0.0。
它使用的剪枝算法为Minimal Cost-Complexity Pruning,即最小化 R α ( T ) = R ( T ) + α ∣ T ∣ R_\alpha(T)=R(T)+\alpha|T| Rα(T)=R(T)+αT
这个式子解释了一颗给定树T的综合代价,由两部分组成:

  1. R(T)为树T的错误成本Cost,具体实现为该树的加权熵。

scikit-learn uses the total sample weighted impurity of the terminal nodes for R(T)
impurity可以理解为熵。

  1. |T|是树的叶子结点个数,同时也是Complexity, α \alpha α 为系数,也就是本文的焦点ccp_alpha参数。该值越大,树应该越小。

这个式子的两部分会因为树的复杂度或者说叶子结点的个数发生相反方向的变化

  • 第一部分 Cost
    如果不进行剪枝,那么生长结束的树拥有最小的R(T),因为它把能分裂的尽量分裂,不同标签的样本尽可能分进了不同的叶子结点,使得每个叶子结点的impurity最小。一旦剪枝,那么R(T)开始变大,因为叶子结点的impurity开始变大。所以树因为剪枝变小的过程,Cost由小变大。

  • 第二部分 Complexity
    剪枝使得树变小,也就是叶子结点(|T|)变少。所以树因为剪枝变小的过程,Complexity由大变小。

one more step 假设现在是两颗树进行比较。一个树只有一个结点,也就是它的根节点t,我们记为数 T root only T_\text{root only} Troot only;另外一棵树是这个根节点加上分裂出来的叶子结点,我们记为树 T with leafs T_\text{with leafs} Twith leafs

这两棵树分别写一下综合代价应该如何表示呢?
R α ( T root only ) = R ( T root only ) + α R_\alpha(T_\text{root only})=R(T_\text{root only})+\alpha Rα(Troot only)=R(Troot only)+α
R α ( T with leafs ) = R ( T with leafs ) + α ∣ T with leafs ∣ R_\alpha(T_\text{with leafs})=R(T_\text{with leafs})+\alpha|T_\text{with leafs}| Rα(Twith leafs)=R(Twith leafs)+αTwith leafs

根据刚才说的,我们有 R ( T root only ) > R ( T with leafs ) R(T_\text{root only}) > R(T_\text{with leafs}) R(Troot only)>R(Twith leafs)成立。同时, α < α ∣ T with leafs ∣ \alpha < \alpha|T_\text{with leafs}| α<αTwith leafs。那么是不是可以找到一个 α \alpha α,使得 R α ( T root only ) = R α ( T with leafs ) R_\alpha(T_\text{root only}) = R_\alpha(T_\text{with leafs}) Rα(Troot only)=Rα(Twith leafs)成立呢?

α e f f e c t i v e ( t ) = R ( T root only ) − R ( T with leafs ) ∣ T with leafs ∣ − 1 \alpha_{effective}(t) = \frac{R(T_\text{root only})-R(T_\text{with leafs})}{|T_\text{with leafs}|-1} αeffective(t)=Twith leafs1R(Troot only)R(Twith leafs) 就是我们要找的那个临界 α \alpha α

你看,对于每一个内部结点t, 我们都有两种选择,要么保留它的叶子结点;要么裁剪掉它的叶子结点,让这个父结点成为一个叶子结点。我们在剪枝的过程中,也是从外到内,从最外的叶子结点,不断往内部裁剪。在裁剪时,我们会遇到一个问题:外面这一圈有这么多叶子结点,我应该先剪掉哪一个父结点的叶子结点呢?

L. Breiman等人证明过,存在一个 α \alpha α的单调区间序列,在这个 α \alpha α序列里每一个 α i \alpha_i αi对应一个最优子树,而且这些子树是相互嵌套的(序列里小的树是序列里比他更大的所有树的子树)。

具体的证明在这里不会展开,因为我也不会。这里简单粗暴地给出他们的证明可以怎么用。
重点来了
刚才我们对某个内部结点t计算了它的临界 α \alpha α,即 α e f f e c t i v e ( t ) \alpha_{effective}(t) αeffective(t)。那么对于每一个内部结点 i i i,我们是不是都可以计算它的 α e f f e c t i v e ( i ) \alpha_{effective}(i) αeffective(i)。那么好,假设我们已经根据决策树的生长算法生成了一颗很大的树,我们猜测它过拟合了,我们要对他进行剪枝,以提升泛化能力。可以怎么做呢?

step1 对当前树的所有叶子结点的父结点,计算临界 α e f f e c t i v e \alpha_{effective} αeffective,找到临界值最小的那个父结点,对他进行剪枝,即把它的叶子结点裁剪掉,让它作为叶子结点。它的输出标签为该结点所持有的样本标签的多数类。裁剪后的树设置为当前树。

step2 重复step1,直到满足停止剪枝条件。比如,剪枝轮次达到阈值、临界值达到阈值等等。

上面这个过程中,我们其实可以产生一个临界 α \alpha α的序列,同时也会产生每棵最优子树的impurity,后面代码的时候我们会用到。

为什么需要调整ccp_alpha参数

由上可知,式子里需要加一个 α \alpha α参数来进行协调两个部分的影响,如果它俩的变化方向是同向的也就没必要加这个参数了。因此,这个 α \alpha α是决策树的一个超参数,在使用决策树模块时可能需要对其进行合理设置以获得更好的模型表现。很容易理解,比起对训练集的预测表现,如果你更希望树复杂度低一点,那么把 α \alpha α调大;如果你希望它能够充分学习训练集甚至过拟合,那么把 α \alpha α调小。

看到这里,你可以先看看来自scikit-learn官网决策树模块有关ccp_alpha参数的解释。
下面是scikit-learn里决策树模块的ccp_alpha参数解释:

ccp_alpha : non-negative float, default=0.0
Complexity parameter used for Minimal Cost-Complexity Pruning. The subtree with the largest cost complexity that is smaller than ccp_alpha will be chosen. By default, no pruning is performed.

为什么前面说,在scikit-learn的决策树模块里,默认是不剪枝的, 应该就很好理解了。

接下来,本文将通过一个代码示例,介绍如何可视化选择合适的ccp_alpha。

初始化

为了下文中代码的可读性,这里先把所有本文涉及到的依赖一次性给出。

import matplotlib.pyplot as plt

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor
from sklearn.metrics import recall_score, precision_score

后面的随机状态默认使用0,即

random_state = 0

获取数据,这里使用的是sklearn自带的乳癌数据集,标签是二分类。并做训练集和测试集划分。

X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

计算临界 α \alpha α序列和对应的impurity序列。然后把临界值序列对应的最优子树也准备好放在clfs变量里备用。

clf = DecisionTreeClassifier(random_state=0)
path = clf.cost_complexity_pruning_path(X_train, y_train)
ccp_alphas, impurities = path.ccp_alphas, path.impurities
clfs = []
for ccp_alpha in ccp_alphas:
    clf = DecisionTreeClassifier(random_state=0, ccp_alpha=ccp_alpha)
    clf.fit(X_train, y_train)
    clfs.append(clf)

然后接下来这段代码比较多,但是也很容易理解。我都写上注释了。

# 由于alpha序列的最后一个是最大的临界alpha,它对应的最优子树其实是根节点,
# 对我们没啥意义,所以剔除掉。
clfs = clfs[:-1]
ccp_alphas = ccp_alphas[:-1]

# 使用最优子树序列预测训练集和测试集。
y_test_preds = [clf.predict(X_test) for clf in clfs]
y_train_preds = [clf.predict(X_train) for clf in clfs]

# 计算训练集、测试集的召回率
train_recall_scores = [recall_score(y_train, y_train_pred) for y_train_pred in y_train_preds]
test_recall_scores = [recall_score(y_test, y_test_pred) for y_test_pred in y_test_preds]

# 计算训练集、测试集的精确率
train_precision_scores = [precision_score(y_train, y_train_pred) for y_train_pred in y_train_preds]
test_precision_scores = [precision_score(y_test, y_test_pred) for y_test_pred in y_test_preds]

# 计算训练集、测试集的准确率
train_accuracy_scores = [clf.score(X_train, y_train) for clf in clfs]
test_accuracy_scores = [clf.score(X_test, y_test) for clf in clfs]

# 画图函数,入参为模型指标(recall、accuracy、precision)
def draw_func(metric_name):
    fig, ax = plt.subplots()
    ax.set_xlabel("alpha")
    ax.set_ylabel(metric_name)
    ax.set_title(metric_name + " vs alpha for training and testing sets")
    ax.plot(ccp_alphas, eval(f"train_{metric_name}_scores"), marker="o", label="train", drawstyle="steps-post")
    ax.plot(ccp_alphas, eval(f"test_{metric_name}_scores"), marker="o", label="test", drawstyle="steps-post")
    ax.legend()
    plt.show()

看看这三个指标的效果
(1)准确率

draw_func(metric_name='accuracy')

sklearn中决策树模块的剪枝参数ccp_alpha如何可视化调整,机器学习ML,sklearn,决策树,剪枝
从准确率来看,选择alpha为0.015, 比较好。

(2)召回率

draw_func(metric_name='recall')

sklearn中决策树模块的剪枝参数ccp_alpha如何可视化调整,机器学习ML,sklearn,决策树,剪枝
从召回率来看,选择0.03比较好。

(3)精确率

draw_func(metric_name='precision')

sklearn中决策树模块的剪枝参数ccp_alpha如何可视化调整,机器学习ML,sklearn,决策树,剪枝
可以发现在0.005到0.01之间有一段非常小的区间,测试集表现最高且训练集没有太大下降。但是这个区间有些窄,好像看起来有点不稳定。我们暂且又选择0.015吧。

现在把ccp_alpha设置好,打印得分出来看看

def get_results(ccp_alpha_para):
    clf = DecisionTreeClassifier(random_state=0, ccp_alpha=ccp_alpha_para)
    clf.fit(X_train, y_train)
    y_pred = clf.predict(X_test)
    print(f'acc: {round(clf.score(X_test, y_test), 3)}')
    print(f'recall: {round(recall_score(y_test, y_pred), 3)}')
    print(f'precision: {round(precision_score(y_test, y_pred), 3)}')

我这里还是觉得放在表格里一目了然一些:

import pandas as pd
adf = pd.DataFrame(columns=['ccp_alpha'], data=[0.0, 0.001, 0.015, 0.03])
adf[['acc', 'recall', 'precision']] = adf.apply(lambda x:get_results(x['ccp_alpha']), axis=1, result_type='expand')

sklearn中决策树模块的剪枝参数ccp_alpha如何可视化调整,机器学习ML,sklearn,决策树,剪枝
表格里的结果都是在测试集下的表现。如同刚才所说的,召回率在0.03的时候高一些,准确率和精确率则是选择0.015比较好。
可见, 当ccp_alpha=0时(也就是默认参数),模型性能不是最好的。
在本案例中,假如设置为0.015, 相比默认参数0,acc提升5.6%,recall提升6.7%,precision提升2.6%。

后续

在获得了临界alpha序列和对应的最优子树序列之后,如果你不指定ccp_alpha,那么剪枝算法其实是对每一个最优子树在数据集上重新计算综合代价来确定的子树。
在李航的统计学习方法中,还讲到可以用验证集来进行剪枝。这样可能具有更好的泛化性。文章来源地址https://www.toymoban.com/news/detail-833569.html

到了这里,关于sklearn中决策树模块的剪枝参数ccp_alpha如何可视化调整的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Alpha-Beta剪枝的原理的深入理解(无图预警)

    转载请注明 原文链接 :https://www.cnblogs.com/Multya/p/17929261.html 考虑一个树: 一棵树上只有叶子节点有值,有确定的根节点的位置 根据层数来划分叶子节点和根节点之间的链接节点 偶数层上的值取子节点的最大值,奇数取最小 因为叶子节点上的值确定,在有这么个规则之后整

    2024年02月04日
    浏览(35)
  • 【博弈论】极小极大搜索(Minimax Algorithm)与α-β剪枝(Alpha-Beta Pruning)

    在零和博弈(有完整信息的,确定的、轮流行动的,两个参与者收益之和为0的博弈)中,双方都希望自己获胜,因此每一步都选择对自己最有利,对对方最不利的做法。 假设我们是参与博弈的一方。我们用静态估计函数 f ( p ) f(p) f ( p ) 来估计博弈双方的态势: 有利于我方的

    2023年04月16日
    浏览(25)
  • 决策树模型(3)决策树的生成与剪枝

    有了信息增益和信息增益比,我就可以以此衡量特征的相对好坏,进而可以用于决策树的生成。相对应的基于信息增益计算的方法所生成的决策树的算法我们叫做ID3算法,而基于信息增益的算法我们叫做C4.5,二者唯一的区别就在于一个使用信息增益衡量特征好坏而另外一个使

    2024年03月28日
    浏览(30)
  • 决策树剪枝:解决模型过拟合【决策树、机器学习】

    决策树是一种强大的机器学习算法,用于解决 分类 和 回归 问题。决策树模型通过树状结构的决策规则来进行预测,但在构建决策树时,常常会出现过拟合的问题,即模型在训练数据上表现出色,但在未见过的数据上表现不佳。 过拟合的威胁 在机器学习中, 过拟合 是一个

    2024年02月07日
    浏览(36)
  • 决策树的剪枝

    目录 一、为什么要剪枝 二、剪枝的策略 1、预剪枝(pre-pruning) 2、后剪枝(post-pruning) 三、代码实现 1、收集、准备数据: 2、分析数据: 3、预剪枝及测试:  4、后剪枝及测试: 四、总结 剪枝(pruning)的目的是为了避免决策树模型的过拟合。因为决策树算法在学习的过程

    2024年02月06日
    浏览(26)
  • sklearn机器学习库(一)sklearn中的决策树

    sklearn中决策树的类都在”tree“这个模块之下。 tree.DecisionTreeClassifier 分类树 tree.DecisionTreeRegressor 回归树 tree.export_graphviz 将生成的决策树导出为DOT格式,画图专用 tree.export_text 以文字形式输出树 tree.ExtraTreeClassifier 高随机版本的分类树 tree.ExtraTreeRegressor 高随机版本的回归树

    2024年02月13日
    浏览(33)
  • 机器学习--sklearn(决策树)

    决策树(Decision Tree)是一种非参数的有监督学习方法,它能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题。 节点 根节点:没有进边,有出边。包含最初的,针对特征的提问。 中间节点:既有进边也有出边,进

    2023年04月18日
    浏览(24)
  • sklearn中使用决策树

    criterion可以是信息熵,entropy,可以是基尼系数gini 决策树生成的pdf  max_depth:这参数用来控制决策树的最大深度。以下示例,构建1~10深度的决策时,看哪个深度的决策树的精确率(score)高 结果: 数据来源: Titanic - Machine Learning from Disaster | Kaggle 读取数据  筛选特征 处理缺失

    2024年02月13日
    浏览(19)
  • sklearn-决策树

    目录 决策树算法关键 特征维度判别条件 决策树算法:选择决策条件 纯度的概念 信息增益 增益率: 基尼指数: 纯度度量方法 1) 纯度函数 2) 纯度度量函数 了解了“if-else”原理,下面我们进一步认识决策树算法。决策树算法涉及了几个重要的知识点:“决策树的分类方法”

    2024年02月12日
    浏览(24)
  • 机器学习(三)决策树对连续值数据的预剪枝及后剪枝(Python代码)

    参考: https://blog.csdn.net/ylhlly/article/details/93213633 https://zhuanlan.zhihu.com/p/267368825 为什么要进行剪枝? 当我们的数据集 样本量很大 、 每个特征的取值很多 时,生成决策树的 代价 就会 很大 。不仅如此,虽然一个完整的决策树对训练数据的预测非常准,但这会造成 对训练数据

    2023年04月22日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包