一、决策树:
包中所包含的各种树;
1.1 建模流程:
- 这个流程适用于所有的模型:
第一步要知道使用函数的参数有些啥;
第二步就是找哪个接口来用,几乎所有都可以用 fit 接口;
第三步就是根据指标对生成的模型进行打分;
- 分类树对应代码:
1.1.2 分类树 与红酒数据集
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)
1.1.2.1 重要参数
(1)criterion
- 作用: 决定不纯度(类似于熵)的 计算方法 :
(1)输入“entropy”,使用信息熵;
(2)输入“gini”,使用基尼指数;
他俩对应的算法:
比起基尼系数,信息熵对不纯度更加敏感,对不纯度的惩罚最强。但是在实际使用中,信息熵和基尼系数的效果基本相同。
- 这个参数的影响:
- 决策树的基本流程:
1.导入需要的库和模块
from sklearn import tree
#用于生成数据集的模块,dataset是自带的一个数据库,里头有很多数据
from sklearn.datasets import load_wine
#导入训练集和测试集的类
from sklearn.model_selection import train_test_split
2.探索数据
import pandas as pd
#把特征矩阵和标签变成一张表,axis参数是用来连接的
pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1)
- 分训练/测试集
#这里要注意前面的循序,test_size=0.3说明30%做测试机,70%做训练集;
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)
# f/target_names可以用来在构建决策树的时候作为分割点的提示
wine.feature_names
wine.target_names
4.建立模型clf
clf = tree.DecisionTreeClassifier(criterion="entropy") #实例化
clf = clf.fit(Xtrain, Ytrain) #fit就是拿来训练的接口
score = clf.score(Xtest, Ytest) #返回预测准确度
score #训练集和测试集随即划分,所以得到的结果是不一样的
5.画出决策树
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜色强度','色调','od280/od315稀释葡萄酒','脯氨酸']
import graphviz
#clf参数是上面训练好的模型;feature_names是特征名字;class_names是标签的名字,前面默认是0,1,2;filled是框的颜色,round是框的形状;
dot_data = tree.export_graphviz(clf
,out_file = None
,feature_names = feature_name
,class_names=["琴酒","雪莉","贝尔摩德"]
,filled=True
,rounded=True
)
graph = graphviz.Source(dot_data)
graph
6.探索决策树
#特征重要性,有用的话就有值,不然就是0
clf.feature_importances_
#把重要性和对应的名字连接起来
[*zip(feature_name,clf.feature_importances_)]
#结果为:
#[('酒精', 0.0),
# ('苹果酸', 0.0),
# ('灰', 0.03424265229804312),
# ('灰的碱性', 0.0),
# ('镁', 0.0),
# ('总酚', 0.0),
# ('类黄酮', 0.4212422739689356),
# ('非黄烷类酚类', 0.0),
# ('花青素', 0.0),
# ('颜色强度', 0.24875172479063973),
# ('色调', 0.0),
# ('od280/od315稀释葡萄酒', 0.0),
# ('脯氨酸', 0.2957633489423816)]
#用random_state来控制随机性,是来设置分枝中的随机模式的参数
clf = tree.DecisionTreeClassifier(criterion="entropy",random_state=30)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) #返回预测的准确度
score
#0.9629629629629629(这里的值会因为每次选的训练/测试集不同而发生变化)
不难看出,由于每次选的训练/测试集不同而导致这个模型的得分每次都不一样,这对于实际应用来说十分不利,所以就有了下面的这个玩意儿;
(2)random_state & splitter
- 作用:
(1)random_state用来设置分枝中的随机模式的参数,默认None,在高维度时随机性会表现更明显,低维度的数据(比如鸢尾花数据集),随机性几乎不会显现。输入任意整数,会一直长出同一棵树,让模型稳定下来;
(2)splitter用来控制决策树中的随机选项的,有两种输入值,输入”best",决策树在分枝时虽然随机,但是还是会优先选择更重要的特征进行分枝(重要性可以通过属性feature_importances_查看),输入“random",决策树在分枝时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合;
clf = tree.DecisionTreeClassifier(criterion="entropy"
,random_state=30
,splitter="random"
)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest)
score
#0.9259259259259259(不会变了,是从一大堆中选出最优的那个)
import graphviz
dot_data = tree.export_graphviz(clf
,feature_names= feature_name
,class_names=["琴酒","雪莉","贝尔摩德"]
,filled=True
,rounded=True
)
graph = graphviz.Source(dot_data)
graph
由于增加了随机性所以这个树变得很大
(3)剪枝参数
- 作用:为了让决策树有更好的泛化性,sklearn为我们提供了不同的剪枝策略:
- max_depth:限制树的最大深度,超过设定深度的树枝全部剪掉,建议从3开始用;
- min_samples_leaf & min_samples_split:
(1)min_samples_leaf(分支后)限定,一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生,一般从5开始用。如果叶节点中含有的样本量变化很大,建议输入浮点数作为样本量的百分比来使用。同时,这个参数可以保证每个叶子的最小尺寸,可以在回归问题中避免低方差,过拟合的叶子节点出现。对于类别不多的分类问题,=1通常就是最佳选择(不绝对);
(2)min_samples_split(分支前)限定,一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分枝,否则分枝就不会发生;
#对前面得到的决策树进行剪枝:
clf = tree.DecisionTreeClassifier(criterion="entropy"
,random_state=30
,splitter="random"
,max_depth=3
#,min_samples_leaf=10
#,min_samples_split=10
)
clf = clf.fit(Xtrain, Ytrain)
dot_data = tree.export_graphviz(clf
,feature_names= feature_name
,class_names=["琴酒","雪莉","贝尔摩德"]
,filled=True
,rounded=True
)
graph = graphviz.Source(dot_data)
graph
生成的树就是:
clf.score(Xtrain,Ytrain)
#0.9596774193548387
clf.score(Xtest,Ytest)
#0.9444444444444444
#发现此时的准确率竟然比之前的要高。。。说明下面那些没用的
max_features & min_impurity_decrease:
(1)max_features限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃,但其方法比较暴力,是直接限制可以使用的特征数量而强行使决策树停下的参数,可能省去一些比较重要的参数;
(2)min_impurity_decrease限制信息增益的大小,信息增益小于设定数值的分枝不会发生;确认最优的剪枝参数:用超参数的学习曲线来进行确认,是一条以超参数的取值为横坐标,模型的度量指标为纵坐标的曲线,它是用来衡量不同超参数取值下模型的表现的线:
#专门用来可视化的模块
import matplotlib.pyplot as plt
test = []
#利用for循环建模后测试其在测试集上的表现并绘制学习曲线
for i in range(10):
clf = tree.DecisionTreeClassifier(max_depth=i+1
,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()
- 问题:
- 剪枝参数一定能够提升模型在测试集上的表现吗? - 调参没有绝对的答案,一切都是看数据本身;
- 这么多参数,一个个画学习曲线? - 在泰坦尼克号的案例中,我们会解答这个问题。
(4)目标权重参数:
- class_weight & min_weight_fraction_leaf:(这俩很少用
(1)class_weight完成样本标签平衡的参数。样本不平衡是指在一组数据集中,标签的一类天生占有很大的比例。使用class_weight参数对样本标签进行一定的均衡,给少量的标签更多的权重,让模型更偏向少数类,向捕获少数类的方向建模,默认是None,此模式表示自动给与数据集中的所有标签相同的权重;
(2)min_weight_fraction_leaf基于权重的剪枝参数,有了权重之后,样本量就不再是单纯地记录数目,而是受输入的权重影响了,所以这时候剪枝就要配合这个一起用了;
1.1.3 重要属性和接口
- fit、score**:前面用过了,不想再说了;
- apply:返回每个测试样本所在的叶子节点的索引;
- predict:返回每个测试样本的分类/回归结果;
上面这两个接口只输入测试集的特征,而不需要标签
注意:所有接口中要求输入X_train和X_test的部分,输入的特征矩阵必须至少是一个二维矩阵。sklearn不接受任何一维矩阵作为特征矩阵被输入,如果真就硬塞给只有一个特征,那必须用reshape(-1,1)来给矩阵增维;如果你的数据只有一个特征和一个样本,使用reshape(1,-1)来给你的数据增维;
总结
- 八个参数:Criterion,两个随机性相关的参数(random_state,splitter),五个剪枝参数(max_depth,min_samples_split,min_samples_leaf,max_feature,min_impurity_decrease);
- 一个属性:feature_importances_
- 四个接口:fit,score,apply,predict
1.2 回归树
classsklearn.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)
- 几乎所有参数,属性及接口都和分类树一模一样。需要注意的是,在回归树种,没有标签分布是否均衡的问题,因此没有class_weight这样的参数。
1.2.1 重要参数、接口
(1)criterion:
- 作用:回归树衡量分枝质量的指标;
- 支持的标准:
1.输入"mse"使用均方误差mean squared error(MSE),父节点和叶子节点之间的均方误差的差额将被用来作为特征选择的标准,这种方法通过使用叶子节点的均值来最小化L2损失;
2.输入“friedman_mse”使用费尔德曼均方误差,这种指标使用弗里德曼 针对潜在分枝中的问题改进后 的均方误差;
3.输入"mae"使用绝对平均误差MAE(mean absolute error),这种指标使用 叶节点的中值 来最小化L1损失属性中最重要的依然是feature_importances_,接口依然是apply, fit, predict, score最核心。
在回归中,我们追求的是,MSE越小越好。然而,回归树的接口score返回的是R平方,并不是MSE。R平方被定义如下:
其中u是残差平方和(MSE * N),v是总平方和,N是样本数量,i是每一个数据样本,fi是模型回归出的数值,yi是样本点i实际的数值标签。y帽是真实数值标签的平均数。R2可以为正为负(如果模型的残差平方和远远大于模型的总平方和,模型非常糟糕,R平方就会为负),而均方误差永远为正。
注意: 虽然均方误差永远为正,但是sklearn当中使用均方误差作为评判标准时,却是计算”负均方误差“(neg_mean_squared_error),而真正的均方误差MSE的数值,其实就是neg_mean_squared_error去掉负号的数;
(2)交叉验证:默认就是k折交叉验证:
#用波士顿房价数据,因为回归型用的是连续变量
from sklearn.datasets import load_boston
#直接调用cross_val_score方法来进行交叉验证
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeRegressor
boston = load_boston()
regressor = DecisionTreeRegressor(random_state=0)
#前三个给没啥好说的,第四个就是k;第五个是指明衡量标准
cross_val_score(regressor, boston.data, boston.target, cv=10,
scoring = "neg_mean_squared_error")
#交叉验证cross_val_score的用法
输出结果为:
不写 scoring = "neg_mean_squared_error"的话就是越接近1的越好;写了之后就是越接近0越好
1.2.2 案例:一维回归的图像绘制
- 1.导入需要的库
#numpy用于生成图上曲线
import numpy as np
from sklearn.tree import DecisionTreeRegressor
#画图的
import matplotlib.pyplot as plt
- 2.创造一条含有噪声的曲线
#用numpy生成一个随机树的种子,但是是是一种固定的随机
rng = np.random.RandomState(1)
#生成随机树,下面这个函数随机生成0到1之间随机树
5*rng.rand(80,1)
#生成二维的树是为了能够进行拟合(接口不允许一维的特征)
#np.sort()用来排序,从小到大排序,X就是横坐标的数据
X = np.sort(5 * rng.rand(80,1), axis=0)
#用sin函数来求y,因为y只能是一维的,所以要用ravel函数来进行降维
y = np.sin(X).ravel()
此时所的图像为:
加噪声,模拟现实的抽样状况(通过给其某些数据加上/减去一个值来进行)
#::是用来切片的,5表示步长
y[::5] += 3 * (0.5 - rng.rand(16))
#为了构建一个通用性高的模型,所以要避免对这些有噪声的点进行拟合
此时所的图像为:
3.实例化&训练模型
#建两个模拟,用来区别不同条件下的拟合情况
regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_1.fit(X, y)
regr_2.fit(X, y)
4.测试集导入模型,预测结果
#了解增维切片np.newaxis的用法
#这里在对测试集进行增维,必要是二维的
l = np.array([1,2,3,4])
l.shape
#(4,)
l[:,np.newaxis]
#array([[1],[2],[3],[4]])
l[:,np.newaxis].shape
#(4, 1)
l[np.newaxis,:].shape
#(1, 4)
#arange(开始点,结束点,步长)大于等于开始点,小于结束点
#测试集是用arange生成的一堆随机数
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)
#np.arrange(开始点,结束点,步长) 生成有序数组的函数#测试集是用arange生成的一堆随机数
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)
#np.arrange(开始点,结束点,步长) 生成有序数组的函数
5.绘制图像
#对于matplotlib的具体应用
#figure是弄了块画布
plt.figure()
#c是点的颜色,label就是点的名字,s是点的大小
plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data")
#plot是画折线的,label是线的名字,可输入也可以不输入
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参数控制)设置得太高,则决策树学习得太精细,它从训练数据中学了很多细节,包括噪声得呈现,从而使模型偏离真实的正弦曲线,形成过拟合。
1.3 实例:泰坦尼克号幸存者的预测
去看看jupyter的代码部分