ID3決策樹演算法實現(Python版)

来源:http://www.cnblogs.com/JennyZhang-sharing/archive/2017/05/30/6920412.html
-Advertisement-
Play Games

ID3決策樹實現源碼(Python版),機器學習經典演算法起步階段,歡迎討論交流。 ...


  1 # -*- coding:utf-8 -*-
  2 
  3 from numpy import *
  4 import numpy as np
  5 import pandas as pd
  6 from math import log
  7 import operator
  8 
  9 #計算數據集的香農熵
 10 def calcShannonEnt(dataSet):
 11     numEntries=len(dataSet)
 12     labelCounts={}
 13     #給所有可能分類創建字典
 14     for featVec in dataSet:
 15         currentLabel=featVec[-1]
 16         if currentLabel not in labelCounts.keys():
 17             labelCounts[currentLabel]=0
 18         labelCounts[currentLabel]+=1
 19     shannonEnt=0.0
 20     #以2為底數計算香農熵
 21     for key in labelCounts:
 22         prob = float(labelCounts[key])/numEntries
 23         shannonEnt-=prob*log(prob,2)
 24     return shannonEnt
 25 
 26 
 27 #對離散變數劃分數據集,取出該特征取值為value的所有樣本
 28 def splitDataSet(dataSet,axis,value):
 29     retDataSet=[]
 30     for featVec in dataSet:
 31         if featVec[axis]==value:
 32             reducedFeatVec=featVec[:axis]
 33             reducedFeatVec.extend(featVec[axis+1:])
 34             retDataSet.append(reducedFeatVec)
 35     return retDataSet
 36 
 37 #對連續變數劃分數據集,direction規定劃分的方向,
 38 #決定是劃分出小於value的數據樣本還是大於value的數據樣本集
 39 def splitContinuousDataSet(dataSet,axis,value,direction):
 40     retDataSet=[]
 41     for featVec in dataSet:
 42         if direction==0:
 43             if featVec[axis]>value:
 44                 reducedFeatVec=featVec[:axis]
 45                 reducedFeatVec.extend(featVec[axis+1:])
 46                 retDataSet.append(reducedFeatVec)
 47         else:
 48             if featVec[axis]<=value:
 49                 reducedFeatVec=featVec[:axis]
 50                 reducedFeatVec.extend(featVec[axis+1:])
 51                 retDataSet.append(reducedFeatVec)
 52     return retDataSet
 53 
 54 #選擇最好的數據集劃分方式
 55 def chooseBestFeatureToSplit(dataSet,labels):
 56     numFeatures=len(dataSet[0])-1
 57     baseEntropy=calcShannonEnt(dataSet)
 58     bestInfoGain=0.0
 59     bestFeature=-1
 60     bestSplitDict={}
 61     for i in range(numFeatures):
 62         featList=[example[i] for example in dataSet]
 63         #對連續型特征進行處理
 64         if type(featList[0]).__name__=='float' or type(featList[0]).__name__=='int':
 65             #產生n-1個候選劃分點
 66             sortfeatList=sorted(featList)
 67             splitList=[]
 68             for j in range(len(sortfeatList)-1):
 69                 splitList.append((sortfeatList[j]+sortfeatList[j+1])/2.0)
 70 
 71             bestSplitEntropy=10000
 72             slen=len(splitList)
 73             #求用第j個候選劃分點劃分時,得到的信息熵,並記錄最佳劃分點
 74             for j in range(slen):
 75                 value=splitList[j]
 76                 newEntropy=0.0
 77                 subDataSet0=splitContinuousDataSet(dataSet,i,value,0)
 78                 subDataSet1=splitContinuousDataSet(dataSet,i,value,1)
 79                 prob0=len(subDataSet0)/float(len(dataSet))
 80                 newEntropy+=prob0*calcShannonEnt(subDataSet0)
 81                 prob1=len(subDataSet1)/float(len(dataSet))
 82                 newEntropy+=prob1*calcShannonEnt(subDataSet1)
 83                 if newEntropy<bestSplitEntropy:
 84                     bestSplitEntropy=newEntropy
 85                     bestSplit=j
 86             #用字典記錄當前特征的最佳劃分點
 87             bestSplitDict[labels[i]]=splitList[bestSplit]
 88             infoGain=baseEntropy-bestSplitEntropy
 89         #對離散型特征進行處理
 90         else:
 91             uniqueVals=set(featList)
 92             newEntropy=0.0
 93             #計算該特征下每種劃分的信息熵
 94             for value in uniqueVals:
 95                 subDataSet=splitDataSet(dataSet,i,value)
 96                 prob=len(subDataSet)/float(len(dataSet))
 97                 newEntropy+=prob*calcShannonEnt(subDataSet)
 98             infoGain=baseEntropy-newEntropy
 99         if infoGain>bestInfoGain:
100             bestInfoGain=infoGain
101             bestFeature=i
102     #若當前節點的最佳劃分特征為連續特征,則將其以之前記錄的劃分點為界進行二值化處理
103     #即是否小於等於bestSplitValue
104     if type(dataSet[0][bestFeature]).__name__=='float' or type(dataSet[0][bestFeature]).__name__=='int':
105         bestSplitValue=bestSplitDict[labels[bestFeature]]
106         labels[bestFeature]=labels[bestFeature]+'<='+str(bestSplitValue)
107         for i in range(shape(dataSet)[0]):
108             if dataSet[i][bestFeature]<=bestSplitValue:
109                 dataSet[i][bestFeature]=1
110             else:
111                 dataSet[i][bestFeature]=0
112     return bestFeature
113 
114 #特征若已經劃分完,節點下的樣本還沒有統一取值,則需要進行投票
115 def majorityCnt(classList):
116     classCount={}
117     for vote in classList:
118         if vote not in classCount.keys():
119             classCount[vote]=0
120         classCount[vote]+=1
121     return max(classCount)
122 
123 #主程式,遞歸產生決策樹
124 def createTree(dataSet,labels,data_full,labels_full):
125     classList=[example[-1] for example in dataSet]
126     if classList.count(classList[0])==len(classList):
127         return classList[0]
128     if len(dataSet[0])==1:
129         return majorityCnt(classList)
130     bestFeat=chooseBestFeatureToSplit(dataSet,labels)
131     bestFeatLabel=labels[bestFeat]
132     myTree={bestFeatLabel:{}}
133     featValues=[example[bestFeat] for example in dataSet]
134     uniqueVals=set(featValues)
135     if type(dataSet[0][bestFeat]).__name__=='str':
136         currentlabel=labels_full.index(labels[bestFeat])
137         featValuesFull=[example[currentlabel] for example in data_full]
138         uniqueValsFull=set(featValuesFull)
139     del(labels[bestFeat])
140     #針對bestFeat的每個取值,劃分出一個子樹。
141     for value in uniqueVals:
142         subLabels=labels[:]
143         if type(dataSet[0][bestFeat]).__name__=='str':
144             uniqueValsFull.remove(value)
145         myTree[bestFeatLabel][value]=createTree(splitDataSet\
146          (dataSet,bestFeat,value),subLabels,data_full,labels_full)
147     if type(dataSet[0][bestFeat]).__name__=='str':
148         for value in uniqueValsFull:
149             myTree[bestFeatLabel][value]=majorityCnt(classList)
150     return myTree
151 
152 import matplotlib.pyplot as plt
153 decisionNode=dict(boxstyle="sawtooth",fc="0.8")
154 leafNode=dict(boxstyle="round4",fc="0.8")
155 arrow_args=dict(arrowstyle="<-")
156 
157 
158 #計算樹的葉子節點數量
159 def getNumLeafs(myTree):
160     numLeafs=0
161     firstSides = list(myTree.keys())
162     firstStr=firstSides[0]
163     secondDict=myTree[firstStr]
164     for key in secondDict.keys():
165         if type(secondDict[key]).__name__=='dict':
166             numLeafs+=getNumLeafs(secondDict[key])
167         else: numLeafs+=1
168     return numLeafs
169 
170 #計算樹的最大深度
171 def getTreeDepth(myTree):
172     maxDepth=0
173     firstSides = list(myTree.keys())
174     firstStr=firstSides[0]
175     secondDict=myTree[firstStr]
176     for key in secondDict.keys():
177         if type(secondDict[key]).__name__=='dict':
178             thisDepth=1+getTreeDepth(secondDict[key])
179         else: thisDepth=1
180         if thisDepth>maxDepth:
181             maxDepth=thisDepth
182     return maxDepth
183 
184 #畫節點
185 def plotNode(nodeTxt,centerPt,parentPt,nodeType):
186     createPlot.ax1.annotate(nodeTxt,xy=parentPt,xycoords='axes fraction',\
187     xytext=centerPt,textcoords='axes fraction',va="center", ha="center",\
188     bbox=nodeType,arrowprops=arrow_args)
189 
190 #畫箭頭上的文字
191 def plotMidText(cntrPt,parentPt,txtString):
192     lens=len(txtString)
193     xMid=(parentPt[0]+cntrPt[0])/2.0-lens*0.002
194     yMid=(parentPt[1]+cntrPt[1])/2.0
195     createPlot.ax1.text(xMid,yMid,txtString)
196 
197 def plotTree(myTree,parentPt,nodeTxt):
198     numLeafs=getNumLeafs(myTree)
199     depth=getTreeDepth(myTree)
200     firstSides = list(myTree.keys())
201     firstStr=firstSides[0]
202     cntrPt=(plotTree.x0ff+(1.0+float(numLeafs))/2.0/plotTree.totalW,plotTree.y0ff)
203     plotMidText(cntrPt,parentPt,nodeTxt)
204     plotNode(firstStr,cntrPt,parentPt,decisionNode)
205     secondDict=myTree[firstStr]
206     plotTree.y0ff=plotTree.y0ff-1.0/plotTree.totalD
207     for key in secondDict.keys():
208         if type(secondDict[key]).__name__=='dict':
209             plotTree(secondDict[key],cntrPt,str(key))
210         else:
211             plotTree.x0ff=plotTree.x0ff+1.0/plotTree.totalW
212             plotNode(secondDict[key],(plotTree.x0ff,plotTree.y0ff),cntrPt,leafNode)
213             plotMidText((plotTree.x0ff,plotTree.y0ff),cntrPt,str(key))
214     plotTree.y0ff=plotTree.y0ff+1.0/plotTree.totalD
215 
216 def createPlot(inTree):
217     fig=plt.figure(1,facecolor='white')
218     fig.clf()
219     axprops=dict(xticks=[],yticks=[])
220     createPlot.ax1=plt.subplot(111,frameon=False,**axprops)
221     plotTree.totalW=float(getNumLeafs(inTree))
222     plotTree.totalD=float(getTreeDepth(inTree))
223     plotTree.x0ff=-0.5/plotTree.totalW
224     plotTree.y0ff=1.0
225     plotTree(inTree,(0.5,1.0),'')
226     plt.show()
227 
228 df=pd.read_csv('watermelon_4_3.csv')
229 data=df.values[:,1:].tolist()
230 data_full=data[:]
231 labels=df.columns.values[1:-1].tolist()
232 labels_full=labels[:]
233 myTree=createTree(data,labels,data_full,labels_full)
234 print(myTree)
235 createPlot(myTree)
最終結果如下: {'texture': {'blur': 0, 'little_blur': {'touch': {'soft_stick': 1, 'hard_smooth': 0}}, 'distinct': {'density<=0.38149999999999995': {0: 1, 1: 0}}}}   得到的決策樹如下:   參考資料: 《機器學習實戰》 《機器學習》周志華著
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、實驗原理 二、實驗步驟 三、實驗過程 1.(程式) (1)二分法:求 在區間(1,2)之間的根,取 (a)bipart.m: (b)fun1.m: (2)不動點迭代法:求方程在附近的根,取 (a)budong.m: (b)fun.m (3)牛頓迭代法:求方程在附近的根,取 newton.m: 2 ...
  • CloseHandle函數 來源:https://msdn.microsoft.com/en us/library/windows/desktop/ms724211(v=vs.85).aspx 作用 關閉一個打開的對象句柄。 語法 參數 hObject 已經打開的有效對象句柄。 返回值 如果函數操作 ...
  • 數據類型之集合 set set集合,是一個無序且不重覆的元素集合 A = set([1, 2, 3, 4, 5, 6,]) B = set([2, 3, 4, 5, 6, 7, 8]) type(A) type(B) class set(object): """ set() new empty se ...
  • 前言 前面已經學習了Apache Commons Beanutils包里的PropertyUtils和動態bean,接下來將學習剩下的幾個工具類,個人覺得還是非常實用的,特別是CollectionUtils; BeanUtils 簡單介紹下兩個方法的使用,populate和copyPropertie ...
  • 首先需要弄清楚npm與cnpm的區別(要看解決問題方案的情直接跳到最後): npm:npm(node package manager)是nodejs的包管理器,用於node插件管理(包括安裝、卸載、管理依賴等) cnpm:因為npm安裝插件是從國外伺服器下載,受網路影響大,可能出現異常,如果npm的 ...
  • 記憶體分配方式 簡介 在C++中,記憶體分成5個區,他們分別是堆、棧、自由存儲區、全局/靜態存儲區和常量存儲區。 棧:在執行函數時,函數內局部變數的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。 堆:就是那些由 n ...
  • 今天這一題有點燒腦: 有一個序列u,滿足: 1. 第一個元素是1 2. 此後任意一個元素x,2x+1和3x+1也必定在u中 現給定整數n,求序列u中的第n+1個元素是什麼? 規定:要註意演算法的效率 分析: 乍一想有點亂。先找幾個數計算一下: 1 [1], 3, 4 1, [3], 4, 7, 10 ...
  • 英文分詞的第三方庫NLTK不錯,中文分詞工具也有很多(盤古分詞、Yaha分詞、Jieba分詞等)。但是從載入自定義字典、多線程、自動匹配新詞等方面來看。 大jieba 確實是中文分詞中的 戰鬥機 。 請隨意觀看表演 "安裝" "分詞" "自定義詞典" "延遲載入" "關鍵詞提取" "詞性標註" "詞 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...