from math import log
import operator
def calcShannonent(dataSet): #计算数据的熵(entropy)
numEntries = len(dataSet) #数据条数
labelCounts = {}
for featVec in dataSet:
currentLabel = featVec[-1] #每行数据的最后一个字(类别)
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1 #统计又多少个类以及每个类的数量
shannonEnt = 0
for key in labelCounts:
prob = float(labelCounts[key])/numEntries #计算单个类的熵值
shannonEnt -= prob*log(prob, 2) #累加每个类的熵值
return shannonEnt
def createDataSet_temp():
#创造实例数据
labels = ['头发', '声音']
with open('TreeGrowth_ID3.txt', 'r', encoding='UTF-8') as f: #改了一个文件读写
dataSet = [[] for i in range(9)]
value = ['长', '短', '粗', '细', '男', '女']
num_line = 0
for line in f:
# re.split(r'(\s{8}\[\')|(\', \')|(\'\],)|(\'\])', line) #尝试使用正则划分,失败了
for i in line:
if (i in value):
dataSet[num_line].append(i)
num_line += 1
del(dataSet[0])
'''
dataSet = [
['长', '粗', '男'],
['短', '粗', '男'],
['短', '粗', '男'],
['长', '细', '女'],
['短', '细', '女'],
['短', '粗', '女'],
['长', '粗', '女'],
['长', '粗', '女']
]
'''
return dataSet, labels
def splitDataSet(dataSet, axis, value): #按某个特征分类后的数据
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value: #axis表示指定属性在label中的标号,value是该分类中属性的目标值
reducedFeatVec = featVec[:axis] #对于每一条记录,在分完类后,都要把之前使用过的属性删除
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet
def chooseBestFeatureToSplit(dataSet): #选择最优的分类特征
numFeatures = len(dataSet[0])-1 #特征的个数
baseEntropy = calcShannonent(dataSet) #原始熵
bestInfoGain = 0
bestFeature = -1
for i in range(numFeatures): #循环每一个特征
featList = [example[i] for example in dataSet]#读取每一条记录取出其中第i个属性的值,并新建一个列表
uniqueVals = set(featList) #set()创建一个无序不重复元素集,可进行关系测试,删除重复元素,进行交差并集运算
newEntropy = 0
for value in uniqueVals: #对于第i个属性值列表中每一个值
subDataSet = splitDataSet(dataSet, i, value) #subDataSet是去掉了第i个属性值是value的列表
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob*calcShannonent(subDataSet) #按特征分类后的熵
infoGain = baseEntropy - newEntropy #计算信息增益
if(infoGain > bestInfoGain): #若按某特征划分后,熵值减少的最大,则次特征为最优分类特征
bestInfoGain = infoGain
bestFeature = i
return bestFeature
def majorityCnt(classList): #多数表决排序,如:最后分类为2男1女则判断为男
classCount = {}
for vote in classList:
if vote not in classCount.keys():
classCount[vote] = 0
classCount[vote] += 1
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
#将items返回的可遍历键值对数组,根据键值对的第二个域(值),进行降序排列
return sortedClassCount[0][0] #返回数量最大的类名
def createTree(dataSet,labels):
classList = [example[-1] for example in dataSet]#类别:男或女 对于记录集中的每一条都取其最后一个值形成列表
if classList.count(classList[0]==len(classList)):#~~~~~~~~~~~~~~~~~~~当该记录集只有一个特征时
return classList[0]
if len(dataSet[0])==1: #当最后一个属性分类完成,记录的长为一
return majorityCnt((classList)) #直接返回数量最多的值
bestFeat = chooseBestFeatureToSplit(dataSet) #找到最优特征的标号
if(bestFeat == -1): #自己添加的,不然报错
return classList[0]
bestFeatLabel = labels[bestFeat] #找到最优特征
myTree = {bestFeatLabel:{}} #分类结果以字典形式保存,得到树的当前层
del(labels[bestFeat]) #删除labels中当前最优特征
featValues = [example[bestFeat] for example in dataSet]#将记录集中当前最优特征的值形成列表
uniqueVals = set(featValues) #对值集去重
for value in uniqueVals: #对于每个值
subLabels = labels[:] #subLabels为去除当前最优特征的特征集
myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
#使用递归,创造下一层树,~~~~~~~~~~~~~~~~~~~~~~
return myTree
if __name__=='__main__':
dataSet, labels = createDataSet_temp() #创造示例数据
print(createTree(dataSet, labels)) #输出决策树模型结果
代码来自:https://blog.csdn.net/csqazwsxedc/article/details/65697652
改了一点点
加了很多注释