实验3:决策树
- 实验目的
了解决策树的构建过程和代码实现,应用决策树解决实际问题。
- 实验准备
安装python和pycharm,了解python基础编程和pycharm使用。
三、实验内容
基于iris数据集,补充完整下面决策树的相关程序,粘贴运行成功的结果截图,并给每行程序添加注释。
实验内容:
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import numpy as np
import matplotlib.pyplot as plt
from collections import Counter
from math import log
from graphviz import Digraph #以上均是导包操作
iris = load_iris() #数据集导入,加载 iris 数据集
x = iris.data
#包括样本的特征 data 里面是花萼长度、花萼宽度、花瓣长度、花瓣宽度的测量数据
y = iris.target
#存储了data中每条记录属于哪一类鸢尾植物 标签(结果)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=666666)
'''
feature_train, feature_test, target_train, target_test 分别代表训练集特征、测试集特征、训练集目标值、验证集特征。
train_data:待划分样本数据 对应x
train_target:待划分样本数据的结果(标签) 对应y
test_size:测试数据占样本数据的比例,,如果是整数的话就是样本的数量
random_state:设置随机数种子,保证每次都是同一个随机数。若为0或不填,则每次得到数据都不一样
。
'''
#树结构
class Node:
def __init__(self,x_data, y_label, dimension, value):
#创建树的结构,定义决策树节点包含的数据,及其赋值
self.x_data = x_data #样本数据
self.y_label = y_label #标签(什么种类的花)
self.dimension = dimension #维度索引
self.value = value #结果 划分特征的数值
self.left = None #左孩子
self.right = None #右孩子
#计算熵H=-p1log(p1)-p2log(p2)-p3log(p3)-……-pnlog(pn)
def entropy(y_label):
counter = Counter(y_label)
#读取标签数据,并用counter生成标签的字典数组,标签为键,值为出现的次数
ent = 0.0 #初始化熵值
for num in counter.values(): #遍历counter.values(遍历标签的对应的个数)
p = float(num)/len(y_label)
#计算每个标签的概率 num对应标签出现的次数,len(y_label) 代表总体的数目,相除求概率
ent += -p*log(p)
#计算熵 累加求和计算熵值
return ent #返回熵值
#划分数据集 不断被调用,进行划分操作
def split(x_data, y_label, dimension, value): #对所给数据进行划分
"""
x_data:输入特征
y_label:输入标签类别
dimension:选取输入特征的维度索引
value:划分特征的数值
return 左子树特征,右子树特征,左子树标签,右子树标签
"""
# 比较划分特征的数值与自身特征值
index_left = (x_data[:, dimension] <= value) #若小于则为左子树
index_right = (x_data[:, dimension] > value) #否则为右子树
#相当于进行划分
return x_data[index_left], x_data[index_right], y_label[index_left], y_label[index_right]
#将划分之后的树返回
#划分一次数据集 确定特征和数值 训练过程
#遍历所有维度的特征,不断寻找一个合适的划分数值,找到能把熵降到最低的那个特征和数值
def one_split(x_data, y_label): #将数据集和数据标签传递到函数中
best_entropy = float('inf') #正无穷
best_dimension = -1 #初始化维度索引,无意义
best_value = -1 #初始化划分特征的数值,无意义
for d in range( x_data.shape[1] ):
#循环特征 #####对每个特征进行划分,所以这里要循环遍历维度索引
sorted_index = np.argsort(x_data[:, d])
#对数据按照不同纬度方向进行排序,并返回索引
for i in range(1, len(x_data)): #遍历数据集中所有的数据
if x_data[sorted_index[i], d] != x_data[sorted_index[i - 1], d]:
#判断前后两组数据的值是否相等,除掉一些不必要的运算,加快程序执行时间
value = (x_data[sorted_index[i], d] + x_data[sorted_index[i - 1], d]) / 2
#如果不相等,让两组数据中的value值取中,作为备选值
x_left, x_right, y_left, y_right = split(x_data, y_label, d, value)
#调用划分函数,进行划分操作
p_left=len(x_left)/len(x_data)
#求出划分到左子树的概率
p_right = len(x_right) / len(x_data)
#求出划分到右子树的概率
ent = p_left * entropy(y_left) + p_right * entropy(y_right)
#计算两者熵值之和
if ent < best_entropy:
#若新的熵值较小,那么证明新的value值更适合,则将对应维度的最佳熵 值、最佳划分值进行更新
best_entropy =ent
#将当前熵值赋值给最佳熵值
best_dimension =d
#维度索引更新,保持与当前一致
best_value = value
#更新value值
return best_entropy, best_dimension, best_value
#返回最优的划分熵值、索引、划分值
#创建决策树
def create_tree(x_data, y_label): #传入数据集以及标签结果
ent, dim, value = one_split(x_data, y_label) #对数据集进行一次划分
x_left, x_right, y_left, y_right = split(x_data, y_label, dim, value)
#根据得到的划分数据(dim、vlaue值)对测试数据集进行划分
node = Node(x_data, y_label, dim, value)
#初始化划分节点,根据划分节点进行判断花的种类 (二分)
if ent < 0.000000001:
#判断精度,即当熵值小于一定值时,认为划分是正确的
return node
#返回这个节点,叶子节点
node.left = create_tree( x_left , y_left )#创建左子树
node.right = create_tree( x_right , y_right ) #创建右子树
return node
#返回当前树根节点,这样就构造出一棵决策树,所以第一个返回的值即为整棵树的根节点
#根据已创建的决策树,查找所属类别
def travel(x_data, node):
# 传入待验证样本数据 传入已创建完成的决策树的根节点
p = node #将树的根节点赋值给p
if x_data[p.dimension] <= p.value and p.left:
#如果满足左子树条件且左子树不为空
pred = travel(x_data, p.left)
elif x_data[p.dimension] > p.value and p.right:
#如果满足右子树条件且右子树不为空
pred = travel(x_data, p.right)
else: #否则到达叶子节点,判断结束
counter = Counter(p.y_label)
#将标签种类生成对应的字典数组
pred = counter.most_common(1)[0][0]
#统计出现频率最高的标签,只有一个也就是0 1判断,将是1(值)的标签(key)返回
return pred #将该值返回,证明此数据
#预测函数
def predict(node,x_predict): #传入决策树和预测样本集
y_predict = []
#用于存储获得的决策结果标签集 (由该程序创建的决策树的决策结果)
for data in x_predict: #遍历预测样本
y_pred = travel(data, node) #对每一个遍历的数据进行决策判断
y_predict.append(y_pred) #存储正确的结果集
return np.array(y_predict) #返回该结果集
#预测准确率
def score( x_test, y_test,node): #传入测试数据集、测试数据标签集、决策树根节点
y_predict = predict(node,x_test) #调用预测函数,返回值为预测数据标签集
return np.sum(y_predict == y_test) / len(y_predict)
#比较预测数据标签集和正确测试数据标签集,并返回正确预测的个数与测试个树的比值,即是预测正确率
if __name__ == '__main__':
node=create_tree(x_data=x_train,y_label=y_train)
#根据训练集生成决策树,并保存决策树根节点
xx=score(x_test,y_test,node) #调用计算预测正确率函数,返回正确率
print(xx) #打印正确率
实验结果: