数据集按类划分_实现ID3算法⽤于鸢尾花(Iris)数据分类及
实现confusionmat。。。
从训练数据划分,到分类器性能评价均没有使⽤scikit-learn中的⽅法
代码
代码中有着详细的注释,直接看就好
tree.py
import collections
import random
import string
from math import log
import pandas as pd
import operator
from ID3HW import treePlotter
def calcShannonEnt(dataSet):
"""
计算给定数据集的信息熵(⾹农熵)
:param dataSet:
:return:
"""
# 计算出数据集的总数
numEntries = len(dataSet)
# ⽤来统计标签
labelCounts = collections.defaultdict(int)
四级士官# 循环整个数据集,得到数据的分类标签
for featVec in dataSet:
# 得到当前的标签
currentLabel = featVec[-1]
# 将对应的标签值加⼀
labelCounts[currentLabel] += 1
# 默认的信息熵
shannonEnt = 0.0
for key in labelCounts:
# 计算出当前分类标签占总标签的⽐例数
prob = float(labelCounts[key]) / numEntries
# 以2为底求对数
shannonEnt -= prob * log(prob, 2)
return shannonEnt
def splitDataSetForSeries(dataSet, axis, value):
"""
按照给定的数值,将数据集分为不⼤于和⼤于两部分
:param dataSet: 要划分的数据集
:param i: 特征值所在的下标
:param value: 划分值
:return:
"""
# ⽤来保存不⼤于划分值的集合
eltDataSet = []
eltDataSet = []
# ⽤来保存⼤于划分值的集合
gtDataSet = []
# 进⾏划分,保留该特征值
for feat in dataSet:
if feat[axis] <= value:
eltDataSet.append(feat)
el:
gtDataSet.append(feat)
return eltDataSet, gtDataSet
def splitDataSet(dataSet, axis, value):
"""
按照给定的特征值,将数据集划分
:param dataSet: 数据集
:param axis: 给定特征值的坐标
幸福的颜色:param value: 给定特征值满⾜的条件,只有给定特征值等于这个value的时候才会返回 :return:
"""
# 创建⼀个新的列表,防⽌对原来的列表进⾏修改
retDataSet = []
# 遍历整个数据集
for featVec in dataSet:
# 如果给定特征值等于想要的特征值
if featVec[axis] == value:
# 将该特征值前⾯的内容保存起来
reducedFeatVec = featVec[:axis]
# 将该特征值后⾯的内容保存起来,所以将给定特征值给去掉了
# 添加到返回列表中
retDataSet.append(reducedFeatVec)
return retDataSet
def calcInfoGainForSeries(dataSet, i, baEntropy):
"""
计算连续值的信息增益
:param dataSet:整个数据集
:param i: 对应的特征值下标
:param baEntropy: 基础信息熵
:return: 返回⼀个信息增益值,和当前的划分点
"""
# 记录最⼤的信息增益
maxInfoGain = 0.0
# 最好的划分点
bestMid = -1
# 得到数据集中所有的当前特征值列表
featList = [example[i] for example in dataSet]
# 得到分类列表
classList = [example[-1] for example in dataSet]
dictList = dict(zip(featList, classList))
# 将其从⼩到⼤排序,按照连续值的⼤⼩排列
sortedFeatList = sorted(dictList.items(), key=operator.itemgetter(0))
# 计算连续值有多少个
numberForFeatList = len(sortedFeatList)
# 计算划分点,保留三位⼩数
midFeatList = [round((sortedFeatList[i][0] + sortedFeatList[i + 1][0]) / 2.0, 3) for i in
range(numberForFeatList - 1)]
# 计算出各个划分点信息增益
for mid in midFeatList:
# 将连续值划分为不⼤于当前划分点和⼤于当前划分点两部分
eltDataSet, gtDataSet = splitDataSetForSeries(dataSet, i, mid)
# 计算两部分的特征值熵和权重的乘积之和
newEntropy = len(eltDataSet) / len(dataSet) * calcShannonEnt(eltDataSet) + len(gtDataSet) / len( dataSet) * calcShannonEnt(gtDataSet)
# 计算出信息增益
infoGain = baEntropy - newEntropy
# print('当前划分值为:' + str(mid) + ',此时的信息增益为:' + str(infoGain))
if infoGain > maxInfoGain:
bestMid = mid
maxInfoGain = infoGain
return maxInfoGain, bestMid
def calcInfoGain(dataSet, featList, i, baEntropy):
"""
计算信息增益
:param dataSet: 数据集
:param featList: 当前特征列表
:param i: 当前特征值下标
:param baEntropy: 基础信息熵
:
return:
"""
# 将当前特征唯⼀化,也就是说当前特征值中共有多少种
uniqueVals = t(featList)
# 新的熵,代表当前特征值的熵
newEntropy = 0.0
# 遍历现在有的特征的可能性
for value in uniqueVals:
# 在全部数据集的当前特征位置上,找到该特征值等于当前值的集合
subDataSet = splitDataSet(dataSet=dataSet, axis=i, value=value)
# 计算出权重
prob = len(subDataSet) / float(len(dataSet))
# 计算出当前特征值的熵
newEntropy += prob * calcShannonEnt(subDataSet)
# 计算出“信息增益”
infoGain = baEntropy - newEntropy
return infoGain
def chooBestFeatureToSplit(dataSet, labels):
"""
选择最好的数据集划分特征,根据信息增益值来计算,可处理连续值
:param dataSet:
:return:
鲁迅说过法考考哪些科目
"""
# 得到数据的特征值总数
numFeatures = len(dataSet[0]) - 1
# 计算出基础信息熵
baEntropy = calcShannonEnt(dataSet)
# 基础信息增益为0.0
bestInfoGain = 0.0
# 最好的特征值
bestFeature = -1
# 标记当前最好的特征值是不是连续值
flagSeries = 0
# 如果是连续值的话,⽤来记录连续值的划分点
bestSeriesMid = 0.0
# 对每个特征值进⾏求信息熵
for i in range(numFeatures):
# 得到数据集中所有的当前特征值列表
featList = [example[i] for example in dataSet]
if isinstance(featList[0], str):
infoGain = calcInfoGain(dataSet, featList, i, baEntropy)
el:
# print('当前划分属性为:' + str(labels[i]))
infoGain, bestMid = calcInfoGainForSeries(dataSet, i, baEntropy)
# print('当前特征值为:' + labels[i] + ',对应的信息增益值为:' + str(infoGain))
# 如果当前的信息增益⽐原来的⼤
if infoGain > bestInfoGain:
# 最好的信息增益
bestInfoGain = infoGain
# 新的最好的⽤来划分的特征值
bestFeature = i
flagSeries = 0
if not isinstance(dataSet[0][bestFeature], str):
flagSeries = 1
bestSeriesMid = bestMid
# print('信息增益最⼤的特征为:' + labels[bestFeature])
if flagSeries:
return bestFeature, bestSeriesMid
el:
return bestFeature
印堂纹大全def getDataSet(test_size):
"""
非洲人图片创建测试的数据集,⾥⾯的数值中具有连续值
:return:
"""
dataSet = pd.read_csv("iris.data").list()
random.shuffle(dataSet)
train_datat = dataSet[:int(len(dataSet) * (1 - test_size))] # 训练数据
test_datat = dataSet[int(len(dataSet) * (1 - test_size)):] # 测试数据
# 特征值列表
labels = ['pal length', 'pal width', 'petal length', 'petal width']
return train_datat, test_datat, labels
def majorityCnt(classList):
"""
找到次数最多的类别标签
:param classList:
:return:
三角计算器
"""
# ⽤来统计标签的票数
classCount = collections.defaultdict(int)
# 遍历所有的标签类别
for vote in classList:
classCount[vote] += 1
# 从⼤到⼩排序
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), rever=True)
# 返回次数最多的标签
return sortedClassCount[0][0]
def createTree(dataSet, labels):
"""
创建决策树
:param dataSet: 数据集
:param labels: 特征标签
:return:
"""
# 拿到所有数据集的分类标签
classList = [example[-1] for example in dataSet]
# 统计第⼀个标签出现的次数,与总标签个数⽐较,如果相等则说明当前列表中全部都是⼀种标签,此时停⽌划分 unt(classList[0]) == len(classList):
return classList[0]
# 计算第⼀⾏有多少个数据,如果只有⼀个的话说明所有的特征属性都遍历完了,剩下的⼀个就是类别标签
if len(dataSet[0]) == 1:
# 返回剩下标签中出现次数较多的那个
return majorityCnt(classList)
# 选择最好的划分特征,得到该特征的下标
bestFeat = chooBestFeatureToSplit(dataSet=dataSet, labels=labels)
冠族
# 得到最好特征的名称
bestFeatLabel = ''
# 记录此刻是连续值还是离散值,1连续,2离散
flagSeries = 0
# 如果是连续值,记录连续值的划分点
midSeries = 0.0
# 如果是元组的话,说明此时是连续值
if isinstance(bestFeat, tuple):
# 重新修改分叉点信息
bestFeatLabel = str(labels[bestFeat[0]]) + '=' + str(bestFeat[1])
# 得到当前的划分点
midSeries = bestFeat[1]
# 得到下标值
bestFeat = bestFeat[0]
# 连续值标志
flagSeries = 1
el:
# 得到分叉点信息
bestFeatLabel = labels[bestFeat]
# 离散值标志
flagSeries = 0