目录
决策树
决策树是一种树型结构的机器学习算法,它每个节点验证数据一个属性,根据该属性进行分割数据,将数据分布到不同的分支上,直到叶子节点,叶子结点上表示该样本的label. 每一条从根节点到叶子节点的路径表示分类[回归]的规则.
sklearn中的决策树简单实践
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris, load_boston
from sklearn import tree
from sklearn.model_selection import train_test_split
# 分类树
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
clf = tree.DecisionTreeClassifier()
clf = clf.fit(X_train, y_train)
print ("Classifier Score:", clf.score(X_test, y_test))
#Classifier Score: 0.8666666666666667
tree.plot_tree(clf.fit(X, y))
plt.show()
# 回归树
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
clf = tree.DecisionTreeRegressor()
clf = clf.fit(X_train, y_train)
print ("Regression Score:", clf.score(X_test, y_test))
#Regression Score: 0.8802395209580839
tree.plot_tree(clf.fit(X, y))
plt.show()
注意的是:上面例子的输出都不是唯一的。
信息论基础
1.熵和信息熵
熵,热力学中表征物质状态的参量之一,用符号S表示,其物理意义是体系混乱程度的度量.
- 熵越大, 物理的不确定性越大.
- 信息熵,解决了对信息的量化度量问题. 信息熵越小,数据的稳定性越好
我们目的肯定是熵越小,机器学习得到的结果越准确.
信息熵表示随机变量不确定性的度量,设随机标量X是一个离散随机变量,其概率分布为:
随机变量X的信息熵定义为:
.
熵越大,随机变量的不确定性就越大。当 时,随机变量的熵最大为logn,其取值范围:
2. 条件熵
条件熵就是在给定X的条件的情况下,随机标量Y的条件,记为: 其中
一般在基于数据的估计中,我们使用的基于极大似然估计出来的经验熵和经验条件熵.
3.信息增益
信息增益表示的是在的得知特征X的信息后,使得类Y的信息的不确定性(熵)减少的程度.
4.基尼指数
基尼系数是指国际上通用的、用以衡量一个国家或地区居民收入差距的常用指标. 在信息学中,例如分类问题, 假设有K个类,样本点属于第k类的概率是,则该概率分布的基尼指数定义为:
决策树解释
解释:决策树中有两种结点,叶子结点和非叶子结点. 其中非叶节点代表的条件,叶子结点表示的实例所属的类别.
特征选择:我们如何生成这个决策树呢,最主要的一点就是选择那个特征作为当前树的分割结点,这就叫做特征选择。根据不同的特征选择方法,后面会介绍几种著名的决策树算法。
有了特征选择就有了决策树的生成,最后我们还会进行决策树剪枝(过拟合)
常见的决策树模型有以下三种(CART决策树既可以做分类也可以做回归):
- 使用信息增益准则选择特征, 相当于用极大似然法进行概率模型选择.
- C4.5: 和ID3算法相似, 只是用信息增益比选择特征.
- CART: 递归构建二叉决策树, 回归树:使用平方误差; 分类树:使用基尼指数.
ID3,C4.5决策树算法伪代码:
- 输入:数据集D,特征集合A,阈值e
- 输出:决策树T
- 如果D中所有实例输出同一类𝐶𝑘, 则T作为单节点树,并将类𝐶𝑘作为该节点的类标记,返回T;
- 若𝐴=∅,则T为单节点树,将D中实例数最多的类𝐶𝑘作为该节点的类标记,返回T;
- 否则,根据信息增益(ID3)或者信息增益比(C4.5)计算特征A对D的值,选择当前最优的特征𝐴𝑔;
- 如果𝐴𝑔的信息增益小于阈值e,则置T为单节点数,并将D中实例最多的类𝐶𝑘作为当前的类标记,返回T;
- 否则,根据𝐴𝑔中的每一个不同的𝑎𝑖,根据𝐴𝑔=𝑎𝑖将D分成若干个非空子集,对于第i个子节点,以𝐷𝑖为数据集,以𝐴−𝐴𝑔为特征集,递归(重复3-6)构造决策树𝑇𝑖,返回𝑇𝑖.
- 对决策树模型T进行剪枝.
过拟合和剪枝
决策树建立的过程中,只考虑经验损失最小化,没有考虑结构损失. 因此可能在训练集上表现良好,但是会出现过拟合问题。
模型损失=经验风险最小化+正则项=结构风险最小化
损失函数加上正则项再进行优化. 正则项表示树节点的个数,因此有如下公式:
树的叶子节点个数|T|, t是树T的叶节点,该叶节点有𝑁𝑡个样本,其中k类的样本点有𝑁𝑡𝑘个,k=1,2,...,K, 𝐻𝑡(𝑇)是叶子节点t经验熵,𝛼≤0是参数,平衡经验损失和正则项,得到计算公式如下:
经验熵:
所以:
决策树剪枝优化过程考虑了在训练数据上的经验风险最小化和减小模型复杂度两个方向. 因为加了正则项,所有我们基于贪心的思想进行剪枝,因为当剪掉一个树节点,虽然经验风险增加了,但是模型复杂度降低了,我们基于两个方面的平衡进行剪枝,如果剪掉之后,总的风险变小,就进行剪枝.
剪枝算法:
输入: 算法产生的整个决策树,参数𝛼
输出:修剪之后的树𝑇𝛼
- 计算每个节点的经验熵
- 递归从树的叶节点向上回溯,假设将某个叶节点回缩到其父节点前后的整体树对应的𝑇𝐵TB和𝑇𝐴TA,对应的损失分别是𝐶𝛼(𝑇𝐵)和𝐶𝛼(𝑇𝐴),如果:
𝐶𝛼(𝑇𝐴)≤𝐶𝛼(𝑇𝐵)
表示,剪掉之后,损失减小,就进行剪枝. - 重复2,直到不能继续为止,得到损失函数最小的子树𝑇𝛼
改进-动态规划剪枝算法:
输入: 算法产生的整个决策树,参数𝛼
输出: 修剪之后的树𝑇𝛼
- dp[所有树的节点] = {0}; 保留所有几点的信息熵
- 计算每个cur_node节点的经验熵, {if dp[cur_node] 直接返回, 否则, 执行2}
- 递归从树的叶节点向上回溯,假设将某个叶节点回缩到其父节点前后的整体树对应的𝑇𝐵和𝑇𝐴,对应的损失分别是𝐶𝛼(𝑇𝐵)和𝐶𝛼(𝑇𝐴),如果:
𝐶𝛼(𝑇𝐴)≤𝐶𝛼(𝑇𝐵)
表示,剪掉之后,损失减小,就进行剪枝.
𝑑𝑝[𝑐𝑢𝑟𝑛𝑜𝑑𝑒]=𝐶𝛼(𝑇𝐴)
4.重复2,直到不能继续为止,得到损失函数最小的子树𝑇𝛼
CART
分类与回归树(classification and regression tree, CART)与上述决策树的不同,
- 既可以做分类又可以做回归.
- 是二叉树,内部节点特征取值,只有yes和no两个选项
同样地,先进行决策树构造,在基于验证集上进行CART决策树的剪枝,既然是回归和分类树,我们就分别介绍回归和分类两种情况. - 分类: gini指数
- 回归: 平方误差 定义数据格式:
其中,𝑥𝑖是向量,当回归问题时,𝑦𝑖是连续变量; 分类问题时,𝑦𝑖是离散变量.
回归树(Regerssion Tree)
算法:
在训练数据上,根据某一个特征将每个区域划分为两个子区域并决定每个子区域的输出值,递归构建二叉树
1.选择最优切分变量j和切分点s,求解:
遍历变量j,对固定的切分变量j扫描所有的s,找到使得上式最小的对(j,s).
2. 使用选定的(j,s)划分区域并决定相应的输出值:
3. 继续对两个子区域调用1和2,知道满足条件
4. 将输入空间划分为M个区域生成决策树:
这里的是随机变量传输的平均信息量是
分类树(classification tree)
基尼指数:
基于数据D,有:
其中,𝐶𝑘是D中所属第k类的样本子集,K是类的个数.
如果样本集合D根据特征A是否取某一可能取值a被被划分成𝐷1和𝐷2两个部分.
在特征A的条件下,集合D的基尼指数定义为:
基尼指数和熵一样,同样表示集合D的不确定性,基尼指数(Gini(D,A))表示根据A=a分割后的集合D的不确定性,基尼指数越大,表示数据D的不确定性越大.
算法:
输入:训练数据D,停止计算的条件
输出:CART决策树
- 计算所有特征A的每一个值a对应的条件基尼指数的值,选择最优的划分得到𝐷1和𝐷2
- 递归对两个数据集𝐷1和𝐷2继续调用1,知道满足条件.
- 生成CART树的分类树.
- 预测的时候,根据决策树,x落到的叶子节点对应的类别表示这个预测x的类别.
CART剪枝(后续专门补充)
实战训练-基于企鹅数据集的决策树实战
数据集链接:https://tianchi-media.oss-cn-beijing.aliyuncs.com/DSW/6tree/penguins_raw.csv
该数据集一共包含8个变量,其中7个特征变量,1个目标分类变量。共有150个样本,目标变量为 企鹅的类别 其都属于企鹅类的三个亚属,分别是(Adélie, Chinstrap and Gentoo)。包含的三种种企鹅的七个特征,分别是所在岛屿,嘴巴长度,嘴巴深度,脚蹼长度,身体体积,性别以及年龄。
核心代码如下:可以用notebook一段一段允许。
## 基础函数库
import numpy as np
import pandas as pd
## 绘图函数库
import matplotlib.pyplot as plt
import seaborn as sns
## 我们利用Pandas自带的read_csv函数读取并转化为DataFrame格式
data = pd.read_csv('./penguins_raw.csv')
## 为了方便我们仅选取四个简单的特征,有兴趣的同学可以研究下其他特征的含义以及使用方法
data = data[['Species','Culmen Length (mm)','Culmen Depth (mm)',
'Flipper Length (mm)','Body Mass (g)']]
## 利用.info()查看数据的整体信息
data.info()
## 进行简单的数据查看,我们可以利用 .head() 头部.tail()尾部
data.head()
data = data.fillna(-1)
data.tail()
## 其对应的类别标签为'Adelie Penguin', 'Gentoo penguin', 'Chinstrap penguin'三种不同企鹅的类别。
data['Species'].unique()
## 利用value_counts函数查看每个类别数量
pd.Series(data['Species']).value_counts()
## 对于特征进行一些统计描述
data.describe()
## 特征与标签组合的散点可视化
sns.pairplot(data=data, diag_kind='hist', hue= 'Species')
plt.show()
'''为了方便我们将标签转化为数字
'Adelie Penguin (Pygoscelis adeliae)' ------0
'Gentoo penguin (Pygoscelis papua)' ------1
'Chinstrap penguin (Pygoscelis antarctica) ------2 '''
def trans(x):
if x == data['Species'].unique()[0]:
return 0
if x == data['Species'].unique()[1]:
return 1
if x == data['Species'].unique()[2]:
return 2
data['Species'] = data['Species'].apply(trans)
for col in data.columns:
if col != 'Species':
sns.boxplot(x='Species', y=col, saturation=0.5, palette='pastel', data=data)
plt.title(col)
plt.show()
# 选取其前三个特征绘制三维散点图
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(111, projection='3d')
data_class0 = data[data['Species']==0].values
data_class1 = data[data['Species']==1].values
data_class2 = data[data['Species']==2].values
# 'setosa'(0), 'versicolor'(1), 'virginica'(2)
ax.scatter(data_class0[:,0], data_class0[:,1], data_class0[:,2],label=data['Species'].unique()[0])
ax.scatter(data_class1[:,0], data_class1[:,1], data_class1[:,2],label=data['Species'].unique()[1])
ax.scatter(data_class2[:,0], data_class2[:,1], data_class2[:,2],label=data['Species'].unique()[2])
plt.legend()
plt.show()
from sklearn.model_selection import train_test_split
## 选择其类别为0和1的样本 (不包括类别为2的样本)
data_target_part = data[data['Species'].isin([0,1])][['Species']]
data_features_part = data[data['Species'].isin([0,1])][['Culmen Length (mm)','Culmen Depth (mm)',
'Flipper Length (mm)','Body Mass (g)']]
## 测试集大小为20%, 80%/20%分
x_train, x_test, y_train, y_test = train_test_split(data_features_part, data_target_part, test_size = 0.2, random_state = 2020)
## 从sklearn中导入决策树模型
from sklearn.tree import DecisionTreeClassifier
from sklearn import tree
## 定义 决策树模型
clf = DecisionTreeClassifier(criterion='entropy')
# 在训练集上训练决策树模型
clf.fit(x_train, y_train)
## 可视化
import graphviz
dot_data = tree.export_graphviz(clf, out_file=None)
graph = graphviz.Source(dot_data)
graph.render("penguins")
## 在训练集和测试集上分布利用训练好的模型进行预测
train_predict = clf.predict(x_train)
test_predict = clf.predict(x_test)
from sklearn import metrics
## 利用accuracy(准确度)【预测正确的样本数目占总预测样本数目的比例】评估模型效果
print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_train,train_predict))
print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_test,test_predict))
## 查看混淆矩阵 (预测值和真实值的各类情况统计矩阵)
confusion_matrix_result = metrics.confusion_matrix(test_predict,y_test)
print('The confusion matrix result:\n',confusion_matrix_result)
# 利用热力图对于结果进行可视化
plt.figure(figsize=(8, 6))
sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues')
plt.xlabel('Predicted labels')
plt.ylabel('True labels')
plt.show()
## 测试集大小为20%, 80%/20%分
x_train, x_test, y_train, y_test = train_test_split(data[['Culmen Length (mm)','Culmen Depth (mm)',
'Flipper Length (mm)','Body Mass (g)']], data[['Species']], test_size = 0.2, random_state = 2020)
## 定义 决策树模型
clf = DecisionTreeClassifier()
# 在训练集上训练决策树模型
clf.fit(x_train, y_train)
## 在训练集和测试集上分布利用训练好的模型进行预测
train_predict = clf.predict(x_train)
test_predict = clf.predict(x_test)
## 由于决策树模型是概率预测模型(前文介绍的 p = p(y=1|x,\theta)),所有我们可以利用 predict_proba 函数预测其概率
train_predict_proba = clf.predict_proba(x_train)
test_predict_proba = clf.predict_proba(x_test)
print('The test predict Probability of each class:\n',test_predict_proba)
## 其中第一列代表预测为0类的概率,第二列代表预测为1类的概率,第三列代表预测为2类的概率。
## 利用accuracy(准确度)【预测正确的样本数目占总预测样本数目的比例】评估模型效果
print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_train,train_predict))
print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_test,test_predict))
## 查看混淆矩阵
confusion_matrix_result = metrics.confusion_matrix(test_predict,y_test)
print('The confusion matrix result:\n',confusion_matrix_result)
# 利用热力图对于结果进行可视化
plt.figure(figsize=(8, 6))
sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues')
plt.xlabel('Predicted labels')
plt.ylabel('True labels')
plt.show()