参考:菜菜的sklearn课堂
文章目录
参考理论(推荐)
基于数据挖掘的潜在用户行为分析
决策树是一个非常常见并且优秀的机器学习算法,它易于理解、可解释性强,其可作为分类算法,也可用于回归模型。
Github项目-100-Days-Of-ML-Code以及代码
导入需要用到的python库
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
导入数据集
dataset = pd.read_csv('Social_Network_Ads.csv')
X = dataset.iloc[:, [2, 3]].values
y = dataset.iloc[:, 4].values
将数据集拆分为训练集和测试集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)
特征缩放
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
对测试集进行决策树分类拟合
from sklearn.tree import DecisionTreeClassifier
classifier = DecisionTreeClassifier(criterion = 'entropy', random_state = 0)
classifier.fit(X_train, y_train)
预测测试集的结果
y_pred = classifier.predict(X_test)
制作混淆矩阵
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred)
将训练集结果进行可视化
from matplotlib.colors import ListedColormap
X_set, y_set = X_train, y_train
X1, X2 = np.meshgrid(np.arange(start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01),
np.arange(start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01))
plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(), X2.ravel()]).T).reshape(X1.shape),
alpha = 0.75, cmap = ListedColormap(('red', 'green')))
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())
for i, j in enumerate(np.unique(y_set)):
plt.scatter(X_set[y_set == j, 0], X_set[y_set == j, 1],
c = ListedColormap(('red', 'green'))(i), label = j)
plt.title('Decision Tree Classification (Training set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()
将测试集结果进行可视化
from matplotlib.colors import ListedColormap
X_set, y_set = X_test, y_test
X1, X2 = np.meshgrid(np.arange(start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01),
np.arange(start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01))
plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(), X2.ravel()]).T).reshape(X1.shape),
alpha = 0.75, cmap = ListedColormap(('red', 'green')))
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())
for i, j in enumerate(np.unique(y_set)):
plt.scatter(X_set[y_set == j, 0], X_set[y_set == j, 1],
c = ListedColormap(('red', 'green'))(i), label = j)
plt.title('Decision Tree Classification (Test set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()
一、什么是决策树?
决策树,顾名思义就是一个类似于流程图的树型结构。一个决策树由根结点、分支和叶结点构成。树的最高层节点称为根结点,是整个决策树的开始。与根结点相连的不同分支,对应这个属性的不同取值,根据不同的回答转向相应的分支,在新到达的结点处做同样的分支判断,持续这一过程直到到达某个叶结点。在决策树中,每个内部结点表示一个测试,该结点的每个分支表示该测试的一个结果,每个叶结点表示一个类别。
决策树是有监督学习中的一种算法,并且是一种基本的分类与回归的方法。也就是说,决策树有两种:分类树和回归树。
分类树
分类决策树学习本质:从训练数据集中归纳出一组分类规则。
决策树的核心问题
- 如何找出正确的特征来进行提问,即如何分枝
- 树生长到什么时候应该停下
用来衡量分枝质量的指标不纯度,分类树的不纯度用基尼系数或信息熵来衡量,回归
树的不纯度用MSE均方误差来衡量。每次分枝时,决策树对所有的特征进行不纯度计算,选取不纯度最低的特征进行分枝,分枝后,又再对被分枝的不同取值下,计算每个特征的不纯度,继续选取不纯度最低的特征进行分枝。
每分枝一层,树整体的不纯度会越来越小,决策树追求的是最小不纯度。因此,决策树会一致分枝,直到没有更多的特征可用,或整体的不纯度指标已经最优,决策树就会停止生长。
二、主要的算法
建立决策树的关键,即在当前状态下选择哪个属性作为分类依据。根据不同的目标函数,建立决策树主要有以下三种算法。
算法 | 核心 |
---|---|
ID3 | 信息熵 |
C4.5 | 信息增益比 |
CART | 基尼系数 |
2.1 ID3算法
ID3是决策树学习算法中最具有影响和最为典型的算法,它的基本思想是,利用信息熵的原理,选择信息增益最大的属性作为分类属性。
ID3 算法流程图
熵(信息量):在信息论中,是接收的每条信息中包含的信息的平均量。表示随机变量不确定性的度量。熵越大,随机变量的不确定性就越大。
随机变量X的熵定义为:
H ( X ) = − ∑ i = 1 n p i log p i H\left( X \right) =-\sum_{i=1}^n{p_i\log p_i} H(X)=−i=1∑npilogpi
熵一就分类而言,所有成员都属于一类,熵为零;不同类别数目相等,则熵等于1;类别数目不等,则熵介于0~1之间。
熵(信息量)随概率p变化的曲线如下图:
可知,当 p=0 或 p=1 时,H=0,随机变量完全没有不确定性,即是完全确定的。
条件熵:条件熵 H ( Y ∣ X ) H\left( Y|X \right) H(Y∣X)表示在已知随机变量 X 的条件下随机变量 Y 的不确定性。
H ( Y ∣ X ) = ∑ i = 1 n p i H ( Y ∣ X = x i ) , p i = P ( X = x i ) , i = 1 , 2 , ⋯ , n H\left( Y|X \right) =\sum_{i=1}^n{p_iH\left( Y|X=x_i \right)}\ ,\ p_i=P\left( X=x_i \right) \ ,\ i=1,2,\cdots ,n H(Y∣X)=i=1∑npiH(Y∣X=xi) , pi=P(X=xi) , i=1,2,⋯,n
信息增益:信息增益表示得知特征 X 的信息而使得类Y的信息不确定性减少的程度。
特征 A 对训练数据集 D 的信息增益 g ( D , A ) g\left( D,A \right) g(D,A),定义为集合 D 的经验熵 H ( D ) H\left( D \right) H(D) 与特征A给定条件下D的经验条件熵 H(D|A) 之差。
g ( D , A ) = H ( D ) − H ( D ∣ A ) g\left( D,A \right) =H\left( D \right) -H\left( D|A \right) g(D,A)=H(D)−H(D∣A)
根据信息增益准则的特征选择方法是:对训练数据集(或子集D),计算其每个特征的信息增益,并比较它们的大小,选择信息增益最大的特征。
2.2 C4.5 算法
C4.5算法是ID3算法的改进,它继承了ID3算法的优点并对ID3算法进行了改进和补充。
C4.5算法采用信息增益比作为选择分支属性的标准,克服了ID3算法中信息增益选择属性时偏向选择取值多的属性的不足,并能够完成对连续属性离散化的处理,还能够对不完整数据进行处理。
信息增益比:
特征 A 对训练数据集 D 的信息增益比 g R ( D , A ) g_R\left( D,A \right) gR(D,A) 定义为其信息增益 g ( D , A ) g\left( D,A \right) g(D,A) 与训练数据集 D 关于特征 A 的值的熵 H A ( D ) H_A\left( D \right) HA(D) 之比,即
g R ( D , A ) = g ( D , A ) H A ( D ) g_R\left( D,A \right) =\frac{g\left( D,A \right)}{H_A\left( D \right)} gR(D,A)=HA(D)g(D,A)
2.3 CART 算法
ID3 和 C4.5 虽然在对训练样本集的学习中可以尽可能多地挖掘信息,但是其生成的决策树分支、规模都比较大,CART 算法的二分法可以简化决策树的规模,提高生成决策树的效率。
熵模型拥有大量耗时的对数运算,基尼指数在简化模型的同时还保留了熵模型的优点。基尼指数代表了模型的不纯度,基尼系数越小,不纯度越低,特征越好。这和信息增益(率)正好相反。
基尼指数反映了从数据集中随机抽取两个样本,其类别标记不一致的概率。因此基尼指数越小,则数据集纯度越高。基尼指数偏向于特征值较多的特征,类似信息增益。基尼指数可以用来度量任何不均匀分布,是介于 0~1 之间的数,0 是完全相等,1 是完全不相等。
三、过度拟合
如果决策树对训练样本的特征描述得“过于精确”,无法实现对新样本的合理分析,所以此时它不是一棵分析新数据的最佳决策树。一棵完全决策树能非常准确地反映训练数据的特征,但因失去了一般代表性而无法用于对新数据的分类或预测,这种现象一般称为“过拟合”。
3.1 产生过度拟合数据问题的原因有哪些 ?
原因1:样本问题
(1) 样本里的噪音数据干扰过大,大到模型过分记住了噪音特征,反而忽略了真实的输入输出间的关系;
(2) 样本抽取错误,包括(但不限于)样本数量太小,抽样方法错误,抽样时没有足够正确考虑业务场景或业务特点等等,导致抽出的样本数据不能有效足够代表业务逻辑或业务场景;
(3) 建模时使用了样本中太多无关的输入变量。
原因2:构建决策树的方法问题
在决策树模型搭建中,使用的算法对于决策树的生长没有合理的限制和修剪,决策树的自由生长有可能每片叶子里只包含单纯的事件数据或非事件数据。
3.2 如何解决过度拟合数据问题 ?
针对原因1的解决方法:
合理、有效地抽样,用相对能够反映业务逻辑的训练集去产生决策树;
针对原因2的主要解决方法:
剪枝:提前停止树的增长或对已经生长的树按照一定的规则进行后剪枝。
决策树生成算法对于训练集是很准确的,但是会造成过度拟合,所以需要通过剪枝来提高泛化能力。剪枝思路:就是在决策树对训练数据的预测误差和树复杂度之间找到一个balance。
四、分类决策树模型python实现
4.1 sklearn的基本建模流程
from sklearn import tree #导入需要的模块
clf = tree.DecisionTreeClassifier() #实例化
clf = clf.fit(X_train,y_train) #用训练集数据训练模型
result = clf.score(X_test,y_test) #导入测试集,从接口中调用需要的信息
4.2 决策树的基本流程
决策树构建过程可以概括为3个步骤:特征选择、决策树的生成和决策树的剪枝。
4.3 安装和配置graphviz
进入官网 Graphviz - Graph Visualization Software
https://graphviz.gitlab.io/_pages/Download/Download_windows.html
下载完毕后双击msi文件,开始进行安装:
设置环境变量
配置完成后,进入cmd运行如下命令:
dot -version
如果显示出相应的graphviz信息,则配置就是完成了
安装到python
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple graphviz
4.4 分类决策树参数
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提供了两种选择:
- 输入”entropy“,使用信息熵
- 输入”gini“,使用基尼系数
为了要将表格转化为一棵树,决策树需要找出最佳节点和最佳的分枝方法,对分类树来,衡量这个“最佳”的指标叫做“不纯度”,不纯度越低,决策树对训练集的拟合越好
在实际使用中,信息熵和基尼系数的效果基本相同
信息熵作为指标时,决策树的生长会更加“精细”,因此对于高维数据或者噪音很多的数,信息熵很容易过拟合
怎样选取参数?
通常就使用基尼系数,数据维度很大,噪音很大时使用基尼系数维度低,数据比较清晰的时候,信息熵和基尼系数没区别,当决策树的拟合程度不够的时候,使用信息熵。两个都试试,不好就换另外一个
4.5 例1——鸢尾花数据
from sklearn.datasets import load_iris
from sklearn import tree
import graphviz
iris = load_iris()
clf = tree.DecisionTreeClassifier()
clf = clf.fit(iris.data, iris.target)
dot_data = tree.export_graphviz(clf, out_file=None)
graph = graphviz.Source(dot_data)
graph.render("iris")
4.6 例2——红酒数据集
import pandas as pd
import graphviz
from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
wine = load_wine()
pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1)
# 分训练集和测试集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)
# 建立模型
clf = tree.DecisionTreeClassifier(criterion="entropy",
random_state=30, # 设置分枝中的随机模式的参数,默认None,在高维度时随机性会表现更明显
splitter="random" # 控制决策树中的随机选项
)
# 训练
clf = clf.fit(Xtrain, Ytrain)
#返回预测的准确度
score = clf.score(Xtest, Ytest)
score # 0.96
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜色强度','色调','od280/od315稀释葡萄酒','脯氨酸']
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
4.7 特征重要性
[*zip(feature_name,clf.feature_importances_)]
# [('酒精', 0.05911575203482781),
# ('苹果酸', 0.0),
# ('灰', 0.0),
# ('灰的碱性', 0.0),
# ('镁', 0.0),
# ('总酚', 0.0),
# ('类黄酮', 0.5140132157873617),
# ('非黄烷类酚类', 0.0),
# ('花青素', 0.0),
# ('颜色强度', 0.27432826744953076),
# ('色调', 0.0),
# ('od280/od315稀释葡萄酒', 0.0),
# ('脯氨酸', 0.15254276472827968)]
4.8 剪枝参数
在不加限制的情况下,一棵决策树会生长到衡量不纯度的指标最优,或者没有更多的特征可用为止。这样的决策树往往会过拟合,这就是说,它会在训练集上表现很好,在测试集上却表现糟糕。我们收集的样本数据不可能和整体的状况完全一致,因此当一棵决策树对训练数据有了过于优秀的解释性,它找出的规则必然包含了训练样本中的噪声,并使它对未知数据的拟合程度不足。
树对训练集的拟合程度如何?
score_train = clf.score(Xtrain, Ytrain)
score_train
# 1.0
为了让决策树有更好的泛化性,我们要对决策树进行剪枝。剪枝策略对决策树的影响巨大,正确的剪枝策略是优化决策树算法的核心。sklearn为我们提供了不同的剪枝策略:
-
max_depth
限制树的最大深度,超过设定深度的树枝全部剪掉
决策树多生长一层,对样本量的需求会增加一倍,所以限制树深度能够有效地限制过拟合。实际使用时,建议从=3开始尝试,看看拟合的效果再决定是否增加设定深度。 -
min_samples_leaf
限定一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生,或者,分枝会朝着满足每个子节点都包含min_samples_leaf个样本的方向去发生。一般搭配max_depth使用,在回归树中有神奇的效果,可以让模型变得更加平滑。一般来说,建议从=5开始使用。 -
min_samples_split
限定,一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分枝,否则分枝就不会发生。
调试
clf = tree.DecisionTreeClassifier(criterion="entropy",
random_state=0,
splitter="random",
max_depth=5,
# min_samples_leaf=10,
# min_samples_split=10,
)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) #返回预测的准确度
score # 得分
0.9629629629629629
clf = tree.DecisionTreeClassifier(criterion="entropy",
random_state=0,
splitter="random",
max_depth=5,
min_samples_leaf=10,
# min_samples_split=10,
)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) #返回预测的准确度
score # 得分
0.9259259259259259
clf = tree.DecisionTreeClassifier(criterion="entropy",
random_state=0,
splitter="random",
max_depth=5,
# min_samples_leaf=10,
min_samples_split=10,
)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) #返回预测的准确度
score # 得分
0.9814814814814815
-
max_features
限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃。用来限制高维度数据的过拟合的剪枝参数 -
min_impurity_decrease
限制信息增益的大小,信息增益小于设定数值的分枝不会发生。
4.9 确认最优的剪枝参数
那具体怎么来确定每个参数填写什么值呢?这时候,我们就要使用确定超参数的曲线来进行判断了,继续使用我们已经训练好的决策树模型clf。超参数的学习曲线,是一条以超参数的取值为横坐标,模型的度量指标为纵坐标的曲线,它是用来衡量不同超参数取值下模型的表现的线。在我们建好的决策树里,我们的模型度量指标就是score。
import matplotlib.pyplot as plt
test = []
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()
在 max_depth=4 时,得分最高
剪枝参数的默认值会让树无尽地生长,这些树在某些数据集上可能非常巨大,对内存的消耗也非常巨大。所以如果你手中的数据集非常巨大,你已经预测到无论如何你都是要剪枝的,那提前设定这些参数来控制树的复杂性和大小会比较好。
4.10 目标权重参数
-
class_weight
使用class_weight参数对样本标签进行一定的均衡,给少量的标签更多的权重,让模型更偏向少数类,向捕获少数类的方向建模。该参数默认None,此模式表示自动给
与数据集中的所有标签相同的权重。 -
min_weight_fraction_leaf
有了权重之后,样本量就不再是单纯地记录数目,而是受输入的权重影响了,因此这时候剪枝,就需要搭配min_weight_fraction_leaf这个基于权重的剪枝参数来使用。
4.11 重要属性和接口
#apply返回每个测试样本所在的叶子节点的索引
clf.apply(Xtest)
Out[63]:
array([2, 2, 6, 5, 5, 5, 5, 5, 6, 5, 6, 3, 2, 5, 6, 5, 2, 5, 3, 2, 2, 2,
3, 6, 2, 6, 5, 6, 3, 6, 2, 2, 3, 5, 6, 6, 3, 3, 2, 5, 6, 5, 2, 5,
5, 2, 6, 6, 3, 6, 3, 2, 6, 5], dtype=int64)
#predict返回每个测试样本的分类/回归结果
clf.predict(Xtest)
Out[64]:
array([2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 2, 0, 1, 2, 2, 2,
1, 0, 2, 0, 0, 0, 1, 0, 2, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0, 0, 2, 0,
0, 2, 0, 0, 1, 0, 1, 2, 0, 0])
回归树
几乎所有参数、属性及接口都和分类树一模一样。在回归树中,没有标签分布是否均衡的问题,因此没有class_weight这样的参数。
重要参数,属性及接口
criterion
回归树衡量分枝质量的指标,支持的标准有三种:
1)输入"mse"使用均方误差,父节点和叶子节点之间的均方误差的差额将被用来作为特征选择的标准,这种方法通过使用叶子节点的均值来最小化L2损失
mse就是样本真实数据与回归结果的差异。在回归树中,MSE不只是分枝质量衡量指标,也是最常用的衡量回归树回归质量的指标,当我们在使用交叉验证,或者其他方式获取回归树的结果时,往往选择均方误差作为评估(在分类树中这个指标是score代表的预测准确率)。在回归中,我们追求的是,MSE越小越好。
回归树的接口score返回的是R平方,并不是MSE
虽然均方误差永远为正,但是sklearn当中使用均方误差作为评判标准时,却是计算”负均方误差“
2)输入“friedman_mse”使用费尔德曼均方误差,这种指标使用弗里德曼针对潜在分枝中的问题改进后的均方误差
3)输入"mae"使用绝对平均误差MAE(mean absolute error),这种指标使用叶节点的中值来最小化L1损失属性中最重要的依然是feature_importances_,接口依然是apply, fit, predict, score最核心。
交叉验证
是用来观察模型的稳定性的一种方法,将数据划分为n份,依次使用其中一份作为测试集,其他n-1份作为训练集,多次计算模型的精确性来评估模型的平均准确程度。训练集和测试集的划分会干扰模型的结果,因此用交叉验证n次的结果求出的平均值,是对模型效果的一个更好的度量。