【1 - 决策树 - 原理部分】菜菜sklearn机器学习

课程地址:《菜菜的机器学习sklearn课堂》_哔哩哔哩_bilibili

  • 第一期:sklearn入门 & 决策树在sklearn中的实现
  • 第二期:随机森林在sklearn中的实现
  • 第三期:sklearn中的数据预处理和特征工程
  • 第四期:sklearn中的降维算法PCA和SVD
  • 第五期:sklearn中的逻辑回归
  • 第六期:sklearn中的聚类算法K-Means
  • 第七期:sklearn中的支持向量机SVM(上)
  • 第八期:sklearn中的支持向量机SVM(下)
  • 第九期:sklearn中的线性回归大家族
  • 第十期:sklearn中的朴素贝叶斯
  • 第十一期:sklearn与XGBoost
  • 第十二期:sklearn中的神经网络

目录

sklearn入门

决策树(Decision Tree,DT) 

(一)决策树是如何工作的 

(二)sklearn中的决策树

分类树DecisionTreeClassifier与红酒数据集

重要参数

(一)criterion:用来决定不纯度的计算方法

(二)random_state & splitter:控制随机性

(三)剪枝参数(5个)

(四)目标权重参数(完成样本标签平衡的参数,不常用) 

重要属性和接口

总结 

回归树DecisionTreeRegressor与波士顿房价数据集

重要参数、属性及接口 

(一)criterion(回归树衡量分枝质量的指标)

(二)属性

(三)接口

(四)交叉验证 

实例:一维回归的图像绘制 

决策树的优缺点


sklearn入门

scikit-learn是一个开源的基于Python的机器学习工具包

分析采集到的数据,根据数据特征选择适合的算法,在工具包中调用算法,调整算法的参数,获取需要的信息,从而实现算法效率和效果之间的平衡

解析sklearn的全面应用,了解不同机器学习算法有哪些可调参数、有哪些可用接口,这些接口和参数对算法来说有什么含义,又会对算法的性能及准确性有什么影响 —— 讲解sklearn中对算法的说明、调参、属性、接口,以及实例应用

sklearn官网:scikit-learn: machine learning in Python — scikit-learn 1.2.0 documentation 

  • 分类、回归、聚类、降维、模型选择、数据预处理 


决策树(Decision Tree,DT) 

(一)决策树是如何工作的 

是一种非参数(不限制数据的结构和类型,几乎可以用它来处理各种各样的数据)的有监督学习(要给标签)方法,能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题

  • 以树模型为核心的各种集成算法(如Adaboost、随机森林)
  • 本质是一种图结构,只需要问一系列问题就可以对数据进行分类了

决策树算法的核心是要解决两个问题:

  1. 如何从数据表中找出最佳节点和最佳分枝?(如何找出正确的特征来进行提问?)

    定义了用来衡量分枝质量的指标——不纯度,分类树的不纯度用基尼系数或信息熵来衡量,回归树的不纯度用MSE均方误差来衡量
    每次分枝时,决策树对所有的特征进行不纯度计算,选取不纯度最低的特征进行分枝,分枝后,又再对被分枝的不同取值下,计算每个特征的不纯度,继续选取不纯度最低的特征进行分枝
     
  2. 如何让决策树停止生长,防止过拟合?

    每分枝一层,树整体的不纯度会越来越小,决策树追求的是最小不纯度。因此,决策树会一直分枝,直到没有更多的特征可用,或整体的不纯度指标已经最优,决策树就会停止生长

(二)sklearn中的决策树

模块sklearn.tree,包含五个类(还有两个类分别是高随机版本的分类树和回归树,不常用):

  • tree.DecisionTreeClassifier:分类树
  • tree.DecisionTreeRegressor:回归树
  • tree.export_graphviz:将生成的决策树导出为DOT格式,画图专用

sklearn的基本建模流程:

在这个流程下,分类树对应的代码是:

from sklearn import tree

clf = tree.DecisionTreeClassifier()   # 实例化
clf = clf.fit(X_train,y_train)   # 用训练集数据训练模型
result = clf.score(X_test,y_test)   # 导入测试集,从接口中调用需要的信息(对分类模型来说就是accuracy)

分类树DecisionTreeClassifier与红酒数据集

sklearn.tree.DecisionTreeClassifier — scikit-learn 1.2.0 documentation

重要参数

(一)criterion:用来决定不纯度的计算方法

为了要将表格转化成一棵树,决策树需要找出最佳节点和最佳分枝方法。对分类树来说,衡量这个最佳的指标是不纯度

  • 不纯度越低,决策树对训练集的拟合越好
  • 基于节点来计算,子节点的不纯度一定低于父节点
  • 在同一棵决策树上,叶子节点的不纯度一定最低 

sklearn提供了两种选择:

  1. entropy:信息熵(实际计算的是基于信息熵的信息增益,即父节点的信息熵和子节点的信息熵之差。子节点的信息熵一定小于父节点,所以信息增益越大,这一层分枝对决策树的贡献就越大),取值范围为0~1
  2. gini:基尼系数(默认),取值范围为0~0.5

  

对比:

  • 信息熵对不纯度更加敏感,所以信息熵作为指标时,决策树的生长会更加精细,因此对于高维数据或噪音很多的数据,信息熵很容易过拟合,基尼系数在这种情况下效果往往比较好
  • 当模型拟合程度不足时,即当模型在训练集和测试集上都表现不太好时,使用信息熵

决策树的基本流程可以简单概括为:

计算全部特征的不纯度指标 ——> 选取不纯度指标最优的特征来分枝 ——> 在第一个特征的分枝下,计算全部特征的不纯度指标 ——> 选取不纯度指标最优的特征继续分枝... ——> 直到没有更多的特征可用,或整体的不纯度指标已经最优,决策树就会停止生长

from sklearn import tree
from sklearn.datasets import load_wine  # datasets是sklearn自带的含有各种各样数据的库,包含波士顿房价、鸢尾花、红酒数据等
from sklearn.model_selection import train_test_split

wine = load_wine()  # 数据实例化

# wine是一个字典,wine.data取数据,wine.target取标签
wine.data.shape  # 13个特征
wine.target  # 三分类

# 将wine变成一张表
import pandas as pd
pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1)

wine.feature_names
wine.target_names

# 分训练集和测试集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)

# 建立模型
clf = tree.DecisionTreeClassifier(criterion="entropy")  # 实例化,criterion默认为gini
clf = clf.fit(Xtrain, Ytrain)   # 把数据带进去训练
score = clf.score(Xtest, Ytest)   # 返回预测的准确度accuracy

score

# 画树
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜色强度','色调','od280/od315稀释葡萄酒','脯氨酸']

import graphviz
dot_data = tree.export_graphviz(clf   # 已经训练好的模型
                                ,feature_names = feature_name
                                ,class_names=["琴酒","雪莉","贝尔摩德"]
                                ,filled=True   # 填充颜色(不纯度越低,颜色越深)
                                ,rounded=True  # 框的形状
                               ) 

graph = graphviz.Source(dot_data)  # 越往下,不纯度entropy越低。不纯度为0时,就可以选出标签类别了
graph

# 特征重要性(没有使用的特征,为0)
clf.feature_importances_    # 对决策树贡献越大的,重要性越高(根节点对特征重要性的贡献一定是最大的)

[*zip(feature_name,clf.feature_importances_)]

上述代码每次运行得到的结果都不一样,这是为什么?

  • 无论决策树模型如何进化,在分枝上的本质都还是追求某个不纯度相关指标的优化
  • 不纯度是基于节点来计算的,即决策树在建树时,是靠优化节点来追求一棵优化的树,但最优的节点不能保证一定是最优的树
  • sklearn基本思想则是,既然一棵树不能保证最优,那就建更多不同的树,然后从中取最好的
  • 怎样从一组数据集中建不同的树?在每次分枝时,不使用全部特征,而是随机选取一部分特征,从中选取不纯度相关指标最优的作为分枝用的节点,这样,每次生成的树也就不同了 

(二)random_state & splitter:控制随机性

  1. random_state:用来设置分枝中的随机模式的参数。输入任意整数,会一直长出同一棵树,让模型稳定下来
  2. splitter:用来控制决策树中的随机选项,有两种输入值,best(默认)/ random

    - best:决策树在分枝时虽然随机,但还是会优先选择更重要的特征进行分枝(重要性可以通过属性 feature_importances_ 查看)

    - random:决策树在分枝时会更加随机,树会因为含有更多不必要的信息而更深更大,并因这些不必要的信息而降低对训练集的拟合(也是防止过拟合的一种方式)

树一旦建成,使用剪枝参数来防止过拟合

(三)剪枝参数(5个)

  • 在不加限制的情况下,一棵决策树会生长到衡量不纯度的指标最优,或者没有更多的特征可用为止,这样的决策树往往会过拟合(训练集上表现好,测试集上表现差)
  • 我们收集的样本数据不可能和整体的状况完全一致,因此,当一棵决策树对训练数据有了过于优秀的解释性,它找出的规则必然包含了训练样本中的噪声,并使它对未知数据的拟合程度不足
  • 为了让决策树有更好的泛化性,要对决策树进行剪枝

sklearn为我们提供了不同的剪枝策略:

  1. max_depth:超过设定深度的树枝全部剪掉。在高维度低样本量时有效,一般从=3开始尝试
  2. min_samples_leaf:限定一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生,或朝着满足每个子节点都包含min_samples_leaf个样本的方向去发生。设置的太小会引起过拟合,设置的太大会阻止模型学习数据,一般从=5开始使用。如果叶节点中含有的样本量变化很大,输入浮点数作为样本量的百分比来使用
  3. min_samples_split:限定一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分枝
  4. max_features:限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃。如果希望通过降维的方式防止过拟合,建议使用PCA、ICA或者特征选择模块中的降维算法
  5. min_impurity_decrease:限制信息增益的大小,信息增益小于设定数值的分枝不会发生

确定最优的剪枝参数:超参数学习曲线,是一条以超参数的取值为横坐标,模型的度量指标为纵坐标的曲线,它是用来衡量不同超参数取值下模型的表现的线

import matplotlib.pyplot as plt

test = []
for i in range(10):
    clf = tree.DecisionTreeClassifier(max_depth=i+1   # 1-10
                                    ,criterion="entropy"
                                    ,random_state=30
                                    ,splitter="random"
                                    )
    clf = clf.fit(Xtrain, Ytrain)
    score = clf.score(Xtest, Ytest)
    test.append(score)

plt.plot(range(1,11),test,color="red",label="max_depth")
plt.legend()
plt.show()

(四)目标权重参数(完成样本标签平衡的参数,不常用) 

  1. class_weight:对样本标签进行一定的均衡,给少量的标签更多的权重,让模型更偏向少数类
  2. min_weight_fraction_leaf:有了权重之后,样本量就不再是单纯地记录数目,而是受输入的权重影响,此时剪枝需要基于权重的剪枝参数min_weight_fraction_leaf。它将比不知道样本权重的标准(如min_samples_leaf)更少偏向主导类

重要属性和接口

属性:在模型训练之后,能够调用查看的模型的各种性质。对决策树来说,属性feature_importances_能够查看各个特征对模型的重要性

接口:

  • fit 和 score:几乎每个算法都可以使用
  • apply:输入测试集,返回每个测试样本所在的叶子节点的索引
  • predict:输入测试集,返回每个测试样本的分类/回归结果

所有接口中要求输入 X_train 和 X_test 的部分,输入的特征矩阵必须至少是一个二维矩阵(sklearn不接受任何一维矩阵作为特征矩阵被输入)

  • 如果数据只有一个特征,必须用reshape(-1,1)来给矩阵增维
  • 如果数据只有一个特征和一个样本,使用reshape(1,-1)来给数据增维

总结 

分类树的八个参数、一个属性(feature_importances_)、四个接口(fit,score,apply,predict)

八个参数:

  • criterion
  • 两个随机性相关的参数:random_state,splitter
  • 五个剪枝参数:max_depth,min_samples_split,min_samples_leaf,max_feature,min_impurity_decrease 

回归树DecisionTreeRegressor与波士顿房价数据集

sklearn.tree.DecisionTreeRegressor — scikit-learn 1.2.0 documentation

在回归树中,没有标签分布是否均衡的问题,故没有class_weight这样的参数

重要参数、属性及接口 

(一)criterion(回归树衡量分枝质量的指标)

  1. mse:均方误差(样本真实数据与回归结果的差异)
  2. friedman_mse:费尔德曼均方误差
  3. mae:绝对平均误差

在回归树中,MSE不只是分枝质量衡量指标,也是最常用的衡量回归树回归质量的指标

在使用交叉验证获取回归树的结果时,往往选择MSE作为评估(在分类树中是score代表的accuracy) 

(二)属性

feature_importances_

(三)接口

score返回的是R²(默认),不是MSE

u是残差平方和,v是总平方和
  • R²可以为正为负,取值范围是 ﹣∞ ~ 1(越接近1越好)
  • MSE永远为正 

(四)交叉验证 

将数据划分为n份,依次使用其中一份作为测试集,其他n-1份作为训练集,多次计算模型的精确性来评估模型的平均准确程度

训练集和测试集的划分会干扰模型的结果,因此用交叉验证n次的结果求出的平均值,是对模型效果的一个更好的度量

交叉验证的过程包含了fit 

from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeRegressor

boston = load_boston()   # 字典
# boston.data取数据,boston.target取标签(连续型变量)

regressor = DecisionTreeRegressor(random_state=0) #实例化
# 交叉验证传入的是完整数据,不需要划分训练集和测试集
# cv=10意味着十折,1份测试,9份训练。默认为5
cross_val_score(regressor, boston.data, boston.target, cv=10, scoring="neg_mean_squared_error").mean()

实例:一维回归的图像绘制 

用回归树来拟合正弦曲线,并添加一些噪声来观察回归树

.rand(x):随机生成x个0-1之间的随机数

.rand(x,y):x行y列的数组

np.random.rand(数组结构):生成随机数组
np.sort(axis=0):从小到大排序(按行)


.ravel():降维函数,n维降维n-1维,多次运行可以一直降到1维


np.newaxis:增维切片

  • l = np.array([1,2,3,4])    # (4,)
  • l[: , np.newaxis]    # (4,1)
  • l[np.newaxis, :]    # (1,4)
import numpy as np  # 生成数据点,即正弦曲线
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt

# 创建一条含有噪声的正弦曲线

'''
基本思路:
先创建一组随机的、分布在0-5上的横坐标轴的取值(x),
然后将这一组值放到sin函数中去生成纵坐标的值(y),
接着再到y上去添加噪声
'''
rng = np.random.RandomState(1) #随机数种子(一种固定的随机)

'''
接口不允许导入一维数组,故X生成的是二维的
'''
X = np.sort(5 * rng.rand(80,1), axis=0) #生成0~5之间随机的x的取值

'''
输入的X是二维的,故np.sin(X)生成的结果也一定是二维的。
但是导入回归树的标签必须是一维的,否则会报错
故使用.ravel()降维
'''
y = np.sin(X).ravel() #生成正弦曲线

'''
y[::5]中的5为步长,故取出16个数
'''
y[::5] += 3 * (0.5 - rng.rand(16)) #在正弦曲线上加噪声

plt.figure()  # 画布
plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data")  # s为点的大小

# 实例化&训练模型
regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_1.fit(X, y)
regr_2.fit(X, y)

# 测试集导入模型,预测结果
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]

y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)

# 绘制图像
plt.figure()
plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data")
plt.plot(X_test, y_1, color="cornflowerblue",label="max_depth=2", linewidth=2)
plt.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2)   # 过拟合了
plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
plt.legend()
plt.show()

如果树的最大深度(由max_depth控制)设置的太高,则决策树学习的太精细,它从训练数据中学了很多细节(包括噪声的呈现),从而使模型偏离真实的正弦曲线,过拟合


决策树的优缺点

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Cheeryang_ego

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

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

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

打赏作者

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

抵扣说明:

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

余额充值