Python實現(xiàn)決策樹C4.5算法的示例
為什么要改進成C4.5算法
原理
C4.5算法是在ID3算法上的一種改進,它與ID3算法最大的區(qū)別就是特征選擇上有所不同,一個是基于信息增益比,一個是基于信息增益。
之所以這樣做是因為信息增益傾向于選擇取值比較多的特征(特征越多,條件熵(特征劃分后的類別變量的熵)越小,信息增益就越大);因此在信息增益下面加一個分母,該分母是當(dāng)前所選特征的熵,注意:這里而不是類別變量的熵了。
這樣就構(gòu)成了新的特征選擇準則,叫做信息增益比。為什么加了這樣一個分母就會消除ID3算法傾向于選擇取值較多的特征呢?
因為特征取值越多,該特征的熵就越大,分母也就越大,所以信息增益比就會減小,而不是像信息增益那樣增大了,一定程度消除了算法對特征取值范圍的影響。
實現(xiàn)
在算法實現(xiàn)上,C4.5算法只是修改了信息增益計算的函數(shù)calcShannonEntOfFeature和最優(yōu)特征選擇函數(shù)chooseBestFeatureToSplit。
calcShannonEntOfFeature在ID3的calcShannonEnt函數(shù)上加了個參數(shù)feat,ID3中該函數(shù)只用計算類別變量的熵,而calcShannonEntOfFeature可以計算指定特征或者類別變量的熵。
chooseBestFeatureToSplit函數(shù)在計算好信息增益后,同時計算了當(dāng)前特征的熵IV,然后相除得到信息增益比,以最大信息增益比作為最優(yōu)特征。
在劃分數(shù)據(jù)的時候,有可能出現(xiàn)特征取同一個值,那么該特征的熵為0,同時信息增益也為0(類別變量劃分前后一樣,因為特征只有一個取值),0/0沒有意義,可以跳過該特征。

#coding=utf-8
import operator
from math import log
import time
import os, sys
import string
def createDataSet(trainDataFile):
print trainDataFile
dataSet = []
try:
fin = open(trainDataFile)
for line in fin:
line = line.strip()
cols = line.split('\t')
row = [cols[1], cols[2], cols[3], cols[4], cols[5], cols[6], cols[7], cols[8], cols[9], cols[10], cols[0]]
dataSet.append(row)
#print row
except:
print 'Usage xxx.py trainDataFilePath'
sys.exit()
labels = ['cip1', 'cip2', 'cip3', 'cip4', 'sip1', 'sip2', 'sip3', 'sip4', 'sport', 'domain']
print 'dataSetlen', len(dataSet)
return dataSet, labels
#calc shannon entropy of label or feature
def calcShannonEntOfFeature(dataSet, feat):
numEntries = len(dataSet)
labelCounts = {}
for feaVec in dataSet:
currentLabel = feaVec[feat]
if currentLabel not in labelCounts:
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0
for key in labelCounts:
prob = float(labelCounts[key])/numEntries
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 chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1 #last col is label
baseEntropy = calcShannonEntOfFeature(dataSet, -1)
bestInfoGainRate = 0.0
bestFeature = -1
for i in range(numFeatures):
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 *calcShannonEntOfFeature(subDataSet, -1) #calc conditional entropy
infoGain = baseEntropy - newEntropy
iv = calcShannonEntOfFeature(dataSet, i)
if(iv == 0): #value of the feature is all same,infoGain and iv all equal 0, skip the feature
continue
infoGainRate = infoGain / iv
if infoGainRate > bestInfoGainRate:
bestInfoGainRate = infoGainRate
bestFeature = i
return bestFeature
#feature is exhaustive, reture what you want label
def majorityCnt(classList):
classCount = {}
for vote in classList:
if vote not in classCount.keys():
classCount[vote] = 0
classCount[vote] += 1
return max(classCount)
def createTree(dataSet, labels):
classList = [example[-1] for example in dataSet]
if classList.count(classList[0]) ==len(classList): #all data is the same label
return classList[0]
if len(dataSet[0]) == 1: #all feature is exhaustive
return majorityCnt(classList)
bestFeat = chooseBestFeatureToSplit(dataSet)
bestFeatLabel = labels[bestFeat]
if(bestFeat == -1): #特征一樣,但類別不一樣,即類別與特征不相關(guān),隨機選第一個類別做分類結(jié)果
return classList[0]
myTree = {bestFeatLabel:{}}
del(labels[bestFeat])
featValues = [example[bestFeat] for example in dataSet]
uniqueVals = set(featValues)
for value in uniqueVals:
subLabels = labels[:]
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)
return myTree
def main():
if(len(sys.argv) < 3):
print 'Usage xxx.py trainSet outputTreeFile'
sys.exit()
data,label = createDataSet(sys.argv[1])
t1 = time.clock()
myTree = createTree(data,label)
t2 = time.clock()
fout = open(sys.argv[2], 'w')
fout.write(str(myTree))
fout.close()
print 'execute for ',t2-t1
if __name__=='__main__':
main()
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python實現(xiàn)的遠程文件自動打包并下載功能示例
這篇文章主要介紹了Python實現(xiàn)的遠程文件自動打包并下載功能,結(jié)合實例形式分析了Python使用spawn()方法執(zhí)行ssh、scp 命令實現(xiàn)遠程文件的相關(guān)操作技巧,需要的朋友可以參考下2019-07-07
Python通過Socket手動實現(xiàn)HTTP協(xié)議
這篇文章主要為大家詳細介紹了Python如何通過Socket手動實現(xiàn)HTTP協(xié)議,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一2024-03-03
Python?Matplotlib通過plt.subplots創(chuàng)建子繪圖
這篇文章主要介紹了Python?Matplotlib通過plt.subplots創(chuàng)建子繪圖,plt.subplots調(diào)用后將會產(chǎn)生一個圖表和默認網(wǎng)格,與此同時提供一個合理的控制策略布局子繪圖,更多相關(guān)需要的朋友可以參考下面文章內(nèi)容2022-07-07
Python實現(xiàn)抓取網(wǎng)頁并且解析的實例
這篇文章主要介紹了Python實現(xiàn)抓取網(wǎng)頁并且解析的功能實例,主要以解析百度問答為例說明其原理與方法,需要的朋友可以參考下2014-09-09
python_array[0][0]與array[0,0]的區(qū)別詳解
今天小編就為大家分享一篇python_array[0][0]與array[0,0]的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02

