课程地址:《菜菜的机器学习sklearn课堂》_哔哩哔哩_bilibili
- 第一期:sklearn入门 & 决策树在sklearn中的实现
- 第二期:随机森林在sklearn中的实现
- 第三期:sklearn中的数据预处理和特征工程
- 第四期:sklearn中的降维算法PCA和SVD
- 第五期:sklearn中的逻辑回归
- 第六期:sklearn中的聚类算法K-Means
- 第七期:sklearn中的支持向量机SVM(上)
- 第八期:sklearn中的支持向量机SVM(下)
- 第九期:sklearn中的线性回归大家族
- 第十期:sklearn中的朴素贝叶斯
- 第十一期:sklearn与XGBoost
- 第十二期:sklearn中的神经网络
目录
分类树DecisionTreeClassifier与红酒数据集
(二)random_state & splitter:控制随机性
回归树DecisionTreeRegressor与波士顿房价数据集
sklearn入门
scikit-learn是一个开源的基于Python的机器学习工具包
分析采集到的数据,根据数据特征选择适合的算法,在工具包中调用算法,调整算法的参数,获取需要的信息,从而实现算法效率和效果之间的平衡
解析sklearn的全面应用,了解不同机器学习算法有哪些可调参数、有哪些可用接口,这些接口和参数对算法来说有什么含义,又会对算法的性能及准确性有什么影响 —— 讲解sklearn中对算法的说明、调参、属性、接口,以及实例应用
sklearn官网:scikit-learn: machine learning in Python — scikit-learn 1.2.0 documentation
- 分类、回归、聚类、降维、模型选择、数据预处理
决策树(Decision Tree,DT)
(一)决策树是如何工作的
是一种非参数(不限制数据的结构和类型,几乎可以用它来处理各种各样的数据)的有监督学习(要给标签)方法,能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题
- 以树模型为核心的各种集成算法(如Adaboost、随机森林)
- 本质是一种图结构,只需要问一系列问题就可以对数据进行分类了
决策树算法的核心是要解决两个问题:
- 如何从数据表中找出最佳节点和最佳分枝?(如何找出正确的特征来进行提问?)
定义了用来衡量分枝质量的指标——不纯度,分类树的不纯度用基尼系数或信息熵来衡量,回归树的不纯度用MSE均方误差来衡量
每次分枝时,决策树对所有的特征进行不纯度计算,选取不纯度最低的特征进行分枝,分枝后,又再对被分枝的不同取值下,计算每个特征的不纯度,继续选取不纯度最低的特征进行分枝
- 如何让决策树停止生长,防止过拟合?
每分枝一层,树整体的不纯度会越来越小,决策树追求的是最小不纯度。因此,决策树会一直分枝,直到没有更多的特征可用,或整体的不纯度指标已经最优,决策树就会停止生长
(二)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提供了两种选择:
- entropy:信息熵(实际计算的是基于信息熵的信息增益,即父节点的信息熵和子节点的信息熵之差。子节点的信息熵一定小于父节点,所以信息增益越大,这一层分枝对决策树的贡献就越大),取值范围为0~1
- 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:控制随机性
- random_state:用来设置分枝中的随机模式的参数。输入任意整数,会一直长出同一棵树,让模型稳定下来
- splitter:用来控制决策树中的随机选项,有两种输入值,best(默认)/ random
- best:决策树在分枝时虽然随机,但还是会优先选择更重要的特征进行分枝(重要性可以通过属性 feature_importances_ 查看)
- random:决策树在分枝时会更加随机,树会因为含有更多不必要的信息而更深更大,并因这些不必要的信息而降低对训练集的拟合(也是防止过拟合的一种方式)
树一旦建成,使用剪枝参数来防止过拟合
(三)剪枝参数(5个)
- 在不加限制的情况下,一棵决策树会生长到衡量不纯度的指标最优,或者没有更多的特征可用为止,这样的决策树往往会过拟合(训练集上表现好,测试集上表现差)
- 我们收集的样本数据不可能和整体的状况完全一致,因此,当一棵决策树对训练数据有了过于优秀的解释性,它找出的规则必然包含了训练样本中的噪声,并使它对未知数据的拟合程度不足
- 为了让决策树有更好的泛化性,要对决策树进行剪枝
sklearn为我们提供了不同的剪枝策略:
- max_depth:超过设定深度的树枝全部剪掉。在高维度低样本量时有效,一般从=3开始尝试
- min_samples_leaf:限定一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生,或朝着满足每个子节点都包含min_samples_leaf个样本的方向去发生。设置的太小会引起过拟合,设置的太大会阻止模型学习数据,一般从=5开始使用。如果叶节点中含有的样本量变化很大,输入浮点数作为样本量的百分比来使用
- min_samples_split:限定一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分枝
- max_features:限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃。如果希望通过降维的方式防止过拟合,建议使用PCA、ICA或者特征选择模块中的降维算法
- 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()
(四)目标权重参数(完成样本标签平衡的参数,不常用)
- class_weight:对样本标签进行一定的均衡,给少量的标签更多的权重,让模型更偏向少数类
- 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(回归树衡量分枝质量的指标)
- mse:均方误差(样本真实数据与回归结果的差异)
- friedman_mse:费尔德曼均方误差
- mae:绝对平均误差
在回归树中,MSE不只是分枝质量衡量指标,也是最常用的衡量回归树回归质量的指标
在使用交叉验证获取回归树的结果时,往往选择MSE作为评估(在分类树中是score代表的accuracy)
(二)属性
feature_importances_
(三)接口
score返回的是R²(默认),不是MSE
- 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控制)设置的太高,则决策树学习的太精细,它从训练数据中学了很多细节(包括噪声的呈现),从而使模型偏离真实的正弦曲线,过拟合