二、基于决策树的分类预测-学习笔记

一、学习目标

1.了解决策树的理论知识
2.掌握决策树的sklearn函数调用并将其运用到企鹅数据集的预测中

二、代码实践

1.代码流程

(1)Demo实践

  1. 库函数导入
  2. 模型训练
  3. 数据和模型可视化
  4. 模型预测

(2)基于企鹅(penguins)数据集的决策树分类实践

  1. 库函数导入
  2. 数据读取/载入
  3. 数据信息查看
  4. 可视化描述
  5. 利用决策树模型在二分类上进行训练和预测
  6. 利用决策树模型在三分类(多分类)上进行训练和预测

2.代码实践

(1)Demo实践

  1. 库函数导入
##  基础函数库
import numpy as np 

## 导入画图库
import matplotlib.pyplot as plt
import seaborn as sns

## 导入决策树模型函数
from sklearn.tree import DecisionTreeClassifier
from sklearn import tree
  1. 训练模型
##Demo演示LogisticRegression分类

## 构造数据集
x_fearures = np.array([[-1, -2], [-2, -1], [-3, -2], [1, 3], [2, 1], [3, 2]])
y_label = np.array([0, 1, 0, 1, 0, 1])

## 调用决策树回归模型
tree_clf = DecisionTreeClassifier()

## 调用决策树模型拟合构造的数据集
tree_clf = tree_clf.fit(x_fearures, y_label)
  1. 数据和模型可视化(需要用到graphviz可视化库)
## 可视化构造的数据样本点
plt.figure()
plt.scatter(x_fearures[:,0],x_fearures[:,1], c=y_label, s=50, cmap='viridis')
plt.title('Dataset')
plt.show()

在这里插入图片描述

## 可视化决策树
import graphviz
dot_data = tree.export_graphviz(tree_clf, out_file=None)
graph = graphviz.Source(dot_data)
graph.render("pengunis")

在这里插入图片描述

  1. 模型预测
## 创建新样本
x_fearures_new1 = np.array([[0, -1]])
x_fearures_new2 = np.array([[2, 1]])

## 在训练集和测试集上分布利用训练好的模型进行预测
y_label_new1_predict = tree_clf.predict(x_fearures_new1)
y_label_new2_predict = tree_clf.predict(x_fearures_new2)

print('The New point 1 predict class:\n',y_label_new1_predict)
print('The New point 2 predict class:\n',y_label_new2_predict)
'''
The New point 1 predict class:
 [1]
The New point 2 predict class:
 [0]
 '''

在这里插入图片描述

(2)基于企鹅(penguins)数据集的决策树实践

#下载需要用到的数据集
!wget https://tianchi-media.oss-cn-beijing.aliyuncs.com/DSW/6tree/penguins_raw.csv
  1. 库函数导入
##  基础函数库
import numpy as np 
import pandas as pd

## 绘图函数库
import matplotlib.pyplot as plt
import seaborn as sns

本次我们选择企鹅数据(palmerpenguins)进行方法的尝试训练,该数据集一共包含8个变量,其中7个特征变量,1个目标分类变量。共有150个样本,目标变量为 企鹅的类别 其都属于企鹅类的三个亚属,分别是(Adélie, Chinstrap and Gentoo)。包含的三种种企鹅的七个特征,分别是所在岛屿,嘴巴长度,嘴巴深度,脚蹼长度,身体体积,性别以及年龄。

变量描述
speciesa factor denoting peguin species
islanda factor denoting island Palmer Archipelago, Antarctica
bill_length_mma number denoting bill length
bill_depth_mma number denoting bill length
filpper_length_mman integer denoting filpper length
body_mass_gan integer denoting body mass
sexa factor denoting peguin sex
yearan integer denoting study year
  1. 数据读取/载入
## 我们利用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)']]
  1. 数据信息查看
## 利用.info()查看数据的整体信息
data.info()
'''
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 344 entries, 0 to 343
Data columns (total 5 columns):
Species                344 non-null object
Culmen Length (mm)     342 non-null float64
Culmen Depth (mm)      342 non-null float64
Flipper Length (mm)    342 non-null float64
Body Mass (g)          342 non-null float64
dtypes: float64(4), object(1)
memory usage: 13.6+ KB
'''
## 进行简单的数据查看,我们可以利用 .head() 头部.tail()尾部
data.head()
SpeciesCulmen Length (mm)Culmen Depth (mm)FlipperLength (mm)Body Mass (g)
0Adelie Penguin (Pygoscelis adeliae)39.118.7181.03750.0
1Adelie Penguin (Pygoscelis adeliae)39.517.4186.03800.0
2Adelie Penguin (Pygoscelis adeliae)40.318.0195.03250.0
3Adelie Penguin (Pygoscelis adeliae)NaNNaNNaNNaN
4Adelie Penguin (Pygoscelis adeliae)36.719.3193.03450.0

这里我们发现数据集中存在NaN,一般的我们认为NaN在数据集中代表了缺失值,可能是数据采集或处理时产生的一种错误。这里我们采用-1将缺失值进行填补,还有其他例如“中位数填补、平均数填补”的缺失值处理方法有兴趣的同学也可以尝试。

data = data.fillna(-1)
data.tail()
SpeciesCulmen Length (mm)Culmen Depth (mm)FlipperLength (mm)Body Mass (g)
339Chistrap Penguin (Pygoscelis antarctica)55.819.8207.04000.0
340Chistrap Penguin (Pygoscelis antarctica)43.518.1202.03400.0
341Chistrap Penguin (Pygoscelis antarctica)49.618.2193.03775.0
342Chistrap Penguin (Pygoscelis antarctica)50.819.0210.04100.0
343Chistrap Penguin (Pygoscelis antarctica)50.218.7198.03775.0
## 其对应的类别标签为'Adelie Penguin', 'Gentoo penguin', 'Chinstrap penguin'三种不同企鹅的类别。
data['Species'].unique()
'''
array(['Adelie Penguin (Pygoscelis adeliae)',
       'Gentoo penguin (Pygoscelis papua)',
       'Chinstrap penguin (Pygoscelis antarctica)'], dtype=object)
'''
## 利用value_counts函数查看每个类别数量
pd.Series(data['Species']).value_counts()
'''
Adelie Penguin (Pygoscelis adeliae)          152
Gentoo penguin (Pygoscelis papua)            124
Chinstrap penguin (Pygoscelis antarctica)     68
Name: Species, dtype: int64
'''
## 对于特征进行一些统计描述
data.describe()
Culmen Length (mm)Culmen Depth (mm)FlipperLength (mm)Body Mass (g)
count344.000000344.000000344.000000344.000000
mean43.66075617.045640199.7412794177.319767
std6.4289572.40561420.806759861.263227
min-1.000000-1.000000-1.000000-1.00000
25%39.20000015.500000190.0000003550.000000
50%44.2500017.300000197.0000004025.000000
75%48.50000018.700000213.0000004750.000000
max59.60000021.500000231.0000006300.000000
  1. 可视化描述
## 特征与标签组合的散点可视化
sns.pairplot(data=data, diag_kind='hist', hue= 'Species')
plt.show()

在这里插入图片描述

从上图可以发现,在2D情况下不同的特征组合对于不同类别的企鹅的散点分布,以及大概的区分能力。Culmen Lenth与其他特征的组合散点的重合较少,所以对于数据集的划分能力最好。

'''为了方便我们将标签转化为数字
       '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()
  1. 利用决策树模型在二分类上进行分类和预测
## 为了正确评估模型性能,将数据划分为训练集和测试集,并在训练集上训练模型,在测试集上验证模型性能。
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)
'''
DecisionTreeClassifier(class_weight=None, criterion='entropy', max_depth=None,
            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=False, random_state=None,
            splitter='best')
'''
## 可视化
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()
'''
The accuracy of the Logistic Regression is: 0.9954545454545455
The accuracy of the Logistic Regression is: 1.0
The confusion matrix result:
 [[31  0]
 [ 0 25]]
'''

我们可以发现其准确度为1,代表所有的样本都预测正确了。

  1. 利用决策树模型在三分类(多分类)上进行分类和预测
## 测试集大小为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)
'''
DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
            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=False, random_state=None,
            splitter='best')
'''
## 在训练集和测试集上分布利用训练好的模型进行预测
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))
'''
The test predict Probability of each class:
 [[0. 0. 1.]
 [0. 1. 0.]
 [0. 1. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 [0. 0. 1.]
 [0. 0. 1.]
 [1. 0. 0.]
 [0. 1. 0.]
 [1. 0. 0.]
 [0. 1. 0.]
 [0. 1. 0.]
 [1. 0. 0.]
 [0. 1. 0.]
 [0. 1. 0.]
 [0. 1. 0.]
 [1. 0. 0.]
 [0. 1. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 [0. 0. 1.]
 [1. 0. 0.]
 [0. 0. 1.]
 [1. 0. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 [0. 1. 0.]
 [1. 0. 0.]
 [0. 1. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 [0. 0. 1.]
 [0. 0. 1.]
 [0. 1. 0.]
 [1. 0. 0.]
 [0. 1. 0.]
 [0. 1. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]
 [1. 0. 0.]
 [0. 1. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 [0. 0. 1.]
 [0. 0. 1.]
 [1. 0. 0.]
 [1. 0. 0.]
 [0. 1. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 [0. 1. 0.]
 [0. 1. 0.]
 [0. 0. 1.]
 [0. 0. 1.]
 [0. 1. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 [1. 0. 0.]
 [0. 1. 0.]
 [0. 1. 0.]
 [0. 0. 1.]
 [0. 0. 1.]
 [1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]
 [1. 0. 0.]
 [1. 0. 0.]]
The accuracy of the Logistic Regression is: 0.9963636363636363
The accuracy of the Logistic Regression is: 0.9565217391304348
'''
## 查看混淆矩阵
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()
'''
The confusion matrix result:
 [[30  1  0]
 [ 0 23  0]
 [ 2  0 13]]
'''

三、重点

1.决策树构建的伪代码

输入: 训练集D={( 𝑥1 , 𝑦1 ),( 𝑥2 , 𝑦2 ),…,( 𝑥𝑚 , 𝑦𝑚 )};
特征集A={ 𝑎1 , 𝑎2 ,…, 𝑎𝑑 }

输出: 以node为根节点的一颗决策树

过程:函数TreeGenerate( 𝐷 , 𝐴 )

  1. 生成节点node
  2. 𝑖𝑓 𝐷 中样本全书属于同一类别 𝐶 𝑡ℎ𝑒𝑛 :
  3. ----将node标记为 𝐶 类叶节点; 𝑟𝑒𝑡𝑢𝑟𝑛
  4. 𝑖𝑓 𝐴 = 空集 OR D中样本在 𝐴 上的取值相同 𝑡ℎ𝑒𝑛 :
  5. ----将node标记为叶节点,其类别标记为 𝐷 中样本数最多的类;𝑟𝑒𝑡𝑢𝑟𝑛
  6. 从 𝐴 中选择最优划分属性 𝑎∗ ;
  7. 𝑓𝑜𝑟 𝑎∗ 的每一个值 𝑎𝑣∗ 𝑑𝑜 :
  8. ----为node生成一个分支,令 𝐷𝑣 表示 𝐷 中在 𝑎∗ 上取值为 𝑎𝑣∗ 的样本子集;
  9. ---- 𝑖𝑓 𝐷𝑣 为空 𝑡ℎ𝑒𝑛 :
  10. --------将分支节点标记为叶节点,其类别标记为 𝐷 中样本最多的类; 𝑡ℎ𝑒𝑛
  11. ---- 𝑒𝑙𝑠𝑒 :
  12. --------以 TreeGenerate( 𝐷𝑣 , 𝐴 { 𝑎∗ })为分支节点

决策树的构建过程是一个递归过程。函数存在三种返回状态:(1)当前节点包含的样本全部属于同一类别,无需继续划分;(2)当前属性集为空或者所有样本在某个属性上的取值相同,无法继续划分;(3)当前节点包含的样本集合为空,无法划分。

2.划分选择

从上述伪代码中我们发现,决策树的关键在于line6.从 𝐴 中选择最优划分属性 𝑎∗ ,一般我们希望决策树每次划分节点中包含的样本尽量属于同一类别,也就是节点的“纯度”更高。

(1)信息增益

信息熵是一种衡量数据混乱程度的指标,信息熵越小,则数据的“纯度”越高

Ent(𝐷)=−∑||𝑘=1𝑝𝑘log2𝑝𝑘
其中 𝑝𝑘 代表了第 𝑘 类样本在 𝐷 中占有的比例。

假设离散属性 𝑎 有 𝑉 个可能的取值{ 𝑎1 , 𝑎2 ,…, 𝑎𝑉 },若使用 𝑎 对数据集 𝐷 进行划分,则产生 𝐷 个分支节点,记为 𝐷𝑣 。则使用 𝑎 对数据集进行划分所带来的信息增益被定义为:

Gain(𝐷,𝑎)=Ent(𝐷)−∑𝑉𝑣=1||𝐷𝑣|||𝐷|Ent(𝐷𝑣)
一般的信息增益越大,则意味着使用特征 𝑎 来进行划分的效果越好。

(2)基尼指数

Gini(𝐷)=∑𝑘=1||∑𝑘′≠𝑘𝑝𝑘𝑝𝑘′=1−∑𝑘=1||𝑝2𝑘
基尼指数反映了从数据集 𝐷 中随机抽取两个的类别标记不一致的概率。

Giniindex(𝐷,𝑎)=∑𝑉𝑣=1||𝐷𝑣|||𝐷|Gini(𝐷𝑣)
使用特征 𝑎 对数据集 𝐷 划分的基尼指数定义为上。

(3)重要参数

  • criterion
    Criterion这个参数正是用来决定模型特征选择的计算方法的。sklearn提供了两种选择:

输入”entropy“,使用信息熵(Entropy)

输入”gini“,使用基尼系数(Gini Impurity)

  • random_state & splitter
    random_state用来设置分枝中的随机模式的参数,默认None,在高维度时随机性会表现更明显。splitter也是用来控制决策树中的随机选项的,有两种输入值,输入”best",决策树在分枝时虽然随机,但是还是会优先选择更重要的特征进行分枝(重要性可以通过属性feature_importances_查看),输入“random",决策树在分枝时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合。

  • max_depth
    限制树的最大深度,超过设定深度的树枝全部剪掉。这是用得最广泛的剪枝参数,在高维度低样本量时非常有效。决策树多生长一层,对样本量的需求会增加一倍,所以限制树深度能够有效地限制过拟合。

  • min_samples_leaf
    min_samples_leaf 限定,一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生,或者,分枝会朝着满足每个子节点都包含min_samples_leaf个样本的方向去发生。一般搭配max_depth使用,在回归树中有神奇的效果,可以让模型变得更加平滑。这个参数的数量设置得太小会引起过拟合,设置得太大就会阻止模型学习数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值