大家好,我是邵奈一,一个不务正业的程序猿、正儿八经的斜杠青年。
1、世人称我为:被代码耽误的诗人、没天赋的书法家、五音不全的歌手、专业跑龙套演员、不合格的运动员…
2、这几年,我整理了很多IT技术相关的教程给大家,爱生活、爱分享。
3、如果您觉得文章有用,请收藏,转发,评论,并关注我,谢谢!
博客导航跳转(请收藏):邵奈一的技术博客导航
| 公众号 | 微信 | CSDN | 掘金 | 51CTO | 简书 | 微博 |
背景说明:
使用的数据集为tennis.txt
,其中包含了14个样本,每个样本都包含了与天气相关的特征以及是否适合打球的相关信息。具体数据如下:
序号 | 天气 | 气温 | 湿度 | 风 | 类别 |
---|---|---|---|---|---|
1 | 晴 | 热 | 高 | 无 | N |
2 | 晴 | 热 | 高 | 有 | N |
3 | 多云 | 热 | 高 | 无 | Y |
4 | 雨 | 适中 | 高 | 无 | Y |
5 | 雨 | 冷 | 正常 | 无 | Y |
6 | 雨 | 冷 | 正常 | 有 | N |
7 | 多云 | 冷 | 正常 | 有 | Y |
8 | 晴 | 适中 | 高 | 无 | N |
9 | 晴 | 冷 | 正常 | 无 | Y |
10 | 雨 | 适中 | 正常 | 无 | Y |
11 | 晴 | 适中 | 正常 | 有 | Y |
12 | 多云 | 适中 | 高 | 有 | Y |
13 | 多云 | 热 | 正常 | 无 | Y |
14 | 雨 | 适中 | 高 | 有 | N |
# 导入pandas库,用于数据处理和分析
import pandas as pd
# 导入numpy库,用于数值计算
import numpy as np
# 导入sklearn库中的tree模块,用于构建决策树模型
from sklearn import tree
# 导入pydotplus库,用于绘制决策树图形
import pydotplus
如果提示:
ModuleNotFoundError: No module named 'pydotplus'
使用以下命令安装pydotplus:
方式一:直接在jupyter notebook中安装
!pip install pydotplus
方式二:直接在pip命令行中安装
pip install pydotplus
效果如图:
(base) C:\Users\shaonaiyi>pip install pydotplus
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))': /simple/pydotplus/
Collecting pydotplus
Downloading pydotplus-2.0.2.tar.gz (278 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 278.7/278.7 kB 58.8 kB/s eta 0:00:00
Preparing metadata (setup.py) ... done
Requirement already satisfied: pyparsing>=2.0.1 in c:\users\shaonaiyi\anaconda3\lib\site-packages (from pydotplus) (3.0.9)
Building wheels for collected packages: pydotplus
Building wheel for pydotplus (setup.py) ... done
Created wheel for pydotplus: filename=pydotplus-2.0.2-py3-none-any.whl size=24554 sha256=dc6225242106622dbd9d9e581bff72da1217c2b2a5048a2d712a0778536353dd
Stored in directory: c:\users\shaonaiyi\appdata\local\pip\cache\wheels\89\e5\de\6966007cf223872eedfbebbe0e074534e72e9128c8fd4b55eb
Successfully built pydotplus
Installing collected packages: pydotplus
# 生成决策树
def createTree(trainingData):
# 从训练数据中提取特征矩阵和标签
data = trainingData.iloc[:, :-1] # 获取特征矩阵(除了最后一列)
labels = trainingData.iloc[:, -1] # 获取标签(即最后一列)
# 创建一个分类决策树模型,使用信息熵作为划分标准
trainedTree = tree.DecisionTreeClassifier(criterion="entropy") # 分类决策树
# 使用特征矩阵和标签训练决策树模型
trainedTree.fit(data, labels) # 训练
# 返回训练好的决策树模型
return trainedTree
createTree
是一个函数,它接受一个参数 trainingData
。这个参数预期是一个数据集,其中每一行是一个样本,每一列是一个特征,最后一列是目标标签。data = trainingData.iloc[:, :-1]
这行代码从 trainingData
中取出所有的行(即所有的样本)和除最后一列之外的所有列。这是为了获取决策树训练所需的特征数据
。labels = trainingData.iloc[:, -1]
这行代码取出 trainingData
的最后一列,这是为了获取决策树训练所需的目标标签
。trainedTree = tree.DecisionTreeClassifier(criterion="entropy")
这行代码创建一个 DecisionTreeClassifier
对象,这个对象将会用于创建决策树。这里,criterion="entropy"
指定了决策树的建立基于信息增益率(也称为交叉熵
),这是在决策树的每个划分中,选择最优划分特征的标准。trainedTree.fit(data, labels)
这行代码调用 fit
方法,使用前面获取的特征
和标签
来训练决策树模型。trainedTree
。def showtree2pdf(trainedTree,finename):
# 将训练好的决策树导出为Graphviz格式的数据
dot_data = tree.export_graphviz(trainedTree, out_file=None)
# 从Graphviz格式的数据中创建一个图形对象
graph = pydotplus.graph_from_dot_data(dot_data)
# 将图形对象保存为PDF文件,文件名为finename
graph.write_pdf(finename)
showtree2pdf
的目的是将一个通过Graphviz格式导出的树形结构保存为PDF文件。trainedTree
,表示需要导出的树形结构;finename
,表示导出PDF文件的名字。tree.export_graphviz
方法将 trainedTree
导出为Graphviz格式的字符串 dot_data
。然后,使用 pydotplus.graph_from_dot_data
方法将 dot_data
转换为一个PyDotPlus图形对象 graph
。graph.write_pdf
方法将图形保存为PDF文件,文件名为 finename
。tree
,pydotplus
和 networkx
。其中 tree
和 networkx
是用于创建和处理树形结构的库,而 pydotplus
是用于处理Graphviz格式的库。定义一个 data2vector 函数,其作用是将非数值型的特征转换
为分类编码
,以便在机器学习模型中使用。这个函数在数据预处理阶段非常有用,可以帮助我们处理非数值型数据,并为后续的分析和建模提供更便利的数据形式。
def data2vector(data):
# 获取数据中除最后一列之外的所有列名
names = data.columns[:-1]
# 遍历每一列
for i in names:
# 将当前列转换为分类数据类型
col = pd.Categorical(data[i])
# 将当前列的分类编码替换为原始值
data[i] = col.codes
# 返回处理后的数据
return data
col = pd.Categorical(data[i])
表示将当前所遍历的列转换为分类数据类型
。pd.Categorical 函数将每个唯一的类别分配一个整数编码,比如编码可以为0、1、2等等。pd.Categorical(list).codes
可以得到原始数据
对应的序号列表,从而将类别信息
转化成数值信息
。为了便于理解,补充说明例子如下:
import pandas as pd
data = pd.DataFrame({
'A': ['apple', 'banana', 'apple', 'orange'],
'B': ['red', 'green', 'red', 'yellow'],
'C': [10, 20, 30, 40],
'Label': ['positive', 'negative', 'positive', 'positive']
})
print("原始数据:")
print(data)
transformed_data = data2vector(data)
print("转换后的数据:")
print(transformed_data)
输出结果为:
原始数据:
A B C Label
0 apple red 10 positive
1 banana green 20 negative
2 apple red 30 positive
3 orange yellow 40 positive
转换后的数据:
A B C Label
0 0 1 0 positive
1 1 0 1 negative
2 0 1 2 positive
3 2 2 3 positive
其中 ‘apple’ 对应编码 0,‘banana’ 对应编码 1,‘orange’ 对应编码 2,执行完后,可以发现已经将A、B、C列都已经进行了编码,将非数值型的特征转换
为了分类编码
。pd.Categorical 函数和 col.codes 是 pandas 库中常用的函数。
这种非数值型数据到分类编码的转换有几个优点:
需要注意的是,分类编码并不适用于所有情况。在某些情况下,我们可能需要使用其他编码方式,例如独热编码(One-Hot Encoding)或特征哈希(Feature Hashing),以满足特定的数据需求。
data = pd.read_table("tennis.txt",header=None,sep='\t') #读取训练数据
trainingvec=data2vector(data) #向量化数据
decisionTree=createTree(trainingvec) #创建决策树
showtree2pdf(decisionTree,"tennis.pdf") #图示决策树
说明:如果没有tennis.txt文件,可以观注公中号私发tennis.txt自动获取。
执行后,可能会报错:
InvocationException: GraphViz's executables not found
首先,先安装graphviz库,命令如下:
!pip install graphviz
然后,直接在网址:https://graphviz.org/download/中下载软件,我下载的版本是2.50.0版本:
下载后,需要安装,我直接安装在Anaconda安装目录的Library\bin目录下即可,比如我的地址为:D:\SmallTools\Anaconda3\Library\bin,因为我的Anaconda已经配置了环境变量了,所以无需再单独配置环境变量(安装时,也有是否配置环境变量选项,也可以选中它),选择则不需要单独配置环境变量路径,否则需要将Graphviz\bin路径配置到环境变量里。当然也可以在代码中配置,即在notebook中加入以下代码:
import os
os.environ["PATH"] += os.pathsep + "D:/SmallTools/Anaconda3/Library/bin/graphviz/bin/"
参考教程如下:https://blog.csdn.net/weixin_36407399/article/details/87890230
如果没有问题,重新执行代码,此时会在本地生成决策树图,名称为“tennis.pdf”:
可以看到里面的内容就是决策树的可视化呈现。字段分别为:天气、气温、湿度、风、类别,
其中
X[2]就表示第3个特征变量:湿度
X[0]则表示第1个特征变量:天气
X[3]则表示第4个特征变量:风力
此处以决策树的根节点的信息做解释:
X[2] <= 0.5:这是一个决策规则,表示当第一个特征(X[0])的值小于或等于0.5时,我们将沿着树向左走,否则向右走。在这个例子中,特征是湿度,例如高为0,正常为1。
entropy = 0.94:这是该节点的熵值,衡量了该节点的不确定性或混乱程度。熵值越大,表示数据集中的信息越多,不确定性越高,分类的难度也越大。
samples = 14:这表示该节点包含14个样本。
value = [5, 9]:这是一个数组,表示该节点中各个类别的样本数量。在这个例子中,可能表示有5个样本属于“不打网球”类别,9个样本属于“打网球”类别。这个值通常用于计算节点的熵。
然后继续看根节点的两个子节点,可以发现,湿度维度中,湿度为正常(值为1)的有7个,湿度为高(值为0)的也有7个,然后看value值,发现value[1,6],表示1个为N(不打网球),6个为Y,表示打网球。继续看湿度为正常节点的子节点,看X[3] <= 0.5,samples为3,即有风的样本是3个,然后继续拆开,发现value[1, 2],可以发现1个是N(不打网球),2个为Y(打网球)。类似这样找下去,其实就是决策树。可以结合着看下图:
重要概念解释:
输入:
testVec = [0,0,1,1] # 天气晴、气温冷、湿度高、风力强
print(decisionTree.predict(np.array(testVec).reshape(1,-1))) #预测
输出:
['否']
由此可以知道,天气晴、气温冷、湿度高、风力强,预测不会出来打网球。
邵奈一 原创不易,如转载请标明出处,教育是一生的事业。