欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于决策树的分类预测

程序员文章站 2024-02-26 19:48:52
...

一、决策树概述

(一)、基本介绍

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

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

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

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

基于决策树的分类预测

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

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