优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据
缺点:可能会产生过度匹配问题
适用数据类型:数值型和标称型
一个数据集中,X是这个集合每个数据对应的类别(比如要不要出去玩、是不是鱼等等)。对于变量X,它可能的取值有n多种,分别是x1,x2,……,xn,每一种取到的概率分别是P1,P2,……,Pn,那么集合的熵(对于x而言)就定义为:
一个集合类别可能的变化越多(只和值的种类多少以及发生概率有关,与具体值是多少无关),它携带的信息量就越大
下面给出计算数据集香农熵的python代码:
from math import log #伪造一些关于是否为鱼类的特征和标签 def createDataSet(): dataSet= [ [1,1,'yes'], #每个字段分别代表 在水下是否可以生存, 是否有脚蹼, 是否属于鱼类 [1,1,'yes'], [1,0,'no'], [0,1,'no'], [0,1,'no'] ] labels=['noSurfacing' , 'flippers'] return dataSet, labels #计算香农熵 参数说明: dataSet是一个数据集合,indexOfLabel是表明每条数据所属类别的下标 def calcShannonEnt(dataSet, indexOfLabel): entriesNum=len(dataSet) #计算数据总条目数 labelCounts={} #每个类别有多少个 for featVec in dataSet: label = featVec[indexOfLabel] if label not in labelCounts.keys(): labelCounts[label]=0 labelCounts[label] +=1 shannonEnt=0.0 for key in labelCounts: #套用上方的计算式 prob=float(labelCounts[key])/entriesNum shannonEnt -= prob* log(prob,2) return shannonEnt
#根据给定特征划分数据集 def splitDataSet(dataSet, axis, value): #待划分的数据集, 划分数据集的特征,特征的值 retDataSet = [] for featVec in dataSet: if featVec[axis] == value: #把符合要求的这条数据加入到返回集合中,但是要除去传入的特征 reducedFeatVec= featVec[:axis] reducedFeatVec.extend(featVec[axis+1:]) retDataSet.append(reducedFeatVec) return retDataSet def chooseBestFeatToSplit(dataSet): featureNum=len(dataSet[0])-1 baseEntropy = calcShannonEnt(dataSet,-1) #原始香农熵 bestInfoGain=0.0 ; bestFeature=-1 for i in range(featureNum): #创建唯一的分类标签列表 featList=[example[i] for example in dataSet] uniqueVals=set(featList) newEntropy=0.0 #计算每种划分方式的熵 for value in uniqueVals: subDataSet=splitDataSet(dataSet,i,value) prob=len(subDataSet)/float(len(dataSet)) newEntropy +=prob*calcShannonEnt(subDataSet,-1) infoGain=baseEntropy-newEntropy #计算最好的信息增益 if infoGain>bestInfoGain: bestInfoGain=infoGain bestFeature=i return bestFeature if __name__=="__main__": dataset,labels=createDataSet() print chooseBestFeatToSplit(dataset)
#获取出现次数最多的类别 def getMostType(typeList): typeCounts={} #每个类别有多少个 for type in typeList: if type not in typeCounts.keys(): typeCounts[type]=0 typeCounts[type] +=1 mostCount=0; mostType=''; for type in typeCounts.keys(): if typeCounts[type] > mostCount: mostCount=typeCounts[type] mostType=type return mostType #递归创建 def createTree(dataSet,labels,indexOfType): typeList=[example[-1] for example in dataSet] #类别完全相同则停止划分 if typeList.count(typeList[0]) == len(typeList): return typeList[0] if len(dataSet[0]) ==1: return getMostType(typeList) bestFeat = chooseBestFeatToSplit(dataSet) bestFeatLabel = labels[bestFeat] myTree={bestFeatLabel:{}} del(labels[bestFeat]) featValues=[example[bestFeat] for example in dataSet] uniqueValues=set(featValues) for value in uniqueValues: subLabels = labels[:] myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),subLabels,indexOfType) return myTree if __name__=="__main__": dataset,labels=createDataSet() print createTree(dataset,labels,-1)