决策树的简单实现与可视化

0.原理

1.数据

http://www.ai-xlab.com/my/course/135
1.课时1-课程资料AllElectronics.csv
是CSV文件,依据已有数据推断是否买电脑
数据属性:age,income,student,credit_rating
标签属性:Yes/No
共14笔数据
2.cart.csv已经处理好数据
数据1
数据2

2.需要的库

csv,sklearn,graphviz
其中graphviz需要独立安装并自行设置环境变量,否则报错:make sure the Graphviz executables are on your systems’ PATH

3.数据预处理

3.0.读取数据

读取CSV数据可用csv或者Pandas,csv为按行依次读取,且为列表类型
Padas为整体读取,dataframe类型
分别获取标签列表labellist和特征列表featurelist

import csv
from sklearn import tree
from sklearn.feature_extraction import DictVectorizer
from sklearn.preprocessing import LabelBinarizer
def read_csv(filename):
    # 获取csv数据
    with open(filename, 'r') as f:
        labellist = []  # 创建标签列表:是否买电脑
        featurelist = []  # 创建属性列表:age,student......

        f_reader = csv.reader(f)
        f_headers = next(f_reader)  # 读取表头
        for row in f_reader:
            f_dict = {}  # 创建字典,{age:senior,student:yes......}
            labellist.append(row[-1])  # 添加标签
            for i in range(1, 5):
                f_dict[f_headers[i]] = row[i]  # 添加属性
            featurelist.append(f_dict)
    return featurelist, labellist

3.1数据处理

将所获得列表编码
1.特征数据编码sklearn 特征提取,dictvectorizer:将字典数据向量化编码,注意这里不能用pandas.get_dummies,TypeError: unhashable type: ‘dict’,即不能处理列表中的字典数据,但结果与get_dummies相同
2.标签数据编码:LabelBinarizer()


def process_f(featurelist, labellist):
    # 数据预处理(编码)
    # sklearn 特征提取,dictvectorizer:将字典数据向量化编码,注意这里不能用pandas.get_dummies,TypeError: unhashable type: 'dict',即不能处理列表中的字典数据
    # 处理feature
    dict_v = DictVectorizer()
    x_data = dict_v.fit_transform(featurelist).toarray()  # 转化为array**
    # print(x_data)
    # [[0. 0. 1. 0. 1. 1. 0. 0. 1. 0.]
    #  [0. 0. 1. 1. 0. 1. 0. 0. 1. 0.]
    #  [1. 0. 0. 0. 1. 1. 0. 0. 1. 0.]......]

    # 处理label
    # y_data = []
    # for i in labellist:
    #
    #     if i == 'yes':
    #         y_data.append(1)
    #     else:
    #         y_data.append(0)
    # 或者用sklearn中的LabelBinarizer
    label_binary = LabelBinarizer()
    y_data = label_binary.fit_transform(labellist)
    return x_data, y_data, dict_v, label_binary

4.建立决策树模型并验证

if __name__ == '__main__':
    filename = r'C:\Users\hp\Desktop\决策树\AllElectronics.csv'
    featurelist, labellist = read_csv(filename)
    x_data, y_data, dict_v, label_binary = process_f(featurelist, labellist)

    # 测试
    # 创建分类决策树完成分类

    model = tree.DecisionTreeClassifier(criterion='entropy')  # criterion 选择划分节点的标准:默认gini指数(CART),还可entropy(C4.5)
    #   输入数据建立模型:
    model.fit(x_data, y_data)  # 求得数据集的均值方差最大值最小值等
    false_count = 0
    for i in range(len(x_data)):
        x_test = x_data[i]
        predict = model.predict(x_test.reshape(1, -1))  # 由于预测时要传入二维数组,因此作转化
        print('predict:%s' % (predict))
        if predict != y_data[i]:
            false_count += 1
    print(false_count)
    #     可视化
   

可视化

 import graphviz

    dot_data = tree.export_graphviz(model, feature_names=dict_v.get_feature_names(), class_names=label_binary.classes_)
    # dict_v.get_feature_names()获取特征名称(向量化之后),即逆向量化
    # label_binary.classes_获取分类标签名称
    graph = graphviz.Source(dot_data)
    graph.render('Decision_tree')
   

结果
结果
同理可对数据2进行处理、可视化
不同的是由于数据均为数字,可以用 np.genfromtxt(filename, delimiter=’,’)进行读取:

data = np.genfromtxt(filename, delimiter=',')
x_data = data[1:, 1:-1]  # 多维列表的访问,1:第一行到最后一行,第一列到倒数第二列
y_data = data[1:, -1]
# 创建决策树模型
model = tree.DecisionTreeClassifier()  # 默认使用基尼指数计算
# 输入数据创建决策树
model.fit(x_data, y_data)
dot_data = tree.export_graphviz(model,
                                feature_names=['house_yes', 'house_no', 'single', 'married', 'divorced', 'income'],
                                class_names=['no', 'yes'])
graph=graphviz.Source(dot_data)
graph.render('cart')

结果

以下为非线性二分类数据:LR-testSet2.txt

shape(x_data)=(118,2),shape(y_data)=(118,)
为了画等高线需要用pyplot.contourf(x,y,z)
但是x,y必须为meshgrid生成的网格矩阵

0.设置数据范围

x_min=x_data[:,0].min()-1#x_min,max,y_min,max是为了画等高线设置的数据范围,保证不出圈
x_max=x_data[:,0].max()+1
y_min=x_data[:,1].min()-1
y_max=x_data[:,1].max()+1
x_range=np.arange(x_min,x_max,0.2)
y_range=np.arange(y_min,y_max,0.2)

其中x_range:(196,),y_range(194,)

1.生成网格矩阵

xx,yy=np.meshgrid(x_range,y_range)#生成网格矩阵

xx:(194,196),yy:(194,196)
meshgird生成两个shape相同的矩阵:

2.预测

z=model.predict(np.c_[xx.ravel(),yy.ravel()])

#ravel()将xx,yy恢复成一维向量
np.c_()行连接
print(np.shape(xx.ravel())) # 38024=194*196,ravel()降维为列向量
print(np.shape(merged_x_data))#(38024, 2)

3.画图

z=z.reshape(xx.shape)# 改为194*196列,使得坐标对应上
cs=plt.contourf(xx,yy,z)
plt.scatter(x_data[:,0],x_data[:,1],c=y_data)
plt.show()

在这里插入图片描述

4.精度分析

精度分析使用sklearn.metrics.classification_report
1.训练集精度

z_train = model.predict(x_train)  # print(len(z_train))#88
print(classification_report(z_train, y_train))  # 输出精度报告
#  precision    recall  f1-score   support
#
#          0.0       1.00      1.00      1.00        46
#          1.0       1.00      1.00      1.00        42
#
#     accuracy                           1.00        88
#    macro avg       1.00      1.00      1.00        88
# weighted avg       1.00      1.00      1.00        88

2.测试集精度

# 利用测试数据作检验
z_test = model.predict(x_test)  # print(len(z_test))  # 30
print(classification_report(z_test, y_test))  # 输出精度报告
#      precision    recall  f1-score   support
#
#          0.0       0.86      0.80      0.83        15
#          1.0       0.81      0.87      0.84        15
#
#     accuracy                           0.83        30
#    macro avg       0.83      0.83      0.83        30
# weighted avg       0.83      0.83      0.83        30

可以发现训练精度很高:100%
测试精度降低——过拟合
看看决策树图形
非线性二分类
可以看到分叉很多,造成过拟合(模型复杂)
因此可以通过剪枝解决过拟合问题:

model(max_depth:树的最大深度,min_samples_split:内部节点再划分所需最小样本数)
发布了24 篇原创文章 · 获赞 8 · 访问量 2172

猜你喜欢

转载自blog.csdn.net/weixin_44839513/article/details/103437634
今日推荐