C4.5算法是在ID3算法上的一种改进,它与ID3算法最大的区别就是特征选择上有所不同,一个是基于信息增益比,一个是基于信息增益。
之所以这样做是因为信息增益倾向于选择取值比较多的特征(特征越多,条件熵(<强>特征划分后>强劲的类别变量的熵)越小,信息增益就越大),因此在信息增益下面加一个分母,该分母是当前所选<强>特征的熵>强,注意:这里而不是类别<强>变量的熵强>了。
这样就构成了新的特征选择准则,叫做信息增益比。为什么加了这样一个分母就会消除ID3算法倾向于选择取值较多的特征呢?
因为特征取值越多,该特征的熵就越大,分母也就越大,所以信息增益比就会减小,而不是像信息增益那样增大了,一定程度消除了算法对特征取值范围的影响。
在算法实现上,C4.5算法只是修改了信息增益计算的函数calcShannonEntOfFeature和最优特征选择函数chooseBestFeatureToSplit。
calcShannonEntOfFeature在ID3的calcShannonEnt函数上<强>加了个参数壮举>强,ID3中该函数只用计算类别变量的熵,而calcShannonEntOfFeature可以计算指定特征或者类别变量的熵。
chooseBestFeatureToSplit函数在计算好信息增益后,同时计算了<强>当前特征的熵IV >强,然后相除得到信息增益比,以最大信息增益比作为最优特征。
在划分数据的时候,有可能出现特征取同一个值,那么该特征的熵为0,同时信息增益也为0(类别变量划分前后一样,因为特征只有一个取值),0/0没有意义,可以跳过该特征。
#=utf - 8编码 进口经营者 从数学导入日志 导入的时间 导入系统,系统 进口的字符串 def createDataSet (trainDataFile): 打印trainDataFile 数据集=[] 试一试: 鳍=开放(trainDataFile) 在鳍线: 行=line.strip () 关口=line.split (“\ t”) 行=[关口[1],[2]的山谷,关口[3],[4]的山谷,关口[5],[6]的山谷,关口[7],[8]的山谷,关口[9],关口[10],[0]]的山谷 dataSet.append(行) 打印行号 除了: 打印“使用xxx。py trainDataFilePath” 西斯退出() 标签=[‘cip1’,‘cip2’,‘cip3’,‘cip4’,‘sip1’,‘sip2’,‘sip3’,‘sip4’,‘运动’,‘域’) 打印dataSetlen, len(数据集) 返回数据集,标签 # calc香农熵的标签或特性 def calcShannonEntOfFeature(数据集,专长): numEntries=len(数据集) labelCounts={} feaVec的数据集: currentLabel=feaVec(专长) 如果currentLabel不在labelCounts: labelCounts [currentLabel]=0 labelCounts [currentLabel] +=1 shannonEnt=0.0 在labelCounts关键: 概率=浮动(labelCounts[主要])/numEntries shannonEnt -=概率*日志(问题2) 返回shannonEnt def splitDataSet(数据集、轴、价值): retDataSet=[] featVec的数据集: 如果featVec(轴)==值: reducedFeatVec=featVec(轴): reducedFeatVec.extend (featVec[轴+ 1:]) retDataSet.append (reducedFeatVec) 返回retDataSet def chooseBestFeatureToSplit(数据): numFeatures=len(数据集[0])——1 #最后坳是标签 baseEntropy=calcShannonEntOfFeature(数据集,1) bestInfoGainRate=0.0 bestFeature=1 因为我在范围(numFeatures): featList=(例子[我]例如数据集) uniqueVals=集(featList) newEntropy=0.0 uniqueVals价值: subDataSet=splitDataSet(数据集,我,值) 概率=len (subDataSet)/浮动(len(数据集) newEntropy +=概率* calcShannonEntOfFeature (subDataSet, 1) # calc条件熵 infoGain=baseEntropy - newEntropy 4=calcShannonEntOfFeature(数据集,我) 如果(iv==0): #价值的功能都是一样的,infoGain和第四都等于0,跳过功能 继续 infoGainRate=infoGain/iv 如果infoGainRate比;bestInfoGainRate: bestInfoGainRate=infoGainRate bestFeature=我 返回bestFeature #特性是详尽的,回来你想要的标签 def majorityCnt(班级名册): classCount={} 在班级名册投票: 如果投票不在classCount.keys (): classCount(投票)=0 classCount【投票】+=1 返回马克斯(classCount) def createTree(数据集、标签): 班级名册=(例子[1]例如数据集) 如果classList.count(班级名册[0])==len(班级名册):#所有的数据是相同的标签 返回班级名册[0] 如果len(数据集[0])==1:#所有特性是详尽 返回majorityCnt(班级名册) bestFeat=chooseBestFeatureToSplit(数据集) bestFeatLabel=标签(bestFeat) 如果(bestFeat==1): #特征一样,但类别不一样,即类别与特征不相关,随机选第一个类别做分类结果 返回班级名册[0] myTree={bestFeatLabel: {}} 德尔(标签(bestFeat)) featValues=[示例(bestFeat)例如在数据集) uniqueVals=集(featValues) uniqueVals价值: subLabels=标签[:] myTree [bestFeatLabel][]价值=createTree (splitDataSet(数据集,bestFeat、价值),subLabels) 返回myTree def main (): 如果(len (sys.argv) & lt;3): 打印“使用xxx。py小火车outputTreeFile” 西斯退出() 数据标签=createDataSet (sys.argv [1]) t1=time.clock () myTree=createTree(数据、标签) t2=time.clock () 输出信号=(sys开放。argv [2], ' w ') fout.write (str (myTree)) fout.close () 打印“执行”,t2-t1 if __name__==癬_main__”: main ()Python实现决策树C4.5算法的示例