基于决策树的分类预测

一、决策树概述

(一)、基本介绍

决策树(Decision Tree)算法是一种基本的分类与回归方法,决策树模型呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是 if-then 规则的集合,也可以认为是定义在特征空间与类空间上的条件概率分布。

结构:一般的,一棵决策树包含一个根结点、若干个内部结点和若干个叶结点;根结点包含样本全集;决策树叶结点对应于决策结果,其他每个结点则对应于一个属性测试;每个结点包含的样本集合根据属性测试的结果被划分到子结点中。从根结点到每个叶结点的路径对应了一个判定测试序列。

目的:决策树学习的目的是为 了产生一棵泛化能力强,即处理未见示例能力强的决策树,其基本流程遵循简单且直观的"分而治之" (divide-and-conquer) 策略。

步骤:决策树学习通常包括 3 个步骤:特征选择、决策树的生成和决策树的修剪。其基本算法流程如下图所示:

基于决策树的分类预测_第1张图片

显然,决策树的生成是一个递归过程。在决策树基本算法中,有三种情形会导致递归返回

​ (1) 当前结点包含的样本全属于同一类别,无需划分;

​ (2) 当前 属性集为空,或是所有样本在所有属性上取值相同,无法划分;

​ (3) 当前结点包 含的样本集合为空,不能划分。

(二)、划分选择

决策树的性能如何一般取决于如何选择最优划分属性,建立决策树。一般而言,随着划分过程不断进行,我们希望决策树的分支结点所包含的样 本尽可能属于同一类别,即结点的"纯度" (purity) 越来越高。主要有一下三种准则:

​ (1) 信息熵:信息熵(information entropy) 是度量样本集合纯度最常用的一种指标,信息熵越大,纯度越高。

​ (2)信息增益:一般而言,信息增益越大,则意味着使用属性来进行划分所获得的"纯度提升"越大。因此,我们可用信息增益来进行决策树的划分属性选择。

​ (3) 增益率:实际上,信息增益准则对可取值数目较多的属性有所偏好,为减少这种偏好可能带来的不利影响,有时决策树算法不直接使用信息增益,而是使用增益率"(gain ratio) 来选择最优划分属性。

​ (4) 基尼指数:CART决策树使用"基尼指数" (Gini index) 来选择划分属性,直观来说, 基尼指数反映了从数据集 中随机抽取两个样本,其类别标记不一致的概率.因此,基尼指数越小,则数据集的纯度越高。于是,我们在候选属性集合中,选择那个使得划分后基尼指数最小的属性作为最优划分属性。

(三)剪枝处理

剪枝(pruning) 是决策树学习算法对付"过拟合"的主要手段.在决策树学习中,为了尽可能正确分类训练样本,结点划分过程将不断重复,有时会造成决 策树分支过多,这时就可能因训练样本学得"太好"了,以致于把训练集自身 的一些特点当作所有数据都具有的一般性质而导致过拟合.因此,可通过主动 去掉一些分支来降低过拟合的风险。主要有两种剪枝方式:

​ (1) 预剪枝:. 预剪枝是指在决策树生成过程中,对每个结点在划 分前先进行估计,若当前结点的划分不能带来决策树泛化性能提升,则停止划 分并将当前结点标记为叶结点;

​ 预剪枝优缺点:预剪枝使得决策树的很多分支都没有"展 开“,这不仅降低了过拟合的风险,还显著减少了决策树的训练时间开销和测试时间开销。但另一方面,有些分支的当前划分虽不能提升泛化性能、甚至可 能导致泛化性能暂时下降,但在其基础上进行的后续划分却有可能导致性能显 著提高;预剪枝基于"贪心"本质禁止这些分支展开 给预剪枝决策树带来了 欠拟含的风险。

​ (2) 后剪枝:;后剪枝则是先从训练集生成一棵完整的决策树, 然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能带来决策树泛化性能提升,则将该子树替换为叶结点;

​ 后剪枝优缺点:后剪枝决策树通常比预剪枝决策树保留 了更多的分支 一般情形下,后剪枝决策树的欠拟合风险很小,泛化能往往 剪枝决策树。但后剪枝过程是在生成完全决策树之后进行的 并且要白底向上对树中的所有非叶结点进行逐考察,因此其训练时间开销比未剪枝决策树和预剪枝决策树都要大得多。

二、DEMO实战案例

import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier
from sklearn import tree
from sklearn.model_selection import train_test_split
from mpl_toolkits.mplot3d import Axes3D
import graphviz
import seaborn as sns
import sys, io, os
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')
def demoTree():
    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)
    plt.figure()
    plt.scatter(x_fearures[:,0],x_fearures[:,1], c=y_label, s=50, cmap='viridis')
    plt.title('Dataset')
    plt.show()
    
    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)

三、基于企鹅数据集的决策树实战案例

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

数据集下载链接:https://tianchi-media.oss-cn-beijing.aliyuncs.com/DSW/6tree/penguins_raw.csv

def palmeDecisionTree(path):
    data = pd.read_csv(path)
    ## 为了方便我们仅选取四个简单的特征,有兴趣的同学可以研究下其他特征的含义以及使用方法
    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) # 用-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()

    # 选取其前三个特征绘制三维散点图
    
    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()

    ## 为了正确评估模型性能,将数据划分为训练集和测试集,并在训练集上训练模型,在测试集上验证模型性能。
   
    ## 选择其类别为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)

    ## 在训练集和测试集上分布利用训练好的模型进行预测
    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()

你可能感兴趣的:(ml,python,机器学习,决策树)