赞
踩
本实验通过鸢尾花数据集iris.csv
来实现对决策树进一步的了解。其中, Iris
鸢尾花数据集是一个经典数据集,在统计学习和机器学习领域都经常被用作示例。数据集内包含3类共150条记录,每类各50个数据,每条记录都有4项特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度,可以通过这4个特征预测鸢尾花卉属于iris-setosa, iris-versicolour, iris-virginica
三个类别中的 哪一品种。Iris
数据集样例如下图所示:
本实验将五分之四的数据集作为训练集对决策树模型进行训练;将剩余五 分之一的数据集作为测试集,采用训练好的决策树模型对其进行预测。训练集 与测试集的数据随机选取。本实验采用准确率(accuracy)作为模型的评估函数:预测结果正确的数量占样本总数,(TP+TN)/(TP+TN+FP+FN)。
【实验要求】
本实验要求输出测试集各样本的预测标签和真实标签,并计算模型准确率。(选做)另外,给出 3 个可视化预测结果。
决策树算法可以分别尝试 ID3,C4.5,cart
树,并评判效果。
(选做):对你的决策树模型进行预剪枝与后剪枝
(选做):分别做 c4.5 和 cart 树的剪枝并比较不同。
分析数据结构,因为没有每个样本独有的属性(例如学生ID),决定采用ID3
决策树(ID3决策树的信息增益偏向于可能值较多的属性)。采用信息增益Information Gain
确定划分的最优特征,对于保存树的结构方面,采用字典的形式保存,以下方字典形式为例:
{
"PetalWidth": {
"0": "Iris-setosa",
"1": {
"PetalLength": {
"0": "Iris-setosa",
"1": "Iris-versicolor",
"2": {
"SepalLength": {
"1": "Iris-virginica",
"2": "Iris-versicolor"
}
}
}
},
"2": {
"SepalLength": {
"0": "Iris-virginica",
"1": "Iris-virginica",
"2": {
"SepalWidth": {
"0": "Iris-virginica",
"1": "Iris-virginica"
}
}
}
}
}
}
由于数据是连续的,在训练决策树之前需要将其离散化,利用python中seaborn
库观察数据分布:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
Data = pd.read_csv('iris.csv')
sb.pairplot(Data.dropna(), hue='Species')
plt.show()
因此我们确定数据的离散边界:
离散特征\离散后的值 | 0 | 1 | 2 |
---|---|---|---|
SepalLength | 0-5.5 | 5.5-6.3 | 6.3-inf |
SepalWidth | 0.3.2 | 3.2-inf | |
PetalLength | 0-2 | 2-4.9 | 4.9-inf |
PetalWidth | 0-0.6 | 0.6-1.7 | 1.7-inf |
为了保证结果的随机性,训练集与测试集的划分采用随机采样,每种花随机抽取10个共30个测试集样本,其余为训练集样本:
# 分割训练集与测试集
def split_train_test(data:pd.DataFrame):
# 随机采样
test_index = random.sample(range(50),10)
test_index.extend(random.sample(range(50,100),10))
test_index.extend(random.sample(range(100,150),10))
print(test_index)
testSet = data.iloc[test_index]
train_index = list(range(150))
for index in test_index:
train_index.remove(index)
# 划分训练集
trainSet = data.iloc[train_index]
return trainSet,testSet
split_train_test
:分割训练集与测试集ShannonEntropy
:计算一个Dataframe
关于forecast_label
列的信息熵InformationGain
:计算一个Dataframe
中label
标签关于forecast_label
的信息增益createTree
:递归生成决策树的过程decision
:对一个样本进行决策import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sb
import json
import random
def split_train_test(data:pd.DataFrame):
"""
分割训练集与测试集
:param data: 总的数据集
:return: 返回训练集与测试集
"""
# 随机采样
test_index = random.sample(range(50),10)
test_index.extend(random.sample(range(50,100),10))
test_index.extend(random.sample(range(100,150),10))
print(test_index)
testSet = data.iloc[test_index]
train_index = list(range(150))
for index in test_index:
train_index.remove(index)
# 划分训练集
trainSet = data.iloc[train_index]
return trainSet,testSet
def ShannonEntropy(data:pd.DataFrame,forecast_label:str)->float:
"""
计算一个数据集关于某个标签(这里是预测标签)的信息熵
:param data: 数据集
:param forecast_label: 预测标签
:return: 返回这个数据集的信息熵
"""
total = data.shape[0]
kinds = data[forecast_label].value_counts()
Entropy = 0.0
# 对于每种预测标签 计算pk*log(pk)
for i in range(kinds.shape[0]):
# 计算每种预测标签的比例
prior_probability = kinds[i]/total
# 计算信息熵
Entropy += (prior_probability * np.log2(prior_probability))
return -Entropy
def InformationGain(data:pd.DataFrame,label:str,forecast_label:str)->float:
"""
计算label标签关于forecast_label的信息增益
:param data: 数据集
:param label: 计算标签
:param forecast_label: 预测标签
:return: 信息增益
"""
# 计算总的信息熵Entropy(S)
total_entropy = ShannonEntropy(data,forecast_label)
# 初始化信息增益
gain = total_entropy
# 按照计算标签分组
sub_frame = data[[label,'Species']]
group = sub_frame.groupby(label)
# 计算信息增益
for key, df in group:
gain -= (df.shape[0]/data.shape[0]) * ShannonEntropy(df,'Species')
return gain
def createTree(data:pd.DataFrame)->dict:
"""
递归的创建决策树
:param data: 训练集数据
:return: 返回一个字典表示决策树
"""
# 该分支下的实例只有一种分类
if len(data['Species'].value_counts()) == 1:
return data['Species'].iloc[0]
# 初始化最优信息增益与最优属性
bestGain = 0
bestFeature = -1
# 对于每种属性计算信息增益,选出信息增益最大的一列
for column in data:
if column != 'Species':
gain = InformationGain(data, column, 'Species')
if bestGain < gain:
bestGain = gain
bestFeature = column
# 数据集中所有数据都相同,但种类不同,返回最多数量的种类
if bestFeature == -1:
valueCount = data['Species'].value_counts()
return valueCount.index[0]
# 初始化一个字典
myTree = {bestFeature: {}}
# 统计出最佳属性的所有可能取值
valueList = set(data[bestFeature])
for value in valueList:
# 递归的构造子树
myTree[bestFeature][value] = createTree(data[data[bestFeature] == value])
return myTree
def decision(tree:dict,testVector:pd.Series):
"""
预测一个测试集样本的类别
:param tree: 生成的决策树
:param testVector: 测试数据向量
:return: 返回预测标签
"""
# 初始化预测标签
forecastLabel = 0
# 获取当前决策树第一个节点属性
firstFeature = next(iter(tree))
# 获取子树
childTree = tree[firstFeature]
# 对子树中不同的可能值检测是否相等
for key in childTree.keys():
# 满足条件深入到下一层
if testVector[firstFeature] == key:
# 下一层是分支节点
if type(childTree[key]) == dict :
forecastLabel = decision(childTree[key],testVector)
# 下一层是叶节点
else:
forecastLabel = childTree[key]
return forecastLabel
if __name__ == '__main__' :
Data = pd.read_csv('iris.csv')
# 画出统计分布图,统计每种类别的特征
# sb.pairplot(Data.dropna(), hue='Species')
# plt.show()
# 数据离散化处理
Data['SepalLength'] = np.digitize(Data['SepalLength'],bins=[5.5,6.3])
Data['SepalWidth'] = np.digitize(Data['SepalWidth'],bins=[3.2])
Data['PetalLength'] = np.digitize(Data['PetalLength'],bins=[2,4.9])
Data['PetalWidth'] = np.digitize(Data['PetalWidth'],bins=[0.6,1.7])
# 数据离散化的字典
discrete_dict = {
'SepalLength' : {'0-5.5':0,'5.5-6.3':1,'6.3-inf':2},
'SepalWidth' : {'0.3.2':0,'3.2-inf':1},
'PetalLength' : {'0-2':0,'2-4.9':1,'4.9-inf':2},
'PetalWidth' : {'0-0.6':0,'0.6-1.7':1,'1.7-inf':2}
}
print('数据离散化字典:')
print(json.dumps(discrete_dict, indent=4))
# 分出训练集与测试集
train_set,test_set = split_train_test(Data)
# 训练出决策树
tree = createTree(train_set)
print("决策树字典表示:")
print(json.dumps(tree, indent=4, sort_keys=True))
# 初始化统计参数
T = 0
N = 0
for i in range(test_set.shape[0]):
print('================================================')
vector = test_set.iloc[i, :-1]
sl = vector['SepalLength']
sw = vector['SepalWidth']
pl = vector['PetalLength']
pw = vector['PetalWidth']
trueLabel = test_set.iloc[i]['Species']
print(f'离散化后的测试数据:SepalLength={sl},SepalWidth={sw},PetalLength={pl},PetalWidth={pw},真实标签={trueLabel}')
forecastLabel= decision(tree,vector)
if forecastLabel == trueLabel:
T+=1
print(f'预测为{forecastLabel},预测正确')
else:
N+=1
print(f'预测为{forecastLabel},预测错误')
print('-------------------------------------------------------------')
print(f'决策树预测准确率为:'+str(T/(T+N)))
运行程序后的控制台输出:
数据离散化字典:
{
"SepalLength": {
"0-5.5": 0,
"5.5-6.3": 1,
"6.3-inf": 2
},
"SepalWidth": {
"0.3.2": 0,
"3.2-inf": 1
},
"PetalLength": {
"0-2": 0,
"2-4.9": 1,
"4.9-inf": 2
},
"PetalWidth": {
"0-0.6": 0,
"0.6-1.7": 1,
"1.7-inf": 2
}
}
随机训练集index:
[38, 28, 26, 44, 40, 19, 2, 18, 7, 46, 68, 79, 50, 97, 65, 88, 69, 81, 92, 95, 126, 132, 137, 131, 110, 124, 133, 116, 125, 143]
决策树字典表示:
{
"PetalLength": {
"0": "Iris-setosa",
"1": {
"PetalWidth": {
"1": "Iris-versicolor",
"2": {
"SepalWidth": {
"0": "Iris-virginica",
"1": "Iris-versicolor"
}
}
}
},
"2": {
"PetalWidth": {
"1": {
"SepalLength": {
"1": "Iris-virginica",
"2": "Iris-versicolor"
}
},
"2": {
"SepalLength": {
"1": "Iris-virginica",
"2": {
"SepalWidth": {
"0": "Iris-virginica",
"1": "Iris-virginica"
}
}
}
}
}
}
}
}
================================================
离散化后的测试数据:SepalLength=0,SepalWidth=0,PetalLength=0,PetalWidth=0,真实标签=Iris-setosa
预测为Iris-setosa,预测正确
================================================
离散化后的测试数据:SepalLength=0,SepalWidth=1,PetalLength=0,PetalWidth=0,真实标签=Iris-setosa
预测为Iris-setosa,预测正确
================================================
离散化后的测试数据:SepalLength=0,SepalWidth=1,PetalLength=0,PetalWidth=0,真实标签=Iris-setosa
预测为Iris-setosa,预测正确
================================================
离散化后的测试数据:SepalLength=0,SepalWidth=1,PetalLength=0,PetalWidth=0,真实标签=Iris-setosa
预测为Iris-setosa,预测正确
================================================
离散化后的测试数据:SepalLength=0,SepalWidth=1,PetalLength=0,PetalWidth=0,真实标签=Iris-setosa
预测为Iris-setosa,预测正确
================================================
离散化后的测试数据:SepalLength=0,SepalWidth=1,PetalLength=0,PetalWidth=0,真实标签=Iris-setosa
预测为Iris-setosa,预测正确
================================================
离散化后的测试数据:SepalLength=0,SepalWidth=1,PetalLength=0,PetalWidth=0,真实标签=Iris-setosa
预测为Iris-setosa,预测正确
================================================
离散化后的测试数据:SepalLength=1,SepalWidth=1,PetalLength=0,PetalWidth=0,真实标签=Iris-setosa
预测为Iris-setosa,预测正确
================================================
离散化后的测试数据:SepalLength=0,SepalWidth=1,PetalLength=0,PetalWidth=0,真实标签=Iris-setosa
预测为Iris-setosa,预测正确
================================================
离散化后的测试数据:SepalLength=0,SepalWidth=1,PetalLength=0,PetalWidth=0,真实标签=Iris-setosa
预测为Iris-setosa,预测正确
================================================
离散化后的测试数据:SepalLength=1,SepalWidth=0,PetalLength=1,PetalWidth=1,真实标签=Iris-versicolor
预测为Iris-versicolor,预测正确
================================================
离散化后的测试数据:SepalLength=1,SepalWidth=0,PetalLength=1,PetalWidth=1,真实标签=Iris-versicolor
预测为Iris-versicolor,预测正确
================================================
离散化后的测试数据:SepalLength=2,SepalWidth=1,PetalLength=1,PetalWidth=1,真实标签=Iris-versicolor
预测为Iris-versicolor,预测正确
================================================
离散化后的测试数据:SepalLength=1,SepalWidth=0,PetalLength=1,PetalWidth=1,真实标签=Iris-versicolor
预测为Iris-versicolor,预测正确
================================================
离散化后的测试数据:SepalLength=2,SepalWidth=0,PetalLength=1,PetalWidth=1,真实标签=Iris-versicolor
预测为Iris-versicolor,预测正确
================================================
离散化后的测试数据:SepalLength=1,SepalWidth=0,PetalLength=1,PetalWidth=1,真实标签=Iris-versicolor
预测为Iris-versicolor,预测正确
================================================
离散化后的测试数据:SepalLength=1,SepalWidth=0,PetalLength=1,PetalWidth=1,真实标签=Iris-versicolor
预测为Iris-versicolor,预测正确
================================================
离散化后的测试数据:SepalLength=1,SepalWidth=0,PetalLength=1,PetalWidth=1,真实标签=Iris-versicolor
预测为Iris-versicolor,预测正确
================================================
离散化后的测试数据:SepalLength=1,SepalWidth=0,PetalLength=1,PetalWidth=1,真实标签=Iris-versicolor
预测为Iris-versicolor,预测正确
================================================
离散化后的测试数据:SepalLength=1,SepalWidth=0,PetalLength=1,PetalWidth=1,真实标签=Iris-versicolor
预测为Iris-versicolor,预测正确
================================================
离散化后的测试数据:SepalLength=1,SepalWidth=0,PetalLength=1,PetalWidth=2,真实标签=Iris-virginica
预测为Iris-virginica,预测正确
================================================
离散化后的测试数据:SepalLength=2,SepalWidth=0,PetalLength=2,PetalWidth=2,真实标签=Iris-virginica
预测为Iris-virginica,预测正确
================================================
离散化后的测试数据:SepalLength=2,SepalWidth=0,PetalLength=2,PetalWidth=2,真实标签=Iris-virginica
预测为Iris-virginica,预测正确
================================================
离散化后的测试数据:SepalLength=2,SepalWidth=1,PetalLength=2,PetalWidth=2,真实标签=Iris-virginica
预测为Iris-virginica,预测正确
================================================
离散化后的测试数据:SepalLength=2,SepalWidth=1,PetalLength=2,PetalWidth=2,真实标签=Iris-virginica
预测为Iris-virginica,预测正确
================================================
离散化后的测试数据:SepalLength=2,SepalWidth=1,PetalLength=2,PetalWidth=2,真实标签=Iris-virginica
预测为Iris-virginica,预测正确
================================================
离散化后的测试数据:SepalLength=2,SepalWidth=0,PetalLength=2,PetalWidth=1,真实标签=Iris-virginica
预测为Iris-versicolor,预测错误
================================================
离散化后的测试数据:SepalLength=2,SepalWidth=0,PetalLength=2,PetalWidth=2,真实标签=Iris-virginica
预测为Iris-virginica,预测正确
================================================
离散化后的测试数据:SepalLength=2,SepalWidth=1,PetalLength=2,PetalWidth=2,真实标签=Iris-virginica
预测为Iris-virginica,预测正确
================================================
离散化后的测试数据:SepalLength=2,SepalWidth=1,PetalLength=2,PetalWidth=2,真实标签=Iris-virginica
预测为Iris-virginica,预测正确
-------------------------------------------------------------
决策树预测准确率为:0.9666666666666667
观察决策树的结构,SepalWidth=0
或SepalWidth=1
时的决策结果相同,可以通过剪枝的操作减去多余的子树。同时对数据的分布进行分析,SepalWidth
与SepalLength
的数据重合部分大,对这两个数据进行预剪枝的效果可能更好。
【1】机器学习实战
【2】 机器学习项目实战–基于鸢尾花数据集(python代码,多种算法对比:决策树、SVM、k近邻)_西南交大-Liu_z的博客-CSDN博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。