利用决策树探讨鸢尾花数据集分类问题,并可视化了数的深度和过拟合的关系

代码来自邹博老师的机器学习课程。其中对鸢尾花label转换为int,plt.pcolormesh()、决策树的可视化等方法都有一定的讲述。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import pydotplus


# 花萼长度、花萼宽度、花瓣长度、花瓣宽度
iris_feature_E = ['sepal length', 'sepal width', 'petal length', 'petal width']
iris_feature = ['花萼长度', '花萼宽度', '花瓣长度', '花瓣宽度']
iris_class = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']


if __name__ == '__main__':
    mpl.rcParams['font.family'] = 'SimHei'
    mpl.rcParams['axes.unicode_minus'] = False
    
    data = pd.read_csv('./iris.data', header=None)
    x = data[[i for i in range(4)]]
    y = pd.Categorical(data[4]).codes   # 将obejet类型转化为int分类,得到numpy格式数据
    
    # 为了可视化,仅使用前两列特征
    x = x.iloc[:, :2]
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.7, random_state=1)
    
    '''
    决策树参数估计
    1、分类用entropy或者gini,回归用mse
    2、min_samples_split=10,如果该节点包含的样本数目大于10,则(有可能)对其分支 --看这一次
    3、min_samples_leaf=10:若将某节点分支后,得到的每个子节点样本数目都大于10,则完成分支;否则不进行分支--看上一次
    4、max_depth=1:树的深度,很重要
    '''
    
    model = DecisionTreeClassifier(criterion='entropy')
    model.fit(x_train, y_train)
    y_test_hat = model.predict(x_test)
    print('测试集上的精确度:', np.mean(y_test == model.predict(x_test)))
    #print(accuracy_score(y_hat, y_test))
    
    # 保存
    # 方法一:
    with open('./iris.dot', 'w') as f:
        tree.export_graphviz(model, f)      # 可以下载个软件专门入去dot文件
    
    '''
    # 方法二:
    tree.export_graphviz(model, './iris.dot')
    '''
    
    # 输出为PDF格式
    dot_data = tree.export_graphviz(model, out_file=None, feature_names=iris_feature_E[:2], 
                                class_names=iris_class,filled=True, rounded=True, special_characters=True)
    # 这些参数是为了增添色彩效果
    graph = pydotplus.graph_from_dot_data(dot_data)
    graph.write_pdf('iris.pdf')
    
    # 输出为png格式
    f = open('iris.png', 'wb')
    f.write(graph.create_png())
    f.close()    
    
    # 画图
    N, M = 50, 50    # 横纵各采样多少个值
    x1_min, x2_min = x.min()
    x1_max, x2_max = x.max()
    t1 = np.linspace(x1_min, x1_max, N)
    t2 = np.linspace(x2_min, x2_max, M)
    x1, x2 = np.meshgrid(t1, t2)       # 生成网格采样
    x_show = np.stack([x1.flat, x2.flat], axis=1)  # 和flatten()一样,但是这个好像是生成器,运行应该更快
    # 将x1和x2分别转换为1列,然后横向拼接
    #x_show = np.hstack([x1.flat, x2.flat])  可以上代码是不一样的
    cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
    cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
    y_show_hat = model.predict(x_show)    # 坐标预测值
    y_show_hat = y_show_hat.reshape(x1.shape)  # 使之与输入的形状相同
    plt.figure(figsize=(12, 12))
    plt.pcolormesh(x1, x2, y_show_hat, cmap=cm_light)     # 坐标预测值的显示,画的是色块
    plt.scatter(x_test[0], x_test[1], c=y_test.flat, edgecolors='k', s=150, zorder=10, cmap=cm_dark, marker='*')
    plt.scatter(x[0], x[1], c=y.ravel(), edgecolors='k', s=40, cmap=cm_dark)
    plt.xlabel(iris_feature[0], fontsize=15)
    plt.ylabel(iris_feature[1], fontsize=15)
    #plt.xlim(x1_min, x1_max)
    #plt.ylim(x2_min, x2_max)
    plt.grid()
    plt.title('鸢尾花数据的决策树的分类', fontsize=18)
    plt.show()
    
    # 找到最优树的深度
    depth = [i for i in range(1, 20)]
    err_ls = []
    for i in range(len(depth)):
       model = DecisionTreeClassifier(max_depth=depth[i]) 
       model.fit(x_train, y_train)
       y_test_hat = model.predict(x_test)
       accuracy = accuracy_score(y_test, y_test_hat)
       error = 1 - accuracy
       err_ls.append(error)
    print(len(err_ls))
    print(len(depth))
    # 画图
    plt.figure(figsize=(9, 6))
    plt.plot(depth, err_ls, 'g-', lw=2)
    plt.xlabel('树的深度', fontsize=12)
    plt.ylabel('错误率', fontsize=12)
    plt.xlim(min(depth)-1, max(depth)+1)
    plt.xticks([i for i in range(int(min(depth)), int(max(depth)+2), 2)])
    plt.title('鸢尾花数据决策树的深度和过拟合', fontsize=18)
    plt.grid()
    plt.legend()
    plt.show()

在原图的基础上,绘制鸢尾花数据两两特征分别与目标值的关系。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split


# 花萼长度、花萼宽度、花瓣长度、花瓣宽度
iris_feature_E = ['sepal length', 'sepal width', 'petal length', 'petal width']
iris_feature = ['花萼长度', '花萼宽度', '花瓣长度', '花瓣宽度']
iris_class = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']


if __name__ == '__main__':
    mpl.rcParams['font.family'] = 'SimHei'
    mpl.rcParams['axes.unicode_minus'] = False
    
    data = pd.read_csv('./iris.data', header=None)
    _x = data[[i for i in range(4)]]
    y = pd.Categorical(data[4]).codes   # 将obejet类型转化为int分类,得到numpy格式数据
    
    x_ls = [[0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3]]
    # 为了可视化,仅使用前两列特征
    plt.figure(figsize=(12, 12))
    num = 0
    for i, j in x_ls:
        x = _x.iloc[:, [i,j]]   # 这里用_x,因为如果用x就会改变x报错。
        x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.7, random_state=1)
    
        '''
        决策树参数估计
        1、分类用entropy或者gini,回归用mse
        2、min_samples_split=10,如果该节点包含的样本数目大于10,则(有可能)对其分支 --看这一次
        3、min_samples_leaf=10:若将某节点分支后,得到的每个子节点样本数目都大于10,则完成分支;否则不进行分支--看上一次
        4、max_depth=1:树的深度,很重要
        '''
    
        model = DecisionTreeClassifier(criterion='entropy', max_depth=2)
        model.fit(x_train, y_train)
        y_test_hat = model.predict(x_test)
        
        # 画图
        num += 1
        plt.subplot(2, 3, num)
        N, M = 50, 50    # 横纵各采样多少个值
        x1_min, x2_min = x.min()
        x1_max, x2_max = x.max()
        t1 = np.linspace(x1_min, x1_max, N)
        t2 = np.linspace(x2_min, x2_max, M)
        x1, x2 = np.meshgrid(t1, t2)       # 生成网格采样
        x_show = np.stack([x1.flat, x2.flat], axis=1)  # 和flatten()一样,但是这个好像是生成器,运行应该更快
        # 将x1和x2分别转换为1列,然后横向拼接
        #x_show = np.hstack([x1.flat, x2.flat])  可以上代码是不一样的
        cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
        cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
        y_show_hat = model.predict(x_show)    # 坐标预测值
        y_show_hat = y_show_hat.reshape(x1.shape)  # 使之与输入的形状相同
        plt.pcolormesh(x1, x2, y_show_hat, cmap=cm_light)     # 坐标预测值的显示,画的是色块
        plt.scatter(x_test[i], x_test[j], c=y_test.flat, edgecolors='k', s=80, zorder=10, cmap=cm_dark, marker='*')
        plt.scatter(_x[i], _x[j], c=y.ravel(), edgecolors='k', cmap=cm_dark)
        plt.xlabel(iris_feature[i], fontsize=15)
        plt.ylabel(iris_feature[j], fontsize=15)
        plt.xlim(x1_min, x1_max)
        plt.ylim(x2_min, x2_max)
        plt.grid()
    plt.suptitle('决策树对鸢尾花数据的两两特征组合的分类结果', fontsize=18)
    plt.tight_layout(1)                 # 子图各自间的间距
    plt.subplots_adjust(top=0.92)       # 总标题与第一行子图的距离
    plt.show()

你可能感兴趣的:(自学)