基于python的分类预测_[Python] 机器学习笔记 基于决策树的分类预测

一、介绍

决策树是一种常见的分类模型,在金融分控、医疗辅助诊断等诸多行业具有较为广泛的应用。决策树的核心思想是基于树结构对数据进行划分,这种思想是人类处理问题时的本能方法。

决策树的主要优点:

具有很好的解释性,模型可以生成可以理解的规则。

可以发现特征的重要程度。

模型的计算复杂度较低。

决策树的主要缺点:

模型容易过拟合,需要采用减枝技术处理。

不能很好利用连续型特征。

预测能力有限,无法达到其他强监督模型效果。

方差较高,数据分布的轻微改变很容易造成树结构完全不同。

二、理论

我们在做决策树的时候,会经历两个阶段:构造和剪枝

构造

构造的过程就是选择什么属性作为节点的过程,那么在构造过程中,会存在三种节点:

根节点:就是树的最顶端,最开始的那个节点;

内部节点:就是树中间的那些节点;

叶节点:就是树最底部的节点,也就是决策结果。

剪枝

为了防止“过拟合”(Overfitting)现象的发生

欠拟合,和过拟合就好比是下面这张图中的第一个和第三个情况一样,训练的结果“太好“,反而在实际应用过程中会导致分类错误。

造成过拟合的原因之一就是因为训练集中样本量较小。如果决策树选择的属性过多,构造出来的决策树一定能够“完美”地把训练集中的样本分类,但是这样就会把训练集中一些数据的特点当成所有数据的特点,但这个特点不一定是全部数据的特点,这就使得这个决策树在真实的数据分类中出现错误,也就是模型的“泛化能力”差。

剪枝可以分为“预剪枝”(Pre-Pruning)和“后剪枝”(Post-Pruning)

预剪枝是在决策树构造时就进行剪枝。方法是在构造的过程中对节点进行评估,如果对某个节点进行划分,在验证集中不能带来准确性的提升,那么对这个节点进行划分就没有意义,这时就会把当前节点作为叶节点,不对其进行划分。

后剪枝就是在生成决策树之后再进行剪枝,通常会从决策树的叶节点开始,逐层向上对每个节点进行评估。如果剪掉这个节点子树,与保留该节点子树在分类准确性上差别不大,或者剪掉该节点子树,能在验证集中带来准确性的提升,那么就可以把该节点子树进行剪枝。方法是:用这个节点子树的叶子节点来替代该节点,类标记为这个节点子树中最频繁的那个类。

纯度

决策树的构造过程理解成为寻找纯净划分的过程。数学上,我们可以用纯度来表示,纯度换一种方式来解释就是让目标变量的分歧最小

信息熵

信息熵越大,纯度越低。当集合中的所有样本均匀混合时,信息熵最大,纯度最低。

在构造决策树的时候,会基于纯度来构建。而经典的 “不纯度”的指标有三种,分别是信息增益(ID3 算法)、信息增益率(C4.5 算法)以及基尼指数(Cart 算法)

ID3 算法

ID3 算法计算的是信息增益,信息增益指的就是划分可以带来纯度的提高,信息熵的下降。

它的计算公式,是父亲节点的信息熵减去所有子节点的信息熵。

在计算的过程中,我们会计算每个子节点的归一化信息熵,即按照每个子节点在父节点中出现的概率,来计算这些子节点的信息熵。

优点:

算法规则相对简单,可解释性强

缺点:

ID3 算法倾向于选择取值比较多的属性。有些属性可能对分类任务没有太大作用,但是他们仍然可能会被选为最优属性。这种缺陷不是每次都会发生,只是存在一定的概率

对噪声敏感。训练数据如果有少量错误,可能会产生决策树分类错误

C4.5 算法

信息增益率

ID3 在计算的时候,倾向于选择取值多的属性。

为了避免这个问题,C4.5 采用信息增益率的方式来选择属性。信息增益率 = 信息增益 / 属性熵

当属性有很多值的时候,相当于被划分成了许多份,虽然信息增益变大了,但是对于 C4.5 来说,属性熵也会变大,所以整体的信息增益率并不大

悲观剪枝

ID3 构造决策树的时候,容易产生过拟合的情况。在 C4.5 中,会在决策树构造之后采用悲观剪枝(PEP),这样可以提升决策树的泛化能力。悲观剪枝是后剪枝技术中的一种,通过递归估算每个内部节点的分类错误率,比较剪枝前后这个节点的分类错误率来决定是否对其进行剪枝。这种剪枝方法不再需要一个单独的测试数据集。

离散化处理连续属性

C4.5 可以处理连续属性的情况,对连续的属性进行离散化的处理。

C4.5 选择具有最高信息增益的划分所对应的阈值。

处理缺失值

针对数据集不完整的情况,C4.5依然可以计算信息增益,并对属性进行选择。

优点:

在 ID3 的基础上,用信息增益率代替了信息增益,解决了噪声敏感的问题,并且可以对构造树进行剪枝、处理连续数值以及数值缺失等情况,

缺点:

C4.5 需要对数据集进行多次扫描,算法效率相对较低。

三、Demo实践

Step1: 库函数导入

## 基础函数库

import numpy as np

## 导入画图库

import matplotlib.pyplot as plt

import seaborn as sns

## 导入决策树模型函数

from sklearn.tree import DecisionTreeClassifier

from sklearn import tree

Step2: 训练模型

##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)

Step3: 数据和模型可视化(需要用到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")

'pengunis.pdf'

Step4:模型预测

## 创建新样本

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]

四、基于企鹅数据集的决策树实战

#下载需要用到的数据集

!wget https://tianchi-media.oss-cn-beijing.aliyuncs.com/DSW/6tree/penguins_raw.csv

Step1:函数库导入

## 基础函数库

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)。包含的三种种企鹅的七个特征,分别是所在岛屿,嘴巴长度,嘴巴深度,脚蹼长度,身体体积,性别以及年龄。

变量

描述

species

a factor denoting penguin species

island

a factor denoting island in Palmer Archipelago, Antarctica

bill_length_mm

a number denoting bill length

bill_depth_mm

a number denoting bill depth

flipper_length_mm

an integer denoting flipper length

body_mass_g

an integer denoting body mass

sex

a factor denoting penguin sex

year

an integer denoting the study year

Step2:数据读取/载入

## 我们利用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)']]

Step3:数据信息简单查看

## 利用.info()查看数据的整体信息

data.info()

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()

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

data = data.fillna(-1)

data.tail()

## 其对应的类别标签为'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()

Step4:可视化描述

## 特征与标签组合的散点可视化

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()

Step5:利用 决策树模型 在二分类上 进行训练和预测

## 为了正确评估模型性能,将数据划分为训练集和测试集,并在训练集上训练模型,在测试集上验证模型性能。

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")

'penguins.pdf'

## 在训练集和测试集上分布利用训练好的模型进行预测

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,代表所有的样本都预测正确了。

Step6:利用 决策树模型 在三分类(多分类)上 进行训练和预测

## 测试集大小为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]]

五、重要知识点

决策树构建的伪代码

输入: 训练集D={(

,

),(

,

),....,(

,

)};

特征集A={

,

,....,

}

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

过程:函数TreeGenerate(

,

)

生成节点node

中样本全书属于同一类别

:

----将node标记为

类叶节点;

= 空集 OR D中样本在

上的取值相同

:

----将node标记为叶节点,其类别标记为

中样本数最多的类;

中选择最优划分属性

;

的每一个值

:

----为node生成一个分支,令

表示

中在

上取值为

的样本子集;

----

为空

:

--------将分支节点标记为叶节点,其类别标记为

中样本最多的类;

----

:

--------以 TreeGenerate(

,

{

})为分支节点

决策树的构建过程是一个递归过程。函数存在三种返回状态:(1)当前节点包含的样本全部属于同一类别,无需继续划分;(2)当前属性集为空或者所有样本在某个属性上的取值相同,无法继续划分;(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使用,在回归树中有神奇的效果,可以让模型变得更加平滑。这个参数的数量设置得太小会引起过拟合,设置得太大就会阻止模型学习数据。

你可能感兴趣的:(基于python的分类预测)