赞
踩
根据age、income、student、credit_rating属性来推断是否会买电脑:
然后画出如下的决策树:
(1) 熵其实可以代表不确定性,如果一个事情的熵越大,代表不确定性越大;熵越小,说明事情是比较确定的。
4.1 信息熵的计算
所以分别得到骰子A、B、C的信息熵:
所以有骰子ABC可知,信息熵越大,不确定性越大。
(1) 把信息增益最大的那个作为根节点,如下图,age的信息增益最大,为0.246,即age为根节点。
再分别累计使用ID3算法选择下一个节点的根节点:
(2) ID3算法比较倾向选择分支数(属性值)比较多的那个参数(下面图中age是三个属性值,而students、credit-rating、income都只有两个属性值)
而为了优化这种倾向于选择因子数较多的变量的特点,提出来C4.5算法:
- # -*- coding: utf-8 -*- #
- """
- -------------------------------------------------------------------------------
- FileName: decision_tree_ID3
- Author: newlinfeng
- Date: 2020/8/3 0003 10:17
- Description: 使用是否购买电脑的数据集,来构建一个决策树例子(ID3)
- -------------------------------------------------------------------------------
- """
- from sklearn.feature_extraction import DictVectorizer
- from sklearn import tree
- from sklearn import preprocessing
- import csv
-
- #读入数据
- Dtree = open(r'AllElectronics.csv', 'r')
- #这次不是使用numpy来读(如果都是数字,可以使用这种方式来读,但现在这个csv里面都是字符,需要使用csv来读取),而是使用csv来读
- reader = csv.reader(Dtree)
-
- #获取第一行数据
- #__next__():读取文件里面的第一行
- headers = reader.__next__()
- print(headers)
-
- #定义两个列表
- featureList = [] #保存特征的
- labelList = [] #保存标签的
-
-
- for row in reader: #每次从reader里面读取一行
- #把label存入list
- labelList.append(row[-1]) #拿到每一行的最后一列的数据存入标签的list中
- rowDict = {} #定义了一个空的字典
- for i in range(1, len(row)-1): #某一行的每一列(除第一行,最后一列以外)对应元素遍历,存入rowDict中
- #建立一个数据字典
- rowDict[headers[i]] = row[i]
- #把数据字典存入list
- featureList.append(rowDict) #再将每个rowDict保存到特征list
-
- print('特征List初始化后的值:', featureList)
- print('标签List初始化后的值:', labelList)
-
-
- #由于算法无法使用字符来进行计算和分析,只能使用数字,所以需要将上面的数据进行转化
- vec = DictVectorizer() #这个DictVectorizer类主要是将字典结构的字符转换为数字形式
- x_data = vec.fit_transform(featureList).toarray()
- print('featureList数字化转换成x_data: ' + str(x_data))
-
- #打印属性名称
- print(vec.get_feature_names())
- #打印标签list
- print("labelList:"+str(labelList))
-
- #把标签转换成01表示
- lb = preprocessing.LabelBinarizer()
- y_data = lb.fit_transform(labelList)
- print("labelList转换后的y_data:"+str(y_data) )
-
-
- #创建一个决策树模型
- # DecisionTreeClassifier:决策树分类器;criterion属性表示使用不同的算法,默认是gini的方式,这里是entropy是信息熵的方式
- model = tree.DecisionTreeClassifier(criterion='entropy')
- #输入数据建立模型
- model.fit(x_data, y_data)
-
- #测试
- x_test = x_data[0] #选取x_data中的第0行元素
- print("x_test:", str(x_test))
-
- #reshape() 把x_test从一维数据变成二维数据
- predict = model.predict(x_test.reshape(1, -1))
- print("predict:"+str(predict))
-
- '''
- 导出决策树
- @todo:
- 1.pip install graphviz
- 2.http://www.graphviz.org
- '''
- import graphviz #http://www.graphviz.org
-
- dot_data = tree.export_graphviz(model,
- out_file=None,
- feature_names=vec.get_feature_names(),
- class_names=lb.classes_,
- filled=True,
- rounded=True,
- special_characters=True)
- graph = graphviz.Source(dot_data)
- graph.render('computer')

(1) 这里需要注意,在第一次安装完毕graphviz之后,需要讲Pycharm重启一下,否则画图会报如下错误:
graphviz.backend.ExecutableNotFound: failed to execute ['dot', '-Tpdf', '-O', 'cart'], make sure the Graphviz executables are on your systems' PATH
最终决策树的pdf文件为:
7.1 CART算法举例
第一步:
第二步:
最后构建的CART:
- # -*- coding: utf-8 -*- #
- """
- -------------------------------------------------------------------------------
- FileName: decision_tree_CART
- Author: newlinfeng
- Date: 2020/8/3 0003 22:22
- Description: 使用CART算法实现决策树的例子
- -------------------------------------------------------------------------------
- """
- from sklearn import tree
- import numpy as np
-
- #载入数据
- data = np.genfromtxt("cart.csv", delimiter=",")
- x_data = data[1:, 1:-1]
- y_data = data[1:, -1]
-
- #创建决策树模型
- model = tree.DecisionTreeClassifier()
- #输入数据建立模型
- model.fit(x_data, y_data)
-
- #导出决策树
- import graphviz
- dot_data = tree.export_graphviz(model,
- out_file=None,
- feature_names=['house_yes', 'house_no', 'single', 'married', 'divorced', 'income'],
- class_names=['no', 'yes'],
- filled=True,
- rounded=True,
- special_characters=True)
- graph = graphviz.Source(dot_data)
- graph.render('cart')

得到的decision tree的PDF:
- # -*- coding: utf-8 -*- #
- """
- -------------------------------------------------------------------------------
- FileName: linear_dichotomy
- Author: newlinfeng
- Date: 2020/8/4 0004 9:05
- Description: 使用决策树解决线性二分类的问题
- -------------------------------------------------------------------------------
- """
- import matplotlib.pyplot as plt
- import numpy as np
- from sklearn.metrics import classification_report
- from sklearn import tree
-
- #载入数据
- data = np.genfromtxt("LR-testSet.csv", delimiter=',')
- x_data = data[:, :-1]
- y_data = data[:, -1]
-
- plt.scatter(x_data[:, 0], x_data[:, 1], c=y_data)
- plt.show()
-
-
- #创建决策树模型
- model = tree.DecisionTreeClassifier()
- #输入数据建立模型
- model.fit(x_data, y_data)
-
- #导出决策树
- import graphviz
- dot_data = tree.export_graphviz(model,
- out_file=None,
- feature_names=['x', 'y'],
- class_names=['label0', 'label1'],
- filled=True,
- rounded=True,
- special_characters=True)
- graph = graphviz.Source(dot_data)
-
-
- #输入数据建立模型
- model.fit(x_data, y_data)
-
- #获取数据值所在的范围
- x_min, x_max = x_data[:, 0].min() - 1, x_data[:, 0].max()+1
- y_min, y_max = x_data[:, 1].min() - 1, x_data[:, 1].max()+1
-
- #生成网络矩阵
- xx, yy = np.meshgrid(np.arange(x_min, y_max, 0.02),
- np.arange(y_min, y_max, 0.02))
- #ravel与flatten类似,多维数组转一维。flatten不会改变原始数据,ravel会改变原始数据
- z = model.predict(np.c_[xx.ravel(), yy.ravel()])
- z = z.reshape(xx.shape)
- #等高线图
- cs = plt.contourf(xx, yy, z)
- #样本散点图
- plt.scatter(x_data[:, 0], x_data[:, 1], c=y_data)
- plt.show()
-
-
- predictions = model.predict(x_data)
- print(classification_report(predictions,y_data))

- # -*- coding: utf-8 -*- #
- """
- -------------------------------------------------------------------------------
- FileName: non-linear_dichotomy
- Author: newlinfeng
- Date: 2020/8/5 0005 15:16
- Description: 使用决策树解决非线性二分类
- -------------------------------------------------------------------------------
- """
- import matplotlib.pyplot as plt
- import numpy as np
- from sklearn.metrics import classification_report
- from sklearn import tree
- from sklearn.model_selection import train_test_split
-
- #载入数据
- data = np.genfromtxt("LR-testSet2.txt", delimiter=',')
- x_data = data[:, :-1]
- y_data = data[:, -1]
-
- plt.scatter(x_data[:, 0], x_data[:, 1], c=y_data)
- plt.show()
-
-
- #分割数据,默认情况下是3/4是训练集和训练集标签;1/4是测试集和测试集标签
- x_train, x_test, y_train, y_test = train_test_split(x_data, y_data)
-
- #创建决策树模型
- #max_depth, 树的深度
- #min_samples_split 内部节点再划分所需要最小样本数
- model = tree.DecisionTreeClassifier()
- #输入数据建立模型
- model.fit(x_train, y_train)
-
- #导出决策树
- import graphviz
-
- dot_data = tree.export_graphviz(model,
- out_file=None,
- feature_names= ['x', 'y'],
- class_names = ['label0', 'label1'],
- filled=True,
- rounded = True,
- special_characters=True)
- graph = graphviz.Source(dot_data)
- # graph.render('non-linear_dichotomy') #决策树导出为pdf
-
-
- #获取数据值所在的范围
- x_min, x_max = x_data[:, 0].min() - 1, x_data[:, 0].max()+1
- y_min, y_max = x_data[:, 1].min() - 1, x_data[:, 1].max()+1
-
- #生成网络矩阵
- xx, yy = np.meshgrid(np.arange(x_min, y_max, 0.02),
- np.arange(y_min, y_max, 0.02))
- #ravel与flatten类似,多维数组转一维。flatten不会改变原始数据,ravel会改变原始数据
- z = model.predict(np.c_[xx.ravel(), yy.ravel()])
- z = z.reshape(xx.shape)
- #等高线图
- cs = plt.contourf(xx, yy, z)
- #样本散点图
- plt.scatter(x_data[:, 0], x_data[:, 1], c=y_data)
- plt.show()
-
-
- #使用训练集预测效果非常好,几个标准都为1
- predictions = model.predict(x_train)
- print(classification_report(predictions,y_train))
-
- #使用训练集预测效果非常差,几个标准都为只有50%
- predictions = model.predict(x_test)
- print(classification_report(predictions,y_test))

决策树导出为PDF展示,结构较为复杂:
描述的决策边界:
最终结果却出现了过拟合:即:训练集中很好,测试集中表现很差,如下图:
训练集进行预测,很好:
测试集进行预测,很差:
12.1 使用剪枝来抵抗过拟合
剪枝的方式如下:
(1) 在DecisionTreeClassifier()方法中设置树的深度max_depth
(2) 在DecisionTreeClassifier()方法中设置树的内部节点再划分所需要最小样本数min_samples_split
经过上述的两个参数的修改,可以将评分从50%提高到80%左右,和之前使用逻辑回归得到的评价差不多:
2020-08-10 更新
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。