python决策树 value_机器学习 | 算法笔记(四)- 决策树算法以及代码实现
概述
上一篇講述了《機器學(xué)習(xí) | 算法筆記(三)- 支持向量機算法以及代碼實現(xiàn)》,本篇講述機器學(xué)習(xí)算法決策樹,內(nèi)容包括模型介紹及代碼實現(xiàn)。
決策樹
決策樹(Decision Tree)在機器學(xué)習(xí)中也是比較常見的一種算法,屬于監(jiān)督學(xué)習(xí)中的一種。看字面意思應(yīng)該也比較容易理解,相比其他算法比如支持向量機(SVM)或神經(jīng)網(wǎng)絡(luò),似乎決策樹感覺“親切”許多。
優(yōu)點:計算復(fù)雜度不高,輸出結(jié)果易于理解,對中間值的缺失值不敏感,可以處理不相關(guān)特征數(shù)據(jù)。
缺點:可能會產(chǎn)生過度匹配的問題。
使用數(shù)據(jù)類型:數(shù)值型和標(biāo)稱型。
劃分?jǐn)?shù)據(jù)集的大原則是:將無序的數(shù)據(jù)變得更加有序。
我們可以使用多種方法劃分?jǐn)?shù)據(jù)集,但是每種方法都有各自的優(yōu)缺點。于是我們這么想,如果我們能測量數(shù)據(jù)的復(fù)雜度,對比按不同特征分類后的數(shù)據(jù)復(fù)雜度,若按某一特征分類后復(fù)雜度減少的更多,那么這個特征即為最佳分類特征。
下面,我們就對以下表格中的西瓜樣本構(gòu)建決策樹模型。
Claude Shannon 定義了熵(entropy)和信息增益(information gain)。
用熵來表示信息的復(fù)雜度,熵越大,則信息越復(fù)雜。
信息熵(information entropy)樣本集合D中第k類樣本所占的比例(k=1,2,...,|Y|),|Y|為樣本分類的個數(shù),則D的信息熵為:
Ent(D)的值越小,則D的純度越高。直觀理解一下:假設(shè)樣本集合有2個分類,每類樣本的比例為1/2,Ent(D)=1;只有一個分類,Ent(D)= 0,顯然后者比前者的純度高。
在西瓜樣本集中,共有17個樣本,其中正樣本8個,負(fù)樣本9個,樣本集的信息熵為:
信息增益(information gain)使用屬性a對樣本集D進行劃分所獲得的“信息增益”的計算方法是,用樣本集的總信息熵減去屬性a的每個分支的信息熵與權(quán)重(該分支的樣本數(shù)除以總樣本數(shù))的乘積,通常,信息增益越大,意味著用屬性a進行劃分所獲得的“純度提升”越大。因此,優(yōu)先選擇信息增益最大的屬性來劃分。
同理也可以計算出其他幾個屬性的信息增益,選擇信息增益最大的屬性作為根節(jié)點來進行劃分,然后再對每個分支做進一步劃分。
用python構(gòu)造決策樹基本流程
決策樹學(xué)習(xí)基本算法
ID3算法與決策樹的流程
(1)數(shù)據(jù)準(zhǔn)備:需要對數(shù)值型數(shù)據(jù)進行離散化
(2)ID3算法構(gòu)建決策樹:
- 如果數(shù)據(jù)集類別完全相同,則停止劃分
- 否則,繼續(xù)劃分決策樹:
計算信息熵和信息增益來選擇最好的數(shù)據(jù)集劃分方法;劃分?jǐn)?shù)據(jù)集創(chuàng)建分支節(jié)點:對每個分支進行判定是否類別相同,如果相同停止劃分,不同按照上述方法進行劃分。
通常一棵決策樹包含一個根節(jié)點、若干個分支節(jié)點和若干個葉子節(jié)點,葉子節(jié)點對應(yīng)決策結(jié)果(如好瓜或壞瓜),根節(jié)點和分支節(jié)點對應(yīng)一個屬性測試(如色澤=?),每個結(jié)點包含的樣本集合根據(jù)屬性測試的結(jié)果劃分到子節(jié)點中。
我們對整個訓(xùn)練集選擇的最優(yōu)劃分屬性就是根節(jié)點,第一次劃分后,數(shù)據(jù)被向下傳遞到樹分支的下一個節(jié)點,再這個節(jié)點我們可以再次劃分?jǐn)?shù)據(jù),構(gòu)建決策樹是一個遞歸的過程,而遞歸結(jié)束的條件是:所有屬性都被遍歷完,或者每個分支下的所有樣本都屬于同一類。
還有一種情況就是當(dāng)劃分到一個節(jié)點,該節(jié)點對應(yīng)的屬性取值都相同,而樣本的類別卻不同,這時就把當(dāng)前節(jié)點標(biāo)記為葉節(jié)點,并將其類別設(shè)為所含樣本較多的類別。例如:當(dāng)劃分到某一分支時,節(jié)點中有3個樣本,其最優(yōu)劃分屬性為色澤,而色澤的取值只有一個“淺白”,3個樣本中有2個好瓜,這時我們就把這個節(jié)點標(biāo)記為葉節(jié)點“好瓜”。
代碼實現(xiàn)
數(shù)據(jù)集:https://download.csdn.net/download/li1873997/12671852
trees.py
from math import logimport operator # 此行加在文件頂部# 通過排序返回出現(xiàn)次數(shù)最多的類別def majorityCnt(classList): classCount = {} for vote in classList: if vote not in classCount.keys(): classCount[vote] = 0 classCount[vote] += 1 sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) return sortedClassCount[0][0]# 遞歸構(gòu)建決策樹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: # 如果所有特征都被遍歷完了,返回出現(xiàn)次數(shù)最多的類別 return majorityCnt(classList) bestFeat = chooseBestFeatureToSplit(dataSet) # 最優(yōu)劃分屬性的索引 bestFeatLabel = labels[bestFeat] # 最優(yōu)劃分屬性的標(biāo)簽 myTree = {bestFeatLabel: {}} del (labels[bestFeat]) # 已經(jīng)選擇的特征不再參與分類 featValues = [example[bestFeat] for example in dataSet] uniqueValue = set(featValues) # 該屬性所有可能取值,也就是節(jié)點的分支 for value in uniqueValue: # 對每個分支,遞歸構(gòu)建樹 subLabels = labels[:] myTree[bestFeatLabel][value] = createTree( splitDataSet(dataSet, bestFeat, value), subLabels) return myTree# 計算信息熵def calcShannonEnt(dataSet): numEntries = len(dataSet) # 樣本數(shù) labelCounts = {} for featVec in dataSet: # 遍歷每個樣本 currentLabel = featVec[-1] # 當(dāng)前樣本的類別 if currentLabel not in labelCounts.keys(): # 生成類別字典 labelCounts[currentLabel] = 0 labelCounts[currentLabel] += 1 shannonEnt = 0.0 for key in labelCounts: # 計算信息熵 prob = float(labelCounts[key]) / numEntries shannonEnt = shannonEnt - prob * log(prob, 2) return shannonEnt# 劃分?jǐn)?shù)據(jù)集,axis:按第幾個屬性劃分,value:要返回的子集對應(yīng)的屬性值def splitDataSet(dataSet, axis, value): retDataSet = [] featVec = [] for featVec in dataSet: if featVec[axis] == value: reducedFeatVec = featVec[:axis] reducedFeatVec.extend(featVec[axis + 1:]) retDataSet.append(reducedFeatVec) return retDataSet# 選擇最好的數(shù)據(jù)集劃分方式def chooseBestFeatureToSplit(dataSet): numFeatures = len(dataSet[0]) - 1 # 屬性的個數(shù) baseEntropy = calcShannonEnt(dataSet) bestInfoGain = 0.0 bestFeature = -1 for i in range(numFeatures): # 對每個屬性技術(shù)信息增益 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) infoGain = baseEntropy - newEntropy if (infoGain > bestInfoGain): # 選擇信息增益最大的屬性 bestInfoGain = infoGain bestFeature = i return bestFeature# 計算信息熵def calcShannonEnt(dataSet): numEntries = len(dataSet) # 樣本數(shù) labelCounts = {} for featVec in dataSet: # 遍歷每個樣本 currentLabel = featVec[-1] # 當(dāng)前樣本的類別 if currentLabel not in labelCounts.keys(): # 生成類別字典 labelCounts[currentLabel] = 0 labelCounts[currentLabel] += 1 shannonEnt = 0.0 for key in labelCounts: # 計算信息熵 prob = float(labelCounts[key]) / numEntries shannonEnt = shannonEnt - prob * log(prob, 2) return shannonEnt# 劃分?jǐn)?shù)據(jù)集,axis:按第幾個屬性劃分,value:要返回的子集對應(yīng)的屬性值def splitDataSet(dataSet, axis, value): retDataSet = [] featVec = [] for featVec in dataSet: if featVec[axis] == value: reducedFeatVec = featVec[:axis] reducedFeatVec.extend(featVec[axis + 1:]) retDataSet.append(reducedFeatVec) return retDataSet# 選擇最好的數(shù)據(jù)集劃分方式def chooseBestFeatureToSplit(dataSet): numFeatures = len(dataSet[0]) - 1 # 屬性的個數(shù) baseEntropy = calcShannonEnt(dataSet) bestInfoGain = 0.0 bestFeature = -1 for i in range(numFeatures): # 對每個屬性技術(shù)信息增益 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) infoGain = baseEntropy - newEntropy if (infoGain > bestInfoGain): # 選擇信息增益最大的屬性 bestInfoGain = infoGain bestFeature = i return bestFeature下面使用西瓜樣本集,測試一下算法,創(chuàng)建一個WaterMalonTree.py文件。因為生成的樹是中文表示的,因此使用json.dumps()方法來打印結(jié)果。如果是不含中文,直接print即可。
# -*- coding: cp936 -*-import treesimport json fr = open(r'C:Python27pyDecisionTreewatermalon.txt') listWm = [inst.strip().split('') for inst in fr.readlines()]labels = ['色澤', '根蒂', '敲聲', '紋理', '臍部', '觸感']Trees = trees.createTree(listWm, labels) print json.dumps(Trees, encoding="cp936", ensure_ascii=False)運行該文件,打印出西瓜的決策樹,它是一個字典:
{"紋理": {"模糊": "否", "清晰": {"根蒂": {"稍蜷": {"色澤": {"烏黑": {"觸感": {"軟粘": "否", "硬滑": "是"}}, "青綠": "是"}}, "蜷縮": "是", "硬挺": "否"}}, "稍糊": {"觸感": {"軟粘": "是", "硬滑": "否"}}}}
總結(jié)
決策樹是一種基于樹結(jié)構(gòu)來進行決策的分類算法,我們希望從給定的訓(xùn)練數(shù)據(jù)集學(xué)得一個模型(即決策樹),用該模型對新樣本分類。決策樹可以非常直觀展現(xiàn)分類的過程和結(jié)果,一旦模型構(gòu)建成功,對新樣本的分類效率也相當(dāng)高。
最經(jīng)典的決策樹算法有ID3、C4.5、CART,其中ID3算法是最早被提出的,它可以處理離散屬性樣本的分類,C4.5和CART算法則可以處理更加復(fù)雜的分類問題,本文重點介紹ID3算法。下一篇介紹通過《 數(shù)據(jù)可視化-Python實現(xiàn)Matplotlib繪制決策樹》。
總結(jié)
以上是生活随笔為你收集整理的python决策树 value_机器学习 | 算法笔记(四)- 决策树算法以及代码实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c字符串中包含双引号_必须知道的C语言知
- 下一篇: 如何用三元组表表示下列稀疏矩阵_盘一盘