决策树(分类树)算法

import numpy as np
import pandas as pd
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
import graphviz

# ID3算法 以信息增益为准划分属性

'''
	函数功能: 计算信息熵
	:param dataSet 原始数据集
	:return ent 信息熵的值
'''


def calEnt(dataSet):
	n = dataSet.shape[0]  # 数据集总行数
	iset = dataSet.iloc[:, -1].value_counts()  # 标签所有类别
	p = iset / n  # 每个类别所占标签比

	# -p * np.log2(p) 计算香农熵公式

	ent = (-p * np.log2(p)).sum()  # 计算信息熵(所有类别的香农熵之和)

	return ent


'''
	构建数据集
'''


def createDataSet():
	row_data = {
		'no surfacing': [1, 1, 1, 0, 0],
		'flippers': [1, 1, 0, 1, 1],
		'fish': ['yes', 'yes', 'no', 'no', 'no']
	}
	dataSet = pd.DataFrame(row_data)
	return dataSet


'''
	函数功能: 根据信息增益选择出最佳数据集切分的列
	:param dataSet 原始数据集
	:return axis 数据集的最佳切分列的索引
'''


# 选择最优的列进行切分
def bestSplit(dataSet):
	baseEnt = calEnt(dataSet)  # 计算原始的信息熵
	bestGain = 0  # 初始化信息增益
	axis = -1  # 初始化最佳切分列,标签列  也就是从根节点开始切分
	for i in range(dataSet.shape[1] - 1):  # 对特征的每一列进行循环
		leaves = dataSet.iloc[:, i].value_counts().index  # 提取出当前列的所有取值
		ents = 0  # 初始化子节点的信息熵
		for j in leaves:  # 对当前列的每一个取值进行循环
			childSet = dataSet[dataSet.iloc[:, i] == j]  # 某一个子节点的dataFrame
			ent = calEnt(childSet)  # 计算某个子节点的信息熵
			ents += (childSet.shape[0] / dataSet.shape[0]) * ent  # 计算当前列的信息熵
		infoGain = baseEnt - ents
		if (infoGain > bestGain):
			bestGain = infoGain
			axis = i
	return axis


'''
	按照给定列切分数据集
	:params dataSet 原始数据集
			axis 指定列索引
			value: 指定属性值
	:return redataSet   按照指定列索引和属性值切分后的数据集
'''


def mySplit(dataSet, axis, value):
	col = dataSet.columns[axis]
	redataSet = dataSet.loc[dataSet[col] == value, :].drop(col, axis=1)  # 移除已经使用过的特征 axis=1->根据col按列删除
	return redataSet


'''
	函数功能 递归构建决策树
	:param dataSet
'''


def createTree(dataSet):
	featList = list(dataSet.columns)  # 提取出数据集的所有的列特征
	classList = dataSet.iloc[:, -1].value_counts()  # 获取最后一列类标签
	# 判断最多标签数目是否等于数据集行数 或者数据集是否只有一列
	if classList[0] == dataSet.shape[0] or dataSet.shape[1] == 1:
		return classList.index[0]  # 如果是则返回类标签 退出递归的条件
	axis = bestSplit(dataSet)  # 确定出当前最佳划分列的索引
	bestFeat = featList[axis]  # 获取该索引对应的特征

	# 采用字典嵌套的方式存储树信息
	myTree = {
		bestFeat: {}
	}

	del featList[axis]  # 删除当前特征
	valueList = set(dataSet.iloc[:, axis])  # 提取最佳切分列所有属性值
	for value in valueList:  # 对每一个属性值递归建树
		myTree[bestFeat][value] = createTree(mySplit(dataSet, axis, value))
	return myTree


'''
	函数功能 使用决策树执行分类
	:params inputTree: 已经生成的决策树
			labels: 存储选择的最优特征标签
			testVec: 测试数据列表,顺序对应原数据集
	:return classLabel : 分类结果
'''
def classify(inputTree, labels, testVec):
	firstStr = next(iter(inputTree))  # 获取决策树的第一个节点
	secondDict = inputTree[firstStr]  # 下一个字典
	print(secondDict)
	featIndex = labels.index(firstStr)  # 第一个节点的列索引
	for key in secondDict.keys():
		if testVec[featIndex] == key:
			if type(secondDict[key]) == dict:
				classLabel = classify(secondDict[key], labels, testVec)
			else:
				classLabel = secondDict[key]
	return classLabel


'''
	函数功能:对测试集进行预测,并返回预测后的结果
	:params train: 训练集
			test: 测试集
	:return test: 预测好分类的测试集
'''
def acc_classify(train, test):
	inputTree = createTree(train)
	labels = list(train.columns)
	result = []
	for i in range(test.shape[0]):
		testVec = test.iloc[i, : -1]
		classLabel = classify(inputTree, labels, testVec)
		result.append(classLabel)
	test['predic'] = result

	acc = (test.iloc[:,-1] == test.iloc[:, -2]).mean()
	print(f'模型预测准确率为{acc}')
	return test

dataSet = createDataSet()
train = dataSet
test = dataSet.iloc[:3,:]
acc_classify(train, test)



'''
dataSet = createDataSet()

# 特征
Xtrain = dataSet.iloc[:,:-1]
# 标签
Ytrain = dataSet.iloc[:,-1]
labels = Ytrain.unique().tolist()
# 将文本转化为数字
Ytrain = Ytrain.apply(lambda  x : labels.index(x))

# 绘制树模型
clf = DecisionTreeClassifier()
clf = clf.fit(Xtrain, Ytrain)
tree.export_graphviz(clf)
dot_data = tree.export_graphviz(clf, out_file=None)
graphviz.Source(dot_data)

# 绘制图形增加标签和颜色
dot_data = tree.export_graphviz(
	clf, out_file=None,
	feature_names=['no surfacing','flippers'],
	class_names=['fish','not fish'],
	filled=True,
	rounded=True,
	special_characters=True
)

graphviz.Source(dot_data)

# 利用render方法生成图形
graph = graphviz.Source(dot_data)
graph.render("fish")
'''
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值