您好,登錄后才能下訂單哦!
這篇文章主要介紹“python怎么實現決策樹建模”,在日常操作中,相信很多人在python怎么實現決策樹建模問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”python怎么實現決策樹建模”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
決策樹是一種簡單的機器學習方法。決策樹經過訓練之后,看起來像是以樹狀形式排列的一系列if-then語句。一旦我們有了決策樹,只要沿著樹的路徑一直向下,正確回答每一個問題,最終就會得到答案。沿著最終的葉節點向上回溯,就會得到一個有關最終分類結果的推理過程。
決策樹:
class decisionnode: def __init__(self,col=-1,value=None,results=None,tb=None,fb=None): self.col=col #待檢驗的判斷條件 self.value=value #對應于為了使結果為true,當前列必須匹配的值 self.results=results #針對當前分支的結果 self.tb=tb #結果為true時,樹上相對于當前節點的子樹上的節點 self.fb=fb #結果為false時,樹上相對于當前節點的子樹上的節點
下面利用分類回歸樹的算法。為了構造決策樹,算法首先創建一個根節點,然后評估表中的所有觀測變量,從中選出最合適的變量對數據進行拆分。為了選擇合適的變量,我們需要一種方法來衡量數據集合中各種因素的混合情況。對于混雜程度的測度,有幾種度量方式可供選擇:
基尼不純度:將來自集合中的某種結果隨機應用于集合中某一數據項的預期誤差率。
下面是python實現:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | def uniquecounts(rows): results={} for row in rows: # The result is the last column r=row[len(row)-1] if r not in results: results[r]=0 results[r]+=1 return results def giniimpurity(rows): total=len(rows) counts=uniquecounts(rows) imp=0 for k1 in counts: p1=float(counts[k1])/total #imp+=p1*p1 for k2 in counts: if k1==k2: continue p2=float(counts[k2])/total imp+=p1*p2 return imp#1-imp |
《集》中的實現:
1 2 3 4 5 6 7 8 9 10 | def entropy(rows): from math import log log2=lambda x:log(x)/log(2) results=uniquecounts(rows) # Now calculate the entropy ent=0.0 for r in results.keys(): p=float(results[r])/len(rows) ent=ent-p*log2(p) return ent |
熵和基尼不純度之間的主要區別在于,熵達到峰值的過程要相對慢一些。因此,熵對于混亂集合的判罰要更重一些。
我們的算法首先求出整個群組的熵,然后嘗試利用每個屬性的可能取值對群組進行拆分,并求出兩個新群組的熵。算法會計算相應的信息增益。信息增益是指當前熵與兩個新群組經加權平均后的熵之間的差值。算法會對每個屬性計算相應的信息增益,然后從中選出信息增益最大的屬性。通過計算每個新生節點的最佳拆分屬性,對分支的拆分過程和樹的構造過程會不斷持續下去。當拆分某個節點所得的信息增益不大于0的時候,對分支的拆分才會停止:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | def buildtree(rows,scoref=entropy): if len(rows)==0: return decisionnode() current_score=scoref(rows) # Set up some variables to track the best criteria best_gain=0.0 best_criteria=None best_sets=None column_count=len(rows[0])-1 for col in range(0,column_count): # Generate the list of different values in # this column column_values={} for row in rows: column_values[row[col]]=1 # Now try dividing the rows up for each value # in this column for value in column_values.keys(): (set1,set2)=divideset(rows,col,value) # Information gain p=float(len(set1))/len(rows) gain=current_score-p*scoref(set1)-(1-p)*scoref(set2) if gain>best_gain and len(set1)>0 and len(set2)>0: best_gain=gain best_criteria=(col,value) best_sets=(set1,set2) # Create the sub branches if best_gain>0: trueBranch=buildtree(best_sets[0]) falseBranch=buildtree(best_sets[1]) return decisionnode(col=best_criteria[0],value=best_criteria[1], tb=trueBranch,fb=falseBranch) else: return decisionnode(results=uniquecounts(rows)) |
函數首先接受一個由數據行構成的列表作為參數。它遍歷了數據集中的每一列,針對各列查找每一種可能的取值,并將數據集拆分成兩個新的子集。通過將每個子集的熵乘以子集中所含數據項在元數據集中所占的比重,函數求出了每一對新生子集的甲醛平均熵,并記錄下熵最低的那一對子集。如果由熵值最低的一對子集求得的加權平均熵比當前集合的當前集合的熵要大,則拆分結束了,針對各種可能結果的計數所得將會被保存起來。否則,算法會在新生成的子集繼續調用buildtree函數,并把調用所得的結果添加到樹上。我們把針對每個子集的調用結果,分別附加到節點的True分支和False分支上,最終整棵樹就這樣構造出來了。
我們可以把它打印出來:
1 2 3 4 5 6 7 8 9 10 11 12 13 | def printtree(tree,indent=''): # Is this a leaf node? if tree.results!=None: print str(tree.results) else: # Print the criteria print str(tree.col)+':'+str(tree.value)+'? ' # Print the branches print indent+'T->', printtree(tree.tb,indent+' ') print indent+'F->', printtree(tree.fb,indent+' ') |
現在到我們使用決策樹的時候了。接受新的觀測數據作為參數,然后根據決策樹對其分類:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 | def classify(observation,tree): if tree.results!=None: return tree.results else: v=observation[tree.col] branch=None if isinstance(v,int) or isinstance(v,float): if v>=tree.value: branch=tree.tb else: branch=tree.fb else: if v==tree.value: branch=tree.tb else: branch=tree.fb return classify(observation,branch) |
該函數采用與printtree相同的方式對樹進行遍歷。每次調用后,函數會根據調用結果來判斷是否到達分支的末端。如果尚未到達末端,它會對觀測數據評估,以確認列數據是否與參考值匹配。如果匹配,則會在True分支調用classify,不匹配則在False分支調用classify。
上面方法訓練決策樹會有一個問題:
過度擬合:它可能會變得過于針對訓練數據,其熵值與真實情況相比可能會有所降低。剪枝的過程就是對具有相同父節點的一組節點進行檢查,判斷如果將其合并,熵的增加量是否會小于某個指定的閾值。如果確實如此,則這些葉節點會被合并成一個單一的節點,合并后的新節點包含了所有可能的結果值。這種做法有助于過度避免過度擬合的情況,使得決策樹做出的預測結果,不至于比從數據集中得到的實際結論還要特殊:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | def prune(tree,mingain): # 如果分支不是葉節點,則對其進行剪枝操作 if tree.tb.results==None: prune(tree.tb,mingain) if tree.fb.results==None: prune(tree.fb,mingain) # 如果兩個分支都是葉節點,則判斷它們是否需要合并 if tree.tb.results!=None and tree.fb.results!=None: # 構造合并后的數據集 tb,fb=[],[] for v,c in tree.tb.results.items(): tb+=[[v]]*c for v,c in tree.fb.results.items(): fb+=[[v]]*c # 檢查熵的減少情況 delta=entropy(tb+fb)-(entropy(tb)+entropy(fb)/2) if delta<mingain: # 合并分支 tree.tb,tree.fb=None,None tree.results=uniquecounts(tb+fb) |
當我們在根節點調用上述函數時,算法將沿著樹的所有路徑向下遍歷到只包含葉節點的節點處。函數會將兩個葉節點中的結果值合起來形成一個新的列表,同時還會對熵進行測試。如果熵的變化小于mingain參數指定的值,則葉節點也可能成為刪除對象,以及與其它節點的合并對象。
如果我們缺失了某些數據,而這些數據是確定分支走向所必需的,那么我們可以選擇兩個分支都走。在一棵基本的決策樹中,所有節點都隱含有一個值為1的權重,即觀測數據項是否屬于某個特定分類的概率具有百分之百的影響。而如果要走多個分支的話,那么我們可以給每個分支賦以一個權重,其值等于所有位于該分支的其它數據行所占的比重:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | def mdclassify(observation,tree): if tree.results!=None: return tree.results else: v=observation[tree.col] if v==None: tr,fr=mdclassify(observation,tree.tb),mdclassify(observation,tree.fb) tcount=sum(tr.values()) fcount=sum(fr.values()) tw=float(tcount)/(tcount+fcount) fw=float(fcount)/(tcount+fcount) result={} for k,v in tr.items(): result[k]=v*tw for k,v in fr.items(): result[k]=v*fw return result else: if isinstance(v,int) or isinstance(v,float): if v>=tree.value: branch=tree.tb else: branch=tree.fb else: if v==tree.value: branch=tree.tb else: branch=tree.fb return mdclassify(observation,branch) |
mdclassify與classify相比,唯一的區別在于末尾處:如果發現有重要數據缺失,則每個分支的對應結果值都會被計算一遍,并且最終的結果值會乘以它們各自的權重。
對與數值型問題,我們可以使用方差作為評價函數來取代熵或基尼不純度。偏低的方差代表數字彼此都非常接近,而偏高的方差則意味著數字分散得很開。這樣,選擇節點判斷條件的依據就變成了拆分后令數字較大者位于樹的一側,數字較小者位于樹的另一側。
到此,關于“python怎么實現決策樹建模”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。