开发环境的配置

我自己是下了一个 anaconda,用 Anaconda Navigator 进到 JupyterLab 进行学习的。(但是我看菜菜好像是用 cmd 进的 JupyterLab?不管那么多,咱们看这个的首要目标是学会用这几个算法)

然后我配置的时候遇到了很多问题,基本上都是下面这个pdf帮我解决的,里面内容写的已经很详细了,只需要当成说明书去装好就行了,毕竟配置开发环境是一劳永逸的事~

Python的安装与环境配置.pdf

对了,还有一个比较重要的一点就是 graphviz,因为anaconda并没有自带,所以没装这个就画不出决策树。

下载地址是:https://graphviz.gitlab.io/_pages/Download/Download_windows.html

然后安装好以后在环境变量里加一条,指向 graphviz/bin/(环境变量要用绝对路径添加,具体看你自己装在哪个盘符里)

最后打开 anaconda 的命令提示符,输入 pip install graphviz,就解决了。

决策树的概念

决策树,简单的说就是,问一系列问题来将一个数据集进行分类。决策树算法的本质是一种图结构。

我们以西瓜书上的例子来说明,我这里尽量简略的说明,如果读者想了解更多有关决策树具体算法原理的内容,可以自行下载西瓜书的pdf阅读一下。

机器学习周志华.pdf

对于一个西瓜来说,例如,我们要对“这是好瓜吗?”这样的问题进行决策时,通常会进行一系列的判断或“子决策”:我们先看“它是什么颜色?”,如果是“青绿色”,则我们再看“它的根蒂是什么形态?”,如果是“蜷缩”,我们再判断“它敲起来是什么声音?”,最后,我们得出最终决策:这是个好瓜,决策过程如下图所示。
QQ截图20210404112514.png
显然,决策过程的最终结论对应了我们所希望的判定结果,例如“是”或“不是”好瓜。决策过程中提出的每个判定问题都是对某个属性的“测试”,例如“色泽=?”“根蒂=?”。每个测试的结果或是导出最终结论,或是导出进一步的判定问题,其考虑范围是在上次决策结果的限定范围之内。

一颗决策树包含一个根节点、若干个内部节点和若干个叶节点。叶节点对应决策结果,其他每个节点对应一个属性测试。根节点包含了样本全集。从根节点到每个叶结点的路径对应了一个判定测试序列。

决策树学习的目的是为了产生一颗泛化能力强,即处理未见示例能力强的决策树。

利用sklearn画出决策树

1.导入需要的算法库和模块

  1. from sklearn import tree
  2. from sklearn.datasets import load_wine
  3. from sklearn.model_selection import train_test_split

2.探索数据

  1. wine = load_wine()
  2. wine.data.shape
  3. wine.target
  4. import pandas as pd
  5. pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1) #画出表格
  6. wine.feature_names
  7. wine.target_names

3.分训练集和测试集

  1. Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)
  2. Xtrain.shape
  3. Xtest.shape

4.建立模型

  1. clf = tree.DecisionTreeClassifier(criterion="entropy")
  2. clf = clf.fit(Xtrain, Ytrain)
  3. score = clf.score(Xtest, Ytest)
  4. score

5.画出决策树

  1. feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜 色强度','色调','od280/od315稀释葡萄酒','脯氨酸']
  2. import graphviz
  3. dot_data = tree.export_graphviz(clf
  4. ,feature_names= feature_name
  5. ,class_names=["琴酒","雪莉","贝尔摩德"]
  6. ,filled=True
  7. ,rounded=True
  8. )
  9. graph = graphviz.Source(dot_data)
  10. graph

6.探索决策树

  1. clf.feature_importances_
  2. [*zip(feature_name,clf.feature_importances_)]

构建决策树的重要参数

random_state & splitter

random_state 用来设置分枝中的随机模式的参数,默认 None,在高维度时随机性会表现更明显,低维度的数据,随机性几乎不会显现。

splitter 也是用来控制决策树中的随机选项的,有两种输入值,输入”best”,决策树在分枝时虽然随机,但是还是会优先选择更重要的特征进行分枝(重要性通过属性featureimportances查看);输入”random”,决策树在分枝时会更加随机,树会因为含有更多的不必要信息而更深更大,并且会因为这些不必要信息而降低对训练集的拟合。

  1. clf = tree.DecisionTreeClassifier(criterion="entropy"
  2. ,random_state=30
  3. ,splitter="random"
  4. )
  5. clf = clf.fit(Xtrain,Ytrain)
  6. score = clf.score(Xtest,Ytest)
  7. score
  8. import graphviz
  9. dot_data = tree.export_graphviz(clf
  10. ,feature_names=feature_name
  11. ,class_names=["琴酒","雪莉","贝尔摩德"]
  12. ,filled=True
  13. ,rounded=True
  14. )
  15. graph = graphviz.Source(dot_data)
  16. graph

剪枝参数

在不加限制的情况下,一颗决策树会生长到衡量不纯度的指标最优,或者没有更多的特征可用为止。这样的决策树往往会过拟合,这就是说,它会在训练集上表现很好,在测试集上却表现糟糕。

为了让决策树有更好的泛化性,我们要对决策树进行剪枝。剪枝策略对决策树的影响巨大,正确的剪枝策略是优化决策树算法的核心。

max_depth

限制树的最大深度,超过设定深度的树枝全部剪掉。

这是用得最广泛的剪枝参数,在高维度低样本量时非常有效。决策树多生长一层,对样本量的需求会增加一倍,所 以限制树深度能够有效地限制过拟合。在集成算法中也非常实用。实际使用时,建议从=3开始尝试,看看拟合的效 果再决定是否增加设定深度

min_samples_leaf & min_samples_split

min_samples_leaf 限定,一个节点在分枝后的每个子节点都必须包含至少 min_samples_leaf 个训练样本,否则分枝就不会发生。

一般搭配 max_depth 使用,在回归树中有神奇的效果,可以让模型变得更加平滑。这个参数的数量设置的太小会引起过拟合,设置得太大就会阻止模型学习数据。一般来说,建议从=5开始使用。如果叶节点中含有的样本量变化很大,建议输入浮点数作为样本的百分比来使用。同时,这个参数可以保证每个叶子的最小尺寸,可以在回归问题中避免低方差,过拟合的叶子节点出现。对于类别不多的分类问题,=1通常就是最佳选择。

min_samples_split 限定,一个节点必须要包含至少 min_samples_split 个训练样本,这个节点才允许被分枝,否则分枝就不会发生。

  1. clf = tree.DecisionTreeClassifier(criterion="entropy"
  2. ,random_state=30
  3. ,splitter="random"
  4. ,max_depth=3
  5. ,min_samples_leaf=10
  6. ,min_samples_split=10
  7. )
  8. clf = clf.fit(Xtrain,Ytrain)
  9. dot_data = tree.export_graphviz(clf
  10. ,feature_names=feature_name
  11. ,class_names=["琴酒","雪莉","贝尔摩德"]
  12. ,filler=True
  13. ,rounded=True
  14. )
  15. graph = graphviz.Source(dot_data)
  16. graph
  17. clf.score(Xtrain,Ytrain)
  18. clf.score(Xttest,Ytest)

max_features & min_impurity_decrease

一般 max_depth 使用,用作树的“精修”

max_features 限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃。和 max_depth 异曲同工,max_features 是用来限制高维度数据的过拟合的剪枝参数,但其方法比较暴力,是直接限制可以使用的特征数量而强行使决策树停下的参数,在不知道决策树中的各个特征的重要性的情况下,强行设定这个参数可能会导致模型 学习不足。如果希望通过降维的方式防止过拟合,建议使用PCA,ICA或者特征选择模块中的降维算法。

min_impurity_decrease 限制信息增益的大小,信息增益小于设定数值的分枝不会发生。

确认最优的剪枝参数

那具体怎么来确定每个参数填写什么值呢?这时候,我们就要使用确定超参数的曲线来进行判断了,继续使用我们 已经训练好的决策树模型clf。超参数的学习曲线,是一条以超参数的取值为横坐标,模型的度量指标为纵坐标的曲 线,它是用来衡量不同超参数取值下模型的表现的线。在我们建好的决策树里,我们的模型度量指标就是score。

  1. import matplotlib.pyplot as plt
  2. test = []
  3. for i in range(10):
  4. clf = tree.DecisionTreeClassifier(max_depth=i+1
  5. ,criterion="entropy"
  6. ,random_state=30
  7. ,splitter="random"
  8. )
  9. clf = clf.fit(Xtrain,Ytrain)
  10. score = clf.score(Xtest,Ytest)
  11. test.append(score)
  12. plt.plot(range(1,11),test,color="red",label="max_depth")
  13. plt.legend()
  14. plt.show()

无论如何,剪枝参数的默认值会让树无尽地生长,这些树在某些数据集上可能非常巨大,对内存的消耗。所以如果 你手中的数据集非常大,你已经预测到无论如何你都是要剪枝的,那提前设定这些参数来控制树的复杂性和大小会 比较好。

目标权重参数

class_weight & min_weight_fraction_leaf

完成样本标签平衡的参数。样本不平衡是指在一组数据集中,标签的一类天生占有很大的比例。比如说,在银行要 判断“一个办了信用卡的人是否会违约”,就是是vs否(1%:99%)的比例。这种分类状况下,即便模型什么也不做,全把结果预测成“否”,正确率也能有99%。因此我们要使用 class_weight 参数对样本标签进行一定均衡,给少量的标签更多的权重,让模型更偏向少数类,向捕获少数类的方向建模。该参数默认 None,此模式表示自动给 与数据集中的所有标签相同的权重。

有了权重之后,样本量就不再是单纯地记录数目,而是受输入的权重影响了,因此这时候剪枝,就需要搭配 min_weight_fraction_leaf 这个基于权重的剪枝参数来使用。另请注意,基于权重的剪枝参数(例如 min_weight_fraction_leaf)将比不知道样本权重的标准(比如 min_samples_leaf )更少偏向主导类。如果样本是加权的,则使用基于权重的预修剪标准来更容易优化树结构,这确保叶节点至少包含样本权重的总和的一小部分。

重要属性和接口

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

sklearn 中许多算法的接口都是相似的,比如说我们之前已经用到的 fit 和 score,几乎对每个算法都可以使用。除了这两个接口之外,决策树最常用的接口还有 apply 和 predict。apply 中输入测试集返回每个测试样本所在的叶子节点的索引,predict 输入测试集返回每个测试样本的标签。返回的内容一目了然并且非常容易,大家感兴趣可以自己下去试试看。

  1. #apply 返回每个测试样本所在的叶子节点的索引
  2. clf.apply(Xtest)
  3. #predict 返回每个测试样本的分类/回归结果
  4. clf.predict(Xtest)