决策树


文章目录

  • 决策树
  • 一、决策树[sklearn.tree]
  • 二、DecisionTreeClassifier[分类树]
    • [criterion]:
    • [random_state][splitter]:
    • [剪枝参数-max_depth、min_samples_leaf、min_samples_split……]:
    • [目标权重参数-class_weight、min_weight_fraction_leaf]:
    • 重要的属性和接口:
  • 三、DecisionTreeRegressor[回归树]
    • [criterion]:
    • 交叉验证:
    • 回归实例
  • 实例:泰坦尼克号幸存者预测
    • 数据处理
    • 初步训练
    • 网格搜索

一、决策树[sklearn.tree]

【开发环境:jupyterLab】
sklearn.tree的决策树模块中包含5类:

sklearn.tree的基本建模流程:

二、DecisionTreeClassifier[分类树]

class sklearn.tree.DecisionTreeClassifier (criterion=’gini’, splitter=’best’, 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, min_impurity_split=None,
class_weight=None, presort=False)

以上是分类树的所有参数,我们重点学习几个:

[criterion]:

为了要将表格转化为一棵树,决策树需要找出最佳节点和最佳的分枝方法,对分类树来说,衡量这个“最佳”的指标叫做“不纯度”。通常来说,不纯度越低,决策树对训练集的拟合越好。现在使用的决策树算法在分枝方法上的核心大多是围绕在对某个不纯度相关指标的最优化上。

不纯度基于节点来计算,树中的每个节点都会有一个不纯度,并且子节点的不纯度一定是低于父节点的,也就是说,在同一棵决策树上,叶子节点的不纯度一定是最低的。

Criterion这个参数正是用来决定不纯度的计算方法的。sklearn提供了两种选择:

比起基尼系数,信息熵对不纯度更加敏感,对不纯度的惩罚最强。但是在实际使用中,信息熵和基尼系数的效果基本相同。信息熵的计算比基尼系数缓慢一些,因为基尼系数的计算不涉及对数。另外,因为信息熵对不纯度更加敏感,所以信息熵作为指标时,决策树的生长会更加“精细”,因此对于高维数据或者噪音很多的数据,信息熵很容易过拟合,基尼系数在这种情况下效果往往比较好。当模型拟合程度不足的时候,即当模型在训练集和测试集上都表现不太好的时候,使用信息熵。当然,这些不是绝对的。


建立一棵树:

from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
wine=load_wine()
wine
结果:{'data': array([[1.423e+01, 1.710e+00, 2.430e+00, ..., 1.040e+00, 3.920e+00,1.065e+03],[1.320e+01, 1.780e+00, 2.140e+00, ..., 1.050e+00, 3.400e+00,1.050e+03],[1.316e+01, 2.360e+00, 2.670e+00, ..., 1.030e+00, 3.170e+00,1.185e+03],...,[1.327e+01, 4.280e+00, 2.260e+00, ..., 5.900e-01, 1.560e+00,8.350e+02],[1.317e+01, 2.590e+00, 2.370e+00, ..., 6.000e-01, 1.620e+00,8.400e+02],[1.413e+01, 4.100e+00, 2.740e+00, ..., 6.100e-01, 1.600e+00,5.600e+02]]),'target': array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,2, 2]),'target_names': array(['class_0', 'class_1', 'class_2'], dtype='<U7'),'DESCR': '.. _wine_dataset:\n\nWine recognition dataset\n------------------------\n\n**Data Set Characteristics:**\n\n    :Number of Instances: 178 (50 in each of three classes)\n    :Number of Attributes: 13 numeric, predictive attributes and the class\n    :Attribute Information:\n \t\t- Alcohol\n \t\t- Malic acid\n \t\t- Ash\n\t\t- Alcalinity of ash  \n \t\t- Magnesium\n\t\t- Total phenols\n \t\t- Flavanoids\n \t\t- Nonflavanoid phenols\n \t\t- Proanthocyanins\n\t\t- Color intensity\n \t\t- Hue\n \t\t- OD280/OD315 of diluted wines\n \t\t- Proline\n\n    - class:\n            - class_0\n            - class_1\n            - class_2\n\t\t\n    :Summary Statistics:\n    \n    ============================= ==== ===== ======= =====\n                                   Min   Max   Mean     SD\n    ============================= ==== ===== ======= =====\n    Alcohol:                      11.0  14.8    13.0   0.8\n    Malic Acid:                   0.74  5.80    2.34  1.12\n    Ash:                          1.36  3.23    2.36  0.27\n    Alcalinity of Ash:            10.6  30.0    19.5   3.3\n    Magnesium:                    70.0 162.0    99.7  14.3\n    Total Phenols:                0.98  3.88    2.29  0.63\n    Flavanoids:                   0.34  5.08    2.03  1.00\n    Nonflavanoid Phenols:         0.13  0.66    0.36  0.12\n    Proanthocyanins:              0.41  3.58    1.59  0.57\n    Colour Intensity:              1.3  13.0     5.1   2.3\n    Hue:                          0.48  1.71    0.96  0.23\n    OD280/OD315 of diluted wines: 1.27  4.00    2.61  0.71\n    Proline:                       278  1680     746   315\n    ============================= ==== ===== ======= =====\n\n    :Missing Attribute Values: None\n    :Class Distribution: class_0 (59), class_1 (71), class_2 (48)\n    :Creator: R.A. Fisher\n    :Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)\n    :Date: July, 1988\n\nThis is a copy of UCI ML Wine recognition datasets.\nhttps://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data\n\nThe data is the results of a chemical analysis of wines grown in the same\nregion in Italy by three different cultivators. There are thirteen different\nmeasurements taken for different constituents found in the three types of\nwine.\n\nOriginal Owners: \n\nForina, M. et al, PARVUS - \nAn Extendible Package for Data Exploration, Classification and Correlation. \nInstitute of Pharmaceutical and Food Analysis and Technologies,\nVia Brigata Salerno, 16147 Genoa, Italy.\n\nCitation:\n\nLichman, M. (2013). UCI Machine Learning Repository\n[https://archive.ics.uci.edu/ml]. Irvine, CA: University of California,\nSchool of Information and Computer Science. \n\n.. topic:: References\n\n  (1) S. Aeberhard, D. Coomans and O. de Vel, \n  Comparison of Classifiers in High Dimensional Settings, \n  Tech. Rep. no. 92-02, (1992), Dept. of Computer Science and Dept. of  \n  Mathematics and Statistics, James Cook University of North Queensland. \n  (Also submitted to Technometrics). \n\n  The data was used with many others for comparing various \n  classifiers. The classes are separable, though only RDA \n  has achieved 100% correct classification. \n  (RDA : 100%, QDA 99.4%, LDA 98.9%, 1NN 96.1% (z-transformed data)) \n  (All results using the leave-one-out technique) \n\n  (2) S. Aeberhard, D. Coomans and O. de Vel, \n  "THE CLASSIFICATION PERFORMANCE OF RDA" \n  Tech. Rep. no. 92-01, (1992), Dept. of Computer Science and Dept. of \n  Mathematics and Statistics, James Cook University of North Queensland. \n  (Also submitted to Journal of Chemometrics).\n','feature_names': ['alcohol','malic_acid','ash','alcalinity_of_ash','magnesium','total_phenols','flavanoids','nonflavanoid_phenols','proanthocyanins','color_intensity','hue','od280/od315_of_diluted_wines','proline']}
wine.data
wine.data.shape
结果:(178, 13)
import pandas as pd
pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1)
结果:
0   1   2   3   4   5   6   7   8   9   10  11  12  0
0   14.23   1.71    2.43    15.6    127.0   2.80    3.06    0.28    2.29    5.64    1.04    3.92    1065.0  0
1   13.20   1.78    2.14    11.2    100.0   2.65    2.76    0.26    1.28    4.38    1.05    3.40    1050.0  0
2   13.16   2.36    2.67    18.6    101.0   2.80    3.24    0.30    2.81    5.68    1.03    3.17    1185.0  0
3   14.37   1.95    2.50    16.8    113.0   3.85    3.49    0.24    2.18    7.80    0.86    3.45    1480.0  0
4   13.24   2.59    2.87    21.0    118.0   2.80    2.69    0.39    1.82    4.32    1.04    2.93    735.0   0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
173 13.71   5.65    2.45    20.5    95.0    1.68    0.61    0.52    1.06    7.70    0.64    1.74    740.0   2
174 13.40   3.91    2.48    23.0    102.0   1.80    0.75    0.43    1.41    7.30    0.70    1.56    750.0   2
175 13.27   4.28    2.26    20.0    120.0   1.59    0.69    0.43    1.35    10.20   0.59    1.56    835.0   2
176 13.17   2.59    2.37    20.0    120.0   1.65    0.68    0.53    1.46    9.30    0.60    1.62    840.0   2
177 14.13   4.10    2.74    24.5    96.0    2.05    0.76    0.56    1.35    9.20    0.61    1.60    560.0   2
178 rows × 14 columns
xtrain,xtest,ytrain,ytest=train_test_split(wine.data,wine.target,test_size=0.3)
clf=tree.DecisionTreeClassifier(criterion="gini",random_state=20,splitter="random")
clf=clf.fit(xtrain,ytrain)
score=clf.score(xtest,ytest)
score
结果:0.9814814814814815
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜色强度','色调','od280/od315稀释葡萄酒','脯氨酸']
class_name=["A_wine","B_wine","C_wine"]
import graphviz
dot_data=tree.export_graphviz(clf,feature_names=feature_name,class_names=class_name,filled=True,rounded=True)
graph=graphviz.Source(dot_data)
graph

结果:

clf.feature_importances_
[*zip(feature_name,clf.feature_importances_)]
结果:
[('酒精', 0.023112431230183247),('苹果酸', 0.023247914985203153),('灰', 0.0),('灰的碱性', 0.02001614205004035),('镁', 0.0),('总酚', 0.0),('类黄酮', 0.17143089634271227),('非黄烷类酚类', 0.0),('花青素', 0.0),('颜色强度', 0.024361751837220145),('色调', 0.04728813559322035),('od280/od315稀释葡萄酒', 0.25760847619945554),('脯氨酸', 0.432934251761965)]

[random_state][splitter]:

我们已经在只了解一个参数的情况下,建立了一棵完整的决策树。但是回到4建立模型,score会在某个值附近波动,引起画出来的每一棵树都不一样。它为什么会不稳定呢?如果使用其他数据集,它还会不稳定吗?我们之前提到过,无论决策树模型如何进化,在分枝上的本质都还是追求某个不纯度相关的指标的优化,而正如我们提到的,不纯度是基于节点来计算的,也就是说,决策树在建树时,是靠优化节点来追求一棵优化的树,但最优的节点能够保证最优的树吗?集成算法被用来解决这个问题:sklearn表示,既然一棵树不能保证最优,那就建更多的不同的树,然后从中取最好的。怎样从一组数据集中建不同的树?在每次分枝时,不从使用全部特征,而是随机选取一部分特征,从中选取不纯度相关指标最优的作为分枝用的节点。这样,每次生成的树也就不同了。

也就是说对于每个人来说实际上虽然train_test_split是随机划分数据集,但是毕竟只执行了一次,也就说仅初始化随机了一次,但是正是由于sklearn的集成思路,随机挑选部分特征进行不纯度的计算,导致了这里的随机化,那么会造成模型的不稳定,random_state就是解决这个问题的,相同的splitter也是为挑选不纯度指标最优而服务的。random_state用来设置分枝中的随机模式的参数,默认None,在高维度时随机性会表现更明显,低维度的数据(比如鸢尾花数据集),随机性几乎不会显现。输入任意整数,会一直长出同一棵树,让模型稳定下来。

splitter也是用来控制决策树中的随机选项的,有两种输入值,输入”best",决策树在分枝时虽然随机,但是还是会优先选择更重要的特征进行分枝(重要性可以通过属性feature_importances_查看),输入“random",决策树在分枝时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合。这也是防止过拟合的一种方式。当你预测到你的模型会过拟合,用这两个参数来帮助你降低树建成之后过拟合的可能性。当然,树一旦建成,我们依然是使用剪枝参数来防止过拟合。

[剪枝参数-max_depth、min_samples_leaf、min_samples_split……]:

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

为了让决策树有更好的泛化性,我们要对决策树进行剪枝。剪枝策略对决策树的影响巨大,正确的剪枝策略是优化决策树算法的核心。sklearn为我们提供了不同的剪枝策略:
max_depth
限制树的最大深度,超过设定深度的树枝全部剪掉这是用得最广泛的剪枝参数,在高维度低样本量时非常有效。决策树多生长一层,对样本量的需求会增加一倍,所以限制树深度能够有效地限制过拟合。在集成算法中也非常实用。实际使用时,建议从=3开始尝试,看看拟合的效果再决定是否增加设定深度。

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

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

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

min_impurity_decrease
限制信息增益的大小,信息增益小于设定数值的分枝不会发生。这是在0.19版本中更新的功能,在0.19版本之前时使用min_impurity_split。

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

import matplotlib.pyplot as plt
test=[]
for i  in range(10):clf=tree.DecisionTreeClassifier(criterion="gini",random_state=20,splitter="random",max_depth=i+1)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. 剪枝参数一定能够提升模型在测试集上的表现吗? - 调参没有绝对的答案,一切都是看数据本身。
  2. 这么多参数,一个个画学习曲线? - 在之后回归树的学习中,我们会解答这个问题。

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

[目标权重参数-class_weight、min_weight_fraction_leaf]:

完成样本标签平衡的参数。样本不平衡是指在一组数据集中,标签的一类天生占有很大的比例。比如说,在银行要判断“一个办了信用卡的人是否会违约”,就是是vs否(1%:99%)的比例。这种分类状况下,即便模型什么也不做,全把结果预测成“否”,正确率也能有99%。因此我们要使用class_weight参数对样本标签进行一定的均衡,给少量的标签更多的权重,让模型更偏向少数类,向捕获少数类的方向建模。该参数默认None,此模式表示自动给与数据集中的所有标签相同的权重。有了权重之后,样本量就不再是单纯地记录数目,而是受输入的权重影响了,因此这时候剪枝,就需要搭配min_weight_fraction_leaf这个基于权重的剪枝参数来使用。另请注意,基于权重的剪枝参数(例如min_weight_fraction_leaf)将比不知道样本权重的标准(比如min_samples_leaf)更少偏向主导类。如果样本是加权的,则使用基于权重的预修剪标准来更容易优化树结构,这确保叶节点至少包含样本权重的总和的一小部分。

重要的属性和接口:

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

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

在这里不得不提的是,所有接口中要求输入X_train和X_test的部分,输入的特征矩阵必须至少是一个二维矩阵。sklearn不接受任何一维矩阵作为特征矩阵被输入。如果你的数据的确只有一个特征,那必须用reshape(-1,1)来给矩阵增维;如果你的数据只有一个特征和一个样本,使用reshape(1,-1)来给你的数据增维。

分类树天生不擅长环形数据。每个模型都有自己的决策上限,所以一个怎样调整都无法提升表现的可能性也是有的。当一个模型怎么调整都不行的时候,我们可以选择换其他的模型使用,不要在一棵树上吊死。顺便一说,最擅长月亮型数据的是最近邻算法,RBF支持向量机和高斯过程;最擅长环形数据的是最近邻算法和高斯过程;最擅长对半分的数据的是朴素贝叶斯,神经网络和随机森林。

三、DecisionTreeRegressor[回归树]

class sklearn.tree.DecisionTreeRegressor (criterion=’mse’, splitter=’best’, 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, min_impurity_split=None, presort=False)

这里的参数实际上都很眼熟,但要注意的是,回归树涉及到的是回归的问题,是连续值的变化,而我们的分类树是分类的离散变量,所以回归树不存在一个数据集不平衡的问题,设计分类树的不平衡参数在这里是没有的。

[criterion]:

回归树衡量分枝质量的指标,支持的标准有三种:
1)输入"mse"使用均方误差mean squared error(MSE),父节点和叶子节点之间的均方误差的差额将被用来作为特征选择的标准,这种方法通过使用叶子节点的均值来最小化L2损失
2)输入“friedman_mse”使用费尔德曼均方误差,这种指标使用弗里德曼针对潜在分枝中的问题改进后的均方误差
3)输入"mae"使用绝对平均误差MAE(mean absolute error),这种指标使用叶节点的中值来最小化L1损失

属性中最重要的依然是feature_importances_,接口依然是apply, fit, predict, score最核心。

其中N是样本数量,i是每一个数据样本,fi是模型回归出的数值,yi是样本点i实际的数值标签。所以MSE的本质,其实是样本真实数据与回归结果的差异。在回归树中,MSE不只是我们的分枝质量衡量指标,也是我们最常用的衡量回归树回归质量的指标,当我们在使用交叉验证,或者其他方式获取回归树的结果时,我们往往选择均方误差作为我们的评估(在分类树中这个指标是score代表的预测准确率)。在回归中,我们追求的是,MSE越小越好。然而,回归树的接口score返回的是R平方,并不是MSE。R平方被定义如下:

其中u是残差平方和(MSE * N),v是总平方和,N是样本数量,i是每一个数据样本,fi是模型回归出的数值,yi是样本点i实际的数值标签。y帽是真实数值标签的平均数。R平方可以为正为负(如果模型的残差平方和远远大于模型的总平方和,模型非常糟糕,R平方就会为负),而均方误差永远为正。

值得一提的是,虽然均方误差永远为正,但是sklearn当中使用均方误差作为评判标准时,却是计算”负均方误差“(neg_mean_squared_error)。这是因为sklearn在计算模型评估指标的时候,会考虑指标本身的性质,均方误差本身是一种误差,所以被sklearn划分为模型的一种损失(loss),因此在sklearn当中,都以负数表示。真正的均方误差MSE的数值,其实就是neg_mean_squared_error去掉负号的数字。

交叉验证:

交叉验证是用来观察模型的稳定性的一种方法,我们将数据划分为n份,依次使用其中一份作为测试集,其他n-1份作为训练集,多次计算模型的精确性来评估模型的平均准确程度。训练集和测试集的划分会干扰模型的结果,因此用交叉验证n次的结果求出的平均值,是对模型效果的一个更好的度量。

类比来看,在划分数据集的时候,我们有说,train_test_split是随机化数据集的,也就是说我们模型不管是多高的精度,都只是说在这一个数据集划分训练和测试集的基础之上,那么问题就来了,我们怎么知道,有很多种划分的方式,我们不知道这么划分得到的结果跟其他划分方式的效果差多少,也就是我们没法通过一次划分去保证该模型的稳定性,例如我选了最好的种子,用最好的条件,但树不一定长得最好,我不如选一堆种子,从种子中再找出最后长得最好的树,这样来得更靠谱,再这里就是“交叉验证”。

from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeRegressor
boston=load_boston()
regressor=DecisionTreeRegressor(random_state=0)
cross_val_score(regressor,boston.data,boston.target,cv=10,scoring="neg_mean_squared_error")
array([-16.41568627, -10.61843137, -18.30176471, -55.36803922,-16.01470588, -44.70117647, -12.2148    , -91.3888    ,-57.764     , -36.8134    ])

在实例化对象的时候,第一个参数是模型,无论是分类树、回归树等其他模型,之后两个是完整数据与完整标签,该函数会自动划分,cv表示交叉验证的次数,划分的份数,最后如果不指明返回的验证指标,默认是R^2,这里我们用neg_mean_squared_error表示直接用均方差作为指标,因为在上面说sklearn会自动把指标性质归类,均方差被归类为loss损失马,所以会是负数。

回归实例

要注意的一个问题是,对于sklearn来说你的数据要是二维,如果你的数据是一维或者单个数据依然要选择增维处理,但对于标签而言,则应该是一维的,选择降维(ravel())。我们用回归树来拟合正弦曲线,并添加一些噪声来观察回归树的表现:

在这一步,我们的基本思路是,先创建一组随机的,分布在0~5上的横坐标轴的取值(x),然后将这一组值放到sin函数中去生成纵坐标的值(y),接着再到y上去添加噪声。全程我们会使用numpy库来为我们生成这个正弦曲线。

import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
rng=np.random.RandomState(1)
x=np.sort(5*rng.rand(80,1),axis=0)
y=np.sin(x).ravel()
plt.figure()
plt.scatter(x,y)

y[::5]+=3*(0.5-rng.rand(16))
plt.figure()
plt.scatter(x,y)


我们开始用fit接口训练模型

reg_1=DecisionTreeRegressor(max_depth=3)
reg_2=DecisionTreeRegressor(max_depth=5)
reg_1.fit(x,y)
reg_2.fit(x,y)
结果:
DecisionTreeRegressor(ccp_alpha=0.0, criterion='mse', max_depth=5,max_features=None, max_leaf_nodes=None,min_impurity_decrease=0.0, min_impurity_split=None,min_samples_leaf=1, min_samples_split=2,min_weight_fraction_leaf=0.0, presort='deprecated',random_state=None, splitter='best')
x_test=np.arange(0.0,5.0,0.01)[:,np.newaxis]
y_1=reg_1.predict(x_test)
y_2=reg_2.predict(x_test)
plt.figure()
plt.scatter(x,y,s=20,label="data")
plt.plot(x_test,y_1,label="max_depth=3",linewidth=2)
plt.plot(x_test,y_2,label="max_depth=5",linewidth=2)
plt.xlabel("data")
plt.ylabel("target")
plt.legend()
plt.show()


对于蓝色的曲线基本是按照正弦数据的走势在拟合,而橙色的曲线,不难看出说,曲线有些地方按照噪声走势在变化。可见,回归树学习了近似正弦曲线的局部线性回归。我们可以看到,如果树的最大深度(由max_depth参数控制)设置得太高,则决策树学习得太精细,它从训练数据中学了很多细节,包括噪声得呈现,从而使模型偏离真实的正弦曲线,形成过拟合。

实例:泰坦尼克号幸存者预测

我们通过分类树模型来预测一下哪些人可能成为幸存者。数据集来着https://www.kaggle.com/c/titanic,数据集会随着代码一起提供给大家,大家可以在下载页面拿到,
或者到群中询问。数据集包含两个csv格式文件,data为我们接下来要使用的数据,test为kaggle提供的测试集。

数据处理

首先导入我们需要的库:

import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
import numpy as np

本地的data.csv文件,有两种方式导入本地,一种是添加r,另一种是将“\”换成“/”不加r,另外pandas的read_csv()转换成DataFrame的格式:

data = pd.read_csv(r"C:\……\data.csv")#文件路径
data
结果:PassengerId    Survived    Pclass  Name    Sex Age SibSp   Parch   Ticket  Fare    Cabin   Embarked
0   1   0   3   Braund, Mr. Owen Harris male    22.0    1   0   A/5 21171   7.2500  NaN S
1   2   1   1   Cumings, Mrs. John Bradley (Florence Briggs Th...   female  38.0    1   0   PC 17599    71.2833 C85 C
2   3   1   3   Heikkinen, Miss. Laina  female  26.0    0   0   STON/O2. 3101282    7.9250  NaN S
3   4   1   1   Futrelle, Mrs. Jacques Heath (Lily May Peel)    female  35.0    1   0   113803  53.1000 C123    S
4   5   0   3   Allen, Mr. William Henry    male    35.0    0   0   373450  8.0500  NaN S
... ... ... ... ... ... ... ... ... ... ... ... ...
886 887 0   2   Montvila, Rev. Juozas   male    27.0    0   0   211536  13.0000 NaN S
887 888 1   1   Graham, Miss. Margaret Edith    female  19.0    0   0   112053  30.0000 B42 S
888 889 0   3   Johnston, Miss. Catherine Helen "Carrie"  female  NaN 1   2   W./C. 6607  23.4500 NaN S
889 890 1   1   Behr, Mr. Karl Howell   male    26.0    0   0   111369  30.0000 C148    C
890 891 0   3   Dooley, Mr. Patrick male    32.0    0   0   370376  7.7500  NaN Q
891 rows × 12 columns

我们要对数据首先进行分析和整理,例如一些数据的确实,一些数据对于我们的预测是没有用的,还有一些数据,考虑我们的sklearn的训练仅仅支持说我们的数字类型,文字符号等不支持参与训练,所以要做一些转换:

data.info()
结果
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):#   Column       Non-Null Count  Dtype
---  ------       --------------  -----  0   PassengerId  891 non-null    int64  1   Survived     891 non-null    int64  2   Pclass       891 non-null    int64  3   Name         891 non-null    object 4   Sex          891 non-null    object 5   Age          714 non-null    float646   SibSp        891 non-null    int64  7   Parch        891 non-null    int64  8   Ticket       891 non-null    object 9   Fare         891 non-null    float6410  Cabin        204 non-null    object 11  Embarked     889 non-null    object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB

说明:inplace代表是否在原对象上原地修改,axis=1队列进行操作,fillna()填充NaN值,dropna()舍弃,mean()均值,unique()筛选去重,apply()将()的条件应用到data[]中所取的一个个值当中,astype()转换,当自然这里因为性别只有男女两种类型,而且对于男女来说没有一个层次上的关联,比如大学与高中学历,实际上是由着层次关联的,不一定就可以直接转换成0,1这样的分类进行训练。这里可以直接转换:

data.drop(["Cabin","Name","Ticket"],inplace=True,axis=1)
data['Age']=data["Age"].fillna(data["Age"].mean())
data.dropna(axis=0,inplace=True)
labels=data["Embarked"].unique().tolist()
data["Embarked"]=data["Embarked"].apply(lambda x : labels.index(x))
data.loc[:,"Sex"]=(data["Sex"]=='male').astype("int")
# loc是取行和索引所在列,索引是文字
# iloc是取行和列所在,这个时候列直接是数字

划分训练集,注意sklearn中的数据和标签是分开导入的,所以要取出来。而且当随机划分的时候,我们需要在划分完成后,对索引进行一个重新排序,避免后面不必要的麻烦:

x = data.iloc[:,data.columns != "Survived"]
y = data.iloc[:,data.columns == "Survived"]
xtrain,xtest,ytrain,ytest = train_test_split(x,y,test_size=0.3)
for i in [xtrain,xtest,ytrain,ytest]:i.index=range(i.shape[0])

初步训练

clf = DecisionTreeClassifier(random_state=25)
clf = clf.fit(xtrain,ytrain)
score = clf.score(xtest,ytest)
score

直接训练的结果并不好,我们进行调整尝试:

0.7865168539325843
clf = DecisionTreeClassifier(random_state=25)
score = cross_val_score(clf,x,y,cv=10).mean()
score

交叉验证的均值结果反而降低,我们下面要继续进行调参:

0.7469611848825333

尝试画出max_depth超参数曲线:

train=[]
test=[]
for i in range(10):clf = DecisionTreeClassifier(random_state=25,max_depth=i+1,criterion="entropy")clf = clf.fit(xtrain,ytrain)score_train = clf.score(xtrain,ytrain)score_test = cross_val_score(clf,x,y,cv=10).mean()train.append(score_train)test.append(score_test)pass
print(max(test))
plt.figure()
plt.plot(range(1,11),train,color="r",linewidth=2,label="train")
plt.plot(range(1,11),test,color="b",linewidth=2,label="test")
plt.xticks(range(1,11))
plt.legend()
plt.show()

网格搜索

网格搜索实际上比较耗时,还有就是,因为他有多个类型的参数进行交叉搜索,所以要兼顾全部参数,比如我用到两个参数的准确率已经很好了,实际上不加下一个就可以,但是网格搜索依然会对下一个进行挑选,进行组合,反而加上之后,相比之前会准确率有所降低:

#网格搜索 能够帮助我们同时调整多个参数的技术,本质是一种枚举
paramters={"criterion":("entropy","gini"),"splitter":("best","random"),"max_depth":[*range(1,10)],"min_samples_leaf":[*range(1,50,5)],"min_impurity_decrease":np.linspace(0,0.5,20).tolist()
}
clf = DecisionTreeClassifier(random_state=25)
GS = GridSearchCV(clf,paramters,cv=10)
GS = GS.fit(xtrain,ytrain)
GS.best_params_
{'criterion': 'entropy','max_depth': 9,'min_impurity_decrease': 0.0,'min_samples_leaf': 6,'splitter': 'random'}
GS.best_score_
0.8263184843830004

调整之后尝试:

clf = DecisionTreeClassifier(random_state=5,criterion="entropy",max_depth=3,min_samples_leaf=6)
clf = clf.fit(xtrain,ytrain)
score = clf.score(xtest,ytest)
score
0.8014981273408239

HuaPu在学:机器学习——sklearn【决策树】相关推荐

  1. [机器学习-Sklearn]决策树学习与总结 (ID3, C4.5, C5.0, CART)

    决策树学习与总结 (ID3, C4.5, C5.0, CART) 1. 什么是决策树 2. 决策树介绍 3. ID3 算法 信息熵 信息增益 缺点 4. C4.5算法 5. C5.0算法 6. CAR ...

  2. 《菜菜的机器学习sklearn课堂》sklearn入门与决策树

    决策树 sklearn简介 决策树 - 概述 决策树是如何工作的 sklearn中的决策树 分类树 DecisionTreeClassifier 重要参数 criterion 建立一颗树(只有一个参数 ...

  3. 优达学城机器学习之--决策树(Decision Trees)

    前言 决策树(Decision tress)是继朴素贝叶斯(NB),向量机(SVM)之后的另一种监督分类算法(supervised classification algorithm). 决策树已经有几 ...

  4. 菜菜的机器学习sklearn实战-----sklearn入门与决策树

    菜菜的机器学习sklearn实战-----sklearn入门与决策树 菜菜的机器学习sklearn实战-----sklearn入门与决策树 sklearn入门 决策树 概述 决策树是如何工作的 skl ...

  5. 【机器学习】决策树代码练习

    本课程是中国大学慕课<机器学习>的"决策树"章节的课后代码. 课程地址: https://www.icourse163.org/course/WZU-146409617 ...

  6. 《菜菜的机器学习sklearn课堂》聚类算法Kmeans

    聚类算法 聚类算法 无监督学习与聚类算法 sklearn中的聚类算法 KMeans KMeans是如何工作的 簇内误差平方和的定义和解惑 sklearn.cluster.KMeans 重要参数 n_c ...

  7. 《菜菜的机器学习sklearn课堂》逻辑回归

    逻辑回归 概述:名为"回归"的分类器 为什么需要逻辑回归? sklearn中的逻辑回归 linear_model.LogisticRegression 二元逻辑回归的损失函数 损失 ...

  8. 机器学习Sklearn学习总结

    Sklearn学习资料推荐: sklearn中文文档 机器学习入门必看:使用 scikit-learn 构建模型的通用模板 机器学习神器Scikit-Learn保姆教程! python机器学习_FF_ ...

  9. 集成学习精讲之Boosting - SAP大神黄佳新作《零基础学机器学习》节选

    Boosting的意思就是提升,这是一族通过训练弱学习模型的肌肉将其提升为强学习模型的算法.要想在机器学习竞赛中追求卓越,Boosting是一种必须的存在.这是一个属于高手的技术. 图片来源于网上,侵 ...

  10. 集成学习精讲02 - Bagging方法:多个基模型的聚合(SAP大神黄佳新作《零基础学机器学习》节选)

    我们将分为5篇文章介绍集成学习,分别是: 集成学习基础知识:偏差和方差 - 戳此阅读 Bagging - Boosting - 戳此阅读 Stacking/Blending - 戳此阅读 Voting ...

最新文章

  1. 新趋势:工具赋能企业数字化转型,驱动组织升级!
  2. jq 读取office插件_800+页麦肯锡经典图示发送!让你不用插件,轻松搞定逻辑图...
  3. mybatis date类型映射_MapStruct 映射工具
  4. ngnix服务器搭建
  5. 开发环境中实现Lombok消除Java冗余
  6. Kubernetes CRD开发汇总
  7. Windows事件等待学习笔记(三)—— WaitForSingleObject函数分析
  8. 记一次中小公司的研发问题
  9. python里it n_Python3 round(x [,n]) 函数
  10. 游戏会记录某个api的调用_专家坐诊丨老出BUG怎么办?游戏服务器常见问题的解决方法分享...
  11. nginx main error_page
  12. 启动tomcat时 错误: 代理抛出异常 : java.rmi.server.ExportException: Port already in use: 1099的解决办法...
  13. linux 查看是否有led设备,linux驱动开发--字符设备:通过cdd_cdev结构中的led变量区分是哪个节点,private_data使用...
  14. 可能是最高颜值的三方网易云音乐播放器 (全平台支持)
  15. 半车模型悬架系统的simulink仿真
  16. vue项目获取视频封面展示在页面上
  17. 金融工程 | 远期与期货的运用
  18. Java判断日期在指定时间段中的第几周
  19. 新手自媒体推广引流,你能运营好吗?
  20. 求知若饥,虚心若愚——Stay Hungry, Stay Foolish

热门文章

  1. 小白易学--ps钢笔工具抠图教程-大长腿抠图
  2. 25K测试老鸟5年经验的面试心得,四种公司、四种问题…
  3. 3d智慧城市线上3d建模仿真三维模型展示
  4. 图片色彩失真 html,矢量图会失真吗?
  5. Google的非主流功能
  6. 浅谈TCP/IP协议栈(三)路由器简介
  7. easy ui 可编辑表格,新增行某个字段可以修改,已经存在的数据不允许修改
  8. 【C++】Visual Studio C++使用配置Json库文件(老爷式教学)
  9. 保护森林从这里开始-FSC认证
  10. matlab如何画相贯线,相贯线及其画法举例