機器學習-4-決策樹
- 簡介
決策樹是基於樹結構進行決策的,決策樹的目的是產生一顆泛化能力強,即處理未見示例能力強的決策樹,其基本流程遵循簡單而直觀的“分而治之”(divide-and-conquer)的策略。
- 虛擬碼
----------------------------------------
輸入:訓練集D = {(x1,y1),(x2,y2),........,(xm,ym)};
屬性集A = {a1,a2,.............,ad}
過程:函式TreeGenerate(D,A)
1:生成結點 node;
2:if D中樣本全屬於同一類別C then
3: 將node標記為C類葉節點;return
4:end if
5:if A == Φ or D中樣本在A上取值相同 then
6: 將node標記為葉節點,其類別標記為D中樣本數最多的類;return
7:end if
8:從A中選擇最優劃分屬性a*; #這裡就需要劃分演算法
9:for a*的每一個值 a*v do
10 : 為node生成一個分支;令Dv表示D中在a*上取值為a*v的樣本子集;
11 : if Dv為空 then
12 : 將分支節點標記為葉節點,其類別標記為D中樣本最多的類;return
13 : else
14 : 以 TreeGenerate(Dv, A\{a*})為分支節點 #精髓遞迴
15 : end if
16 :end for
輸出:以node為根結點的一顆決策樹
--------------------------------------
虛擬碼注意點
遞迴返回情況:
1.當前節點包含的樣本全屬於同一類別,無需劃分;
2.當前屬性集為空,或是所有樣本在所有屬性上的取值相同;
3.當前節點包含的樣本集合為空,不能劃分;
特別地,在第2種情形下,我們把當前節點標記為葉結點,並將其類別設定為該結點所含樣本最多的類別;在第3種情形下,同樣把當前結點標記為葉結點,但將其類別設定為其父結點所含樣本最多的類別。即2為當前結點的後驗分佈,3則是把父結點的樣本分佈當作結點的先驗分佈。
- 劃分演算法
1.資訊熵(information entropy)是度量樣本集合純度最常用的一種指標。假定當前樣本集合D種第k類樣本所佔的比例為pk(k = 1,2,........,|y|),則D的資訊熵定義為
Ent(D)的值越小,則D的純度越高。
2.資訊增益(information gain)
假定離散屬性a有V個可能的取值{a1 ,a2,.......,av},若使用a來對樣本集D進行劃分,則會產生V個分支結點,其中第v個分支結點包含了D中所有在屬性a上取值為av的樣本,記為Dv.根據上述公式計算Dv的資訊熵,再考慮到不同的分支結點包含的樣本數不同,給分支結點賦予權重|Dv|/|D|,即樣本數越多的分支結點的影響越大,於是可計算出用屬性a對樣本集D進行劃分所獲得的“資訊增益“
一般而言,資訊增益越大,則意味著使用屬性a來進行劃分所獲得的”純度提升“越大。
3.增益率
資訊增益準則對可取值數目較多的屬性有所偏好,為減少這種偏好可能帶來的不利影響,著名的C4.5決策樹演算法不直接使用資訊增益,而是使用增益率(gain ratio)來選擇最優劃分屬性。
其中
稱為屬性a的“固有值”。屬性a的可能取值數目越多(即V越大),則IV(a)的值通常會越大。
需注意的是,增益率準則對可取值數目較少的屬性有所偏好,因此,C4.5演算法並不是直接選擇增益率最大的候選劃分屬性,而是使用了一個啟發式:先從候選劃分屬性中找出資訊增益高於平均水平的屬性,再從中選擇增益率最高的。
4.基尼指數
CART決策樹使用“基尼係數”來選擇劃分屬性。資料集D的純度可以用基尼值來度量:
直觀來說,Gini(D)反映了從資料集D中隨機抽取兩個樣本,其類別標記不一致的概率。因此,Gini(D)越小,則資料集D的純度越高。則屬性a的基尼指數定義為
於是,我們再候選屬性集合A中,選擇那個使得劃分後基尼指數最小的屬性作為最優劃分屬性,即a*= arg min Gini_index( D,a)
- 剪枝處理
剪枝(pruning)是決策樹學習演算法對付“過擬合”的主要手段。
預剪枝:在決策樹生成過程中,對每個結點在劃分前先進行估計,若當前結點的劃分不能帶來決策樹泛化效能的提升,則停止劃分並將當前結點標記為葉節點;
後剪枝:從訓練集生成一顆完整的決策樹,然後自底向上地對非葉結點進行考察,若將該結點對應的子樹替換為葉節點能帶來決策樹泛化效能提升,則將該子樹替換為葉節點。
- 連續與缺失值
可以將連續屬性離散化,最簡單的策略是採用二分法對連續屬性進行處理。
缺失值處理
- 多變數決策樹
emmmmm
- 例項程式碼
from math import log import pandas as pd import numpy as np from matplotlib.font_manager import FontProperties ''' 函式說明:計算資訊熵函式 輸入:data,計算列名 輸出:資訊熵 ''' def compute_infoentropy(Dataframe,columns_name): data = Dataframe[columns_name] data_classify = [] length = len(data) for singledata in data: if len(data_classify) == 0: data_classify.append([singledata,1]) else: exist = 0 for i in range(len(data_classify)): if data_classify[i][0] == singledata: data_classify[i][1] = data_classify[i][1]+1 exist = 1 if exist == 0: data_classify.append([singledata,1]) infoentropy = 0 for data_classfy1 in data_classify: infoentropy += data_classfy1[1] / length * log(data_classfy1[1] / length,2) infoentropy = -infoentropy return infoentropy ''' 函式說明:將資料依照某種型別分類 輸入:資料,資料分類型別 輸出:分類資料 ''' def my_classify(Dataframe,columns_name): data = Dataframe[columns_name] classify = [] for singledata in data: if singledata not in classify: classify.append(singledata) return classify ''' 函式說明:計算各類別的資訊增益(information gain),並選擇資訊增益最大的類別,進行相應劃分 輸入:資料,類別 輸出:最大類別 ''' def choose_bestfeature(Dataframe): #獲取columns_names columns_names = list(Dataframe) key_name = columns_names[-1] columns_names = columns_names[:-1] data_count = Dataframe[key_name].count() gain_list=[] #計算各屬性資訊增益值 key_infoentropy = compute_infoentropy(Dataframe,key_name) for singlename in columns_names: classify = my_classify(Dataframe,singlename) dflist = [] for edata in classify: dflist.append(Dataframe[Dataframe[singlename] == edata]) sum_infoentropy = 0 for dflist1 in dflist: sum_infoentropy += dflist1[key_name].count()/data_count*compute_infoentropy(dflist1,key_name) gain_list.append([singlename,key_infoentropy-sum_infoentropy]) max_gain = ['',0] for gain in gain_list: if gain[1]>max_gain[1]: max_gain=gain return max_gain[0] ''' 函式說明:獲取當前最大分類的屬性 輸入:data 輸出:特徵屬性數量佔多數的屬性 ''' def get_maxproperty(Dataframe): my_property = [] clnname=list(Dataframe) for data in Dataframe[clnname[0]]: exist = 0 for i in range(len(my_property)): if my_property[i][0] == data: my_property[i][1] += 1 exist = 1 if exist == 0: my_property.append([data,1]) max_p=['',0] for my_property1 in my_property: if my_property1[1]>max_p[1]: max_p[0]=my_property1[0] return max_p[0] ''' 函式說明:決策樹主函式 輸入:資料集 輸出:字典形式的決策樹 ''' def mydescion_tree(Dataframe,feature): key_featlist = Dataframe.iloc[:,-1] if key_featlist.loc[key_featlist == key_featlist.iloc[0]].count() == key_featlist.count(): #如果分類相同,則取該分類 return key_featlist.iloc[0] if Dataframe.shape[1] == 1: #如果只剩下一列資料(即分到了最後一類特徵),那麼取分類佔多數的分類 return get_maxproperty(Dataframe) bestfeature = choose_bestfeature(Dataframe) #找出當前最佳特徵 feature.append(bestfeature) tree = {bestfeature : {}} #建立節點用的 classify = my_classify(Dataframe,bestfeature) #找出當前最佳特徵共有幾種屬性 for classify1 in classify: #遍歷當前特徵的屬性 # 遞迴,後面dataframe是獲取特徵等於當前屬性的dataframe後並刪除當前最佳特徵,因為已經分過類了,進入遞迴。 tree[bestfeature][classify1] = mydescion_tree(Dataframe[Dataframe[bestfeature]==classify1].drop([bestfeature],axis=1),feature) return tree #測試資料 df1 = pd.read_excel('西瓜資料.xlsx',engine='openpyxl') df1 = df1.iloc[:,1:] tree = mydescion_tree(df1,feature=[]) print(tree)
後面還有一些補充的,未完待續。。。。
參考文獻:部落格園裡的一位同學,周志華《機器學習》