决策树挑选西瓜
目錄
- 決策樹(shù)概念
- 信息熵
- CART算法
- ID3算法實(shí)現(xiàn)
- 使用sklearn庫(kù)實(shí)現(xiàn)
- 總結(jié)
- 參考
決策樹(shù)概念
決策樹(shù)(Decision Tree)是在已知各種情況發(fā)生概率的基礎(chǔ)上,通過(guò)構(gòu)成決策樹(shù)來(lái)求取凈現(xiàn)值的期望值大于等于零的概率,評(píng)價(jià)項(xiàng)目風(fēng)險(xiǎn),判斷其可行性的決策分析方法,是直觀運(yùn)用概率分析的一種圖解法。由于這種決策分支畫(huà)成圖形很像一棵樹(shù)的枝干,故稱決策樹(shù)。在機(jī)器學(xué)習(xí)中,決策樹(shù)是一個(gè)預(yù)測(cè)模型,他代表的是對(duì)象屬性與對(duì)象值之間的一種映射關(guān)系。Entropy = 系統(tǒng)的凌亂程度,使用算法ID3, C4.5和C5.0生成樹(shù)算法使用熵。這一度量是基于信息學(xué)理論中熵的概念。
決策樹(shù)是一種樹(shù)形結(jié)構(gòu),其中每個(gè)內(nèi)部節(jié)點(diǎn)表示一個(gè)屬性上的測(cè)試,每個(gè)分支代表一個(gè)測(cè)試輸出,每個(gè)葉節(jié)點(diǎn)代表一種類別。
分類樹(shù)(決策樹(shù))是一種十分常用的分類方法。它是一種監(jiān)督學(xué)習(xí),所謂監(jiān)督學(xué)習(xí)就是給定一堆樣本,每個(gè)樣本都有一組屬性和一個(gè)類別,這些類別是事先確定的,那么通過(guò)學(xué)習(xí)得到一個(gè)分類器,這個(gè)分類器能夠?qū)π鲁霈F(xiàn)的對(duì)象給出正確的分類。這樣的機(jī)器學(xué)習(xí)就被稱之為監(jiān)督學(xué)習(xí)。
信息熵
所謂信息熵,是一個(gè)數(shù)學(xué)上頗為抽象的概念,在這里不妨把信息熵理解成某種特定信息的出現(xiàn)概率。而信息熵和熱力學(xué)熵是緊密相關(guān)的。根據(jù)Charles H. Bennett對(duì)Maxwell’s Demon的重新解釋,對(duì)信息的銷毀是一個(gè)不可逆過(guò)程,所以銷毀信息是符合熱力學(xué)第二定律的。而產(chǎn)生信息,則是為系統(tǒng)引入負(fù)(熱力學(xué))熵的過(guò)程。所以信息熵的符號(hào)與熱力學(xué)熵應(yīng)該是相反的。
CART算法
Classification And Regression Tree,即分類回歸樹(shù)算法,簡(jiǎn)稱CART算法,它是決策樹(shù)的一種實(shí)現(xiàn),通常決策樹(shù)主要有三種實(shí)現(xiàn),分別是ID3算法,CART算法和C4.5算法。 CART算法是一種二分遞歸分割技術(shù),把當(dāng)前樣本劃分為兩個(gè)子樣本,使得生成的每個(gè)非葉子結(jié)點(diǎn)都有兩個(gè)分支,因此CART算法生成的決策樹(shù)是結(jié)構(gòu)簡(jiǎn)潔的二叉樹(shù)。由于CART算法構(gòu)成的是一個(gè)二叉樹(shù),它在每一步的決策時(shí)只能是“是”或者“否”,即使一個(gè)feature有多個(gè)取值,也是把數(shù)據(jù)分為兩部分。在CART算法中主要分為兩個(gè)步驟
(1)將樣本遞歸劃分進(jìn)行建樹(shù)過(guò)程
(2)用驗(yàn)證數(shù)據(jù)進(jìn)行剪枝
ID3算法實(shí)現(xiàn)
修改數(shù)據(jù)集為:
新建.ipynb:
代碼:
得到結(jié)果:
之后準(zhǔn)備計(jì)算信息增益:
def splitDataSet(dataSet, axis, value):"""按照給定的特征值,將數(shù)據(jù)集劃分:param dataSet: 數(shù)據(jù)集:param axis: 給定特征值的坐標(biāo):param value: 給定特征值滿足的條件,只有給定特征值等于這個(gè)value的時(shí)候才會(huì)返回:return:"""# 創(chuàng)建一個(gè)新的列表,防止對(duì)原來(lái)的列表進(jìn)行修改retDataSet = []# 遍歷整個(gè)數(shù)據(jù)集for featVec in dataSet:# 如果給定特征值等于想要的特征值if featVec[axis] == value:# 將該特征值前面的內(nèi)容保存起來(lái)reducedFeatVec = featVec[:axis]# 將該特征值后面的內(nèi)容保存起來(lái),所以將給定特征值給去掉了reducedFeatVec.extend(featVec[axis + 1:])# 添加到返回列表中retDataSet.append(reducedFeatVec)return retDataSet確定數(shù)據(jù)集劃分
def chooseBestFeatureToSplit(dataSet, labels):"""選擇最好的數(shù)據(jù)集劃分特征,根據(jù)信息增益值來(lái)計(jì)算:param dataSet::return:"""# 得到數(shù)據(jù)的特征值總數(shù)numFeatures = len(dataSet[0]) - 1# 計(jì)算出基礎(chǔ)信息熵baseEntropy = calcShannonEnt(dataSet)# 基礎(chǔ)信息增益為0.0bestInfoGain = 0.0# 最好的特征值bestFeature = -1# 對(duì)每個(gè)特征值進(jìn)行求信息熵for i in range(numFeatures):# 得到數(shù)據(jù)集中所有的當(dāng)前特征值列表featList = [example[i] for example in dataSet]# 將當(dāng)前特征唯一化,也就是說(shuō)當(dāng)前特征值中共有多少種uniqueVals = set(featList)# 新的熵,代表當(dāng)前特征值的熵newEntropy = 0.0# 遍歷現(xiàn)在有的特征的可能性for value in uniqueVals:# 在全部數(shù)據(jù)集的當(dāng)前特征位置上,找到該特征值等于當(dāng)前值的集合subDataSet = splitDataSet(dataSet=dataSet, axis=i, value=value)# 計(jì)算出權(quán)重prob = len(subDataSet) / float(len(dataSet))# 計(jì)算出當(dāng)前特征值的熵newEntropy += prob * calcShannonEnt(subDataSet)# 計(jì)算出“信息增益”infoGain = baseEntropy - newEntropy#print('當(dāng)前特征值為:' + labels[i] + ',對(duì)應(yīng)的信息增益值為:' + str(infoGain)+"i等于"+str(i))#如果當(dāng)前的信息增益比原來(lái)的大if infoGain > bestInfoGain:# 最好的信息增益bestInfoGain = infoGain# 新的最好的用來(lái)劃分的特征值bestFeature = i#print('信息增益最大的特征為:' + labels[bestFeature])return bestFeature判斷屬性一致性:
def judgeEqualLabels(dataSet):"""判斷數(shù)據(jù)集的各個(gè)屬性集是否完全一致:param dataSet::return:"""# 計(jì)算出樣本集中共有多少個(gè)屬性,最后一個(gè)為類別feature_leng = len(dataSet[0]) - 1# 計(jì)算出共有多少個(gè)數(shù)據(jù)data_leng = len(dataSet)# 標(biāo)記每個(gè)屬性中第一個(gè)屬性值是什么first_feature = ''# 各個(gè)屬性集是否完全一致is_equal = True# 遍歷全部屬性for i in range(feature_leng):# 得到第一個(gè)樣本的第i個(gè)屬性first_feature = dataSet[0][i]# 與樣本集中所有的數(shù)據(jù)進(jìn)行對(duì)比,看看在該屬性上是否都一致for _ in range(1, data_leng):# 如果發(fā)現(xiàn)不相等的,則直接返回Falseif first_feature != dataSet[_][i]:return Falsereturn is_equal繪制決策樹(shù)并打印:
def createTree(dataSet, labels):"""創(chuàng)建決策樹(shù):param dataSet: 數(shù)據(jù)集:param labels: 特征標(biāo)簽:return:"""# 拿到所有數(shù)據(jù)集的分類標(biāo)簽classList = [example[-1] for example in dataSet]# 統(tǒng)計(jì)第一個(gè)標(biāo)簽出現(xiàn)的次數(shù),與總標(biāo)簽個(gè)數(shù)比較,如果相等則說(shuō)明當(dāng)前列表中全部都是一種標(biāo)簽,此時(shí)停止劃分if classList.count(classList[0]) == len(classList):return classList[0]# 計(jì)算第一行有多少個(gè)數(shù)據(jù),如果只有一個(gè)的話說(shuō)明所有的特征屬性都遍歷完了,剩下的一個(gè)就是類別標(biāo)簽,或者所有的樣本在全部屬性上都一致if len(dataSet[0]) == 1 or judgeEqualLabels(dataSet):# 返回剩下標(biāo)簽中出現(xiàn)次數(shù)較多的那個(gè)return majorityCnt(classList)# 選擇最好的劃分特征,得到該特征的下標(biāo)bestFeat = chooseBestFeatureToSplit(dataSet=dataSet, labels=labels)print(bestFeat)# 得到最好特征的名稱bestFeatLabel = labels[bestFeat]print(bestFeatLabel)# 使用一個(gè)字典來(lái)存儲(chǔ)樹(shù)結(jié)構(gòu),分叉處為劃分的特征名稱myTree = {bestFeatLabel: {}}# 將本次劃分的特征值從列表中刪除掉del(labels[bestFeat])# 得到當(dāng)前特征標(biāo)簽的所有可能值featValues = [example[bestFeat] for example in dataSet]# 唯一化,去掉重復(fù)的特征值uniqueVals = set(featValues)# 遍歷所有的特征值for value in uniqueVals:# 得到剩下的特征標(biāo)簽subLabels = labels[:]subTree = createTree(splitDataSet(dataSet=dataSet, axis=bestFeat, value=value), subLabels)# 遞歸調(diào)用,將數(shù)據(jù)集中該特征等于當(dāng)前特征值的所有數(shù)據(jù)劃分到當(dāng)前節(jié)點(diǎn)下,遞歸調(diào)用時(shí)需要先將當(dāng)前的特征去除掉myTree[bestFeatLabel][value] = subTreereturn myTree mytree=createTree(data,labels) print(mytree)
之后繪制可視化樹(shù):
添加標(biāo)簽重新繪制:
def makeTreeFull(myTree, labels_full, default):"""將樹(shù)中的不存在的特征標(biāo)簽進(jìn)行補(bǔ)全,補(bǔ)全為父節(jié)點(diǎn)中出現(xiàn)最多的類別:param myTree: 生成的樹(shù):param labels_full: 特征的全部標(biāo)簽:param parentClass: 父節(jié)點(diǎn)中所含最多的類別:param default: 如果缺失標(biāo)簽中父節(jié)點(diǎn)無(wú)法判斷類別則使用該值:return:"""# 這里所說(shuō)的父節(jié)點(diǎn)就是當(dāng)前根節(jié)點(diǎn),把當(dāng)前根節(jié)點(diǎn)下不存在的特征標(biāo)簽作為子節(jié)點(diǎn)# 拿到當(dāng)前的根節(jié)點(diǎn)root_key = list(myTree.keys())[0]# 拿到根節(jié)點(diǎn)下的所有分類,可能是子節(jié)點(diǎn)(好瓜or壞瓜)也可能不是子節(jié)點(diǎn)(再次劃分的屬性值)sub_tree = myTree[root_key]# 如果是葉子節(jié)點(diǎn)就結(jié)束if isinstance(sub_tree, str):return# 找到使用當(dāng)前節(jié)點(diǎn)分類下最多的種類,該分類結(jié)果作為新特征標(biāo)簽的分類,如:色澤下面沒(méi)有淺白則用色澤中有的青綠分類作為淺白的分類root_class = []# 把已經(jīng)分好類的結(jié)果記錄下來(lái)for sub_key in sub_tree.keys():if isinstance(sub_tree[sub_key], str):root_class.append(sub_tree[sub_key])# 找到本層出現(xiàn)最多的類別,可能會(huì)出現(xiàn)相同的情況取其一if len(root_class):most_class = collections.Counter(root_class).most_common(1)[0][0]else:most_class = None# 當(dāng)前節(jié)點(diǎn)下沒(méi)有已經(jīng)分類好的屬性# print(most_class)# 循環(huán)遍歷全部特征標(biāo)簽,將不存在標(biāo)簽添加進(jìn)去for label in labels_full[root_key]:if label not in sub_tree.keys():if most_class is not None:sub_tree[label] = most_classelse:sub_tree[label] = default# 遞歸處理for sub_key in sub_tree.keys():if isinstance(sub_tree[sub_key], dict):makeTreeFull(myTree=sub_tree[sub_key], labels_full=labels_full, default=default) makeTreeFull(mytree,labels_full,default='未知') createPlot(mytree)得到:
使用sklearn庫(kù)實(shí)現(xiàn)
導(dǎo)入包并讀取:
# 導(dǎo)入包 import pandas as pd from sklearn import tree import graphviz df = pd.read_csv('..\\source\\watermalon.txt') df.head(10)
特征值轉(zhuǎn)為數(shù)字:
得到:
總結(jié)
本次實(shí)驗(yàn)學(xué)習(xí)了解了決策樹(shù),信息熵等的概念,對(duì)于ID3,C4.5和CART算法的各優(yōu)缺點(diǎn)有更多的認(rèn)知。
參考
決策樹(shù)3:基尼指數(shù)–Gini index(CART)
西瓜書(shū)中的決策樹(shù)算法實(shí)現(xiàn)(ID3)
總結(jié)
- 上一篇: 三星 android截屏快捷键,三星C5
- 下一篇: 如何关掉visual studio 20