總結
決策樹 (有監督學習方法,集成學習的核心操作):能夠從一系列有特征和標簽的數據中總結出決策(基於分類或者回歸)規則,並用樹狀圖的結構來呈現這些規則,以解決分類和回歸問題
- API: from sklearn.tree import DecisionTreeClassifier
- 節點:根節點(針對特征的提問)、中間節點(針對特征的提問,特征自上而下重要性下降)、葉子節點(類別標簽)、子節點和父節點(更接近根節點)
構建決策樹:局部最優--》全局最優(貪心算法:局部的最優來達到最接近全局最優的結果)
- Hunt算法構建決策樹:包括ID3、C4.5和CART算法
- 不純度(用信息熵計算不純度):落在不同類別的樣本數量,差距越大不純度就越低,差距越小,不純度越高。類分布為(0,100%)的結點具有零不純性,而均衡分布 (50%,50%)的結點具有最高的不純性。子節點的不純度一定是低於父節點的,葉子節點的不純度一定是最低的。
- 比特也叫信息量 (香農提出):信息論中信息度量的單位,猜錯所付出的代價 (信息量的值會隨着更多有用信息的出現而降低)
- 信息熵:信息量的值在信息論中被稱為信息熵,一種信息的度量方式,表示信息的混亂程度,也就是說:信息越有序,信息熵越低(不純度或者信息量越低)
- 公式:
p(xi)為分到某個類別的概率,H為信息量的值叫做【信息熵】
- 結論:信息熵和消除不確定性是相關聯的
- 信息熵越大則表示信息的不確定性越大,猜對的代價大
- 信息熵越小則表示信息的不確定性越小,猜對的代價小
- 信息增益(衡量特征的重要性):根據某個特征划分數據集之前之后信息熵發生的變化or差異叫做信息增益 (差異越大信息越重要)。信息增益 = 用特征划分前信息熵 - 用特征划分后信息熵
- 各分支的信息熵計算: p(xi)指的是某一個節點某一類別占據該節點總類別的比例
- 一個特征總的信息熵 = 每一個特征的組成的信息熵 x 該組成占總樣本的比例。
ID3算法,分類問題:通過信息增益來對最佳節點進行設定,最佳節點設置好了,最佳決策樹就可以畫出。
- ID3算法的局限性
- 不能直接處理連續型數據集,連續性數據集是指數據的目標值為連續性,則無法計算某類別樣例數量占總類別樣例的占比 。(需要對連續變量進行離散化)
- 對缺失值較為敏感,存在缺失值則信息熵的公式無法計算結果(需要提前對缺失值進行處理)
- 沒有剪枝的設置,容易導致過擬合
C4.5信息增益比(決策樹存在擬合問題就用它),分類問題:
- 分支度:
p(vi)是某子節點的總樣本數占父節點總樣本數的比例
- 信息增益比:
信息增益/分支度, (一個分支點的分支越多的總信息熵可能會因為分類多造成的信息熵變大,這個信息增益比就可以很好解決由於分支多造成的信息熵變大)
CART(基尼系數)基尼系數的計算速度高於信息熵。用於分類問題回歸問題。:CART 的全稱是分類與回歸樹 ,CART 生成的樹必須是二叉樹。
- 公式:
認識決策樹
- 決策樹(Decision Tree)是一種有監督學習方法,它能夠從一系列有特征和標簽的數據中總結出決策(基於分類或者回歸)規則,並用樹狀圖的結構來呈現這些規則,以解決分類和回歸問題。決策樹算法容易理解,適用各種數據,在解決各種問題時都有良好表現,尤其是以樹模型為核心的各種集成算法(集成學習的核心操作),在各個行業領域都有廣泛的應用。
- 我們來簡單了解一下決策樹是如何工作的。決策樹算法的本質是一種樹結構,我們只需要問一系列問題就可以對數據進行分類了。比如說,來看看下面的一組數據集,這是一些列已知物種以及所屬類別的數據:
- 我們現在的目標是,將動物們分為哺乳類和非哺乳類。那根據已經收集到的數據,決策樹算法為我們算出了下面的這棵決策樹:
-
- 假如我們現在發現了一種新物種Python,它是冷血動物,體表帶鱗片,並且不是胎生,我們就可以通過這棵決策樹來判斷它的所屬類別。
- 可以看出,在這個決策過程中,我們一直在對記錄的特征進行提問。最初的問題所在的地方叫做根節點,在得到結論前的每一個問題都是中間節點,而得到的每一個結論(動物的類別)都叫做葉子節點。
節點
- 根節點:沒有進邊,有出邊。包含最初的,針對特征的提問。
- 中間節點:既有進邊也有出邊,進邊只有一條,出邊可以有很多條。都是針對特征的提問。
- 葉子節點:有進邊,沒有出邊,每個葉子節點都是一個類別標簽。
- 子節點和父節點:在兩個相連的節點中,更接近根節點的是父節點,另一個是子節點。
- 相親案例:
- 上述案例中就可以將被相親對象預測為見或者不見。上述分叉的結構就是決策樹,如果一個決策樹建立好之后,就可以基於該樹的相關分支得到不同分類的預測結果。
- 問題:為什么上述決策樹中不把收入(特征)作為判斷的第一步(作為樹的根節點)呢?
- 樹的根節點和中間節點對應的是某一種類型特征,那么這些節點(特征)自上而下的重要性應該是由大到小進行排列的。
- 因為我們普遍的認為年齡的重要性要大於收入!當然樹中的這些節點具有怎樣的重要性都是我們根據以往的經驗來設定的,其實這樣是不精准的,因為經驗會有誤差,不嚴謹。那么決策樹模型肯定是根據有理有據的科學的方法進行重要性的設定的。那么如何科學設定呢?首先我們得先知道決策樹算法主要解決的問題是什么!
決策樹算法的核心是要解決兩個問題:
- 1.如何從數據表中找出最佳節點或最佳分枝?
- 2.如何讓決策樹停止生長,防止過擬合?
- 決策樹是基於訓練集數據構建出來的,如果樹長的越大分支越細致,則對訓練數據的描述越清楚,但是不一定會很好的作用到測試數據中。
- 幾乎所有決策樹有關的模型調整方法,都圍繞這兩個問題展開。接下來,我們就來了解一下決策樹背后的原理。
構建決策樹
- 接下來討論如何根據已有的數據集來建立有效的決策樹。原則上講,任意一個數據集上的所有特征都可以被拿來分枝,特征上的任意節點又可以自由組合,所以一個數據集上可以發展出非常非常多棵決策樹,其數量可達指數級。在這些樹中,總有那么一棵樹比其他的樹分類效力都好,那樣的樹叫做”全局最優樹“。
- 全局最優:經過某種組合形成的決策樹,整體來說分類效果為最好的模型
- 局部最優:每一次分枝的時候都向着更好的分類效果分枝,但無法確認如此生成的樹在全局上是否是最優的
- 要在這么多棵決策樹中去一次性找到分類效果最佳的那一棵是不可能的,如果通過排列組合來進行篩選,計算量過於大而且低效,因此我們不會這樣做。相對的,機器學習研究者們開發了一些有效的算法,能夠在合理的時間內構造出具有一定准確率的次最優決策樹。
- 這些算法基本都執行”貪心策略“,即通過局部的最優來達到我們相信是最接近全局最優(次最優決策樹)的結果。
- 貪心算法
- 通過實現局部最優來達到接近全局最優結果的算法,所有的樹模型都是這樣的算法。
ID3算法構建決策樹
- 最典型的決策樹算法是Hunt算法,該算法是由Hunt等人提出的最早的決策樹算法。現代,Hunt算法是許多決策樹算法的基礎,包括ID3、C4.5和CART等。此處以應用較廣、理論基礎較為完善的ID3算法的基本原理開始,討論如何利用局部最優化方法來創建決策模型。
- ID3算法原型見於J.R Quinlan的博士論文,是基礎理論較為完善,使用較為廣泛的決策樹模型算法,在此基礎上J.R Quinlan進行優化后,陸續推出了C4.5決策樹算法,后者現已稱為當前最流行的決策樹算法,我們先從ID3 開始講起,再討論如何從ID3逐漸優化至C4.5。
- 為了要將數據集轉化為一棵樹,決策樹需要找出最佳節點和最佳的分枝方法,而衡量這個“最佳”的指標叫做“不純度”。 不純度基於葉子節點來計算的,所以樹中的每個節點都會有一個不純度,並且子節點的不純度一定是低於父節點的, 也就是說,在同一棵決策樹上,葉子節點的不純度一定是最低的。
不純度
- 決策樹的每個根節點和中間節點中都會包含一組數據(工作為公務員為某一個節點),在這組數據中,如果有某一類標簽占有較大的比例,我們就說該節點越“純”,分枝分得好。某一類標簽占的比例越大,葉子就越純,不純度就越低,分枝就越好。
- 如果沒有哪一類標簽的比例很大,各類標簽都相對平均,則說該節點”不純“,分枝不好,不純度高
- 這個其實非常容易理解。分類型決策樹在節點上的決策規則是少數服從多數,在一個節點上,如果某一類標簽所占的比例較大,那所有進入這個節點的樣本都會被認為是這一類別。具體來說,如果90%根據規則進入節點的樣本都是類別0(節點比較純),那新進入該節點的測試樣本的類別也很有可能是0。但是,如果51%的樣本是0,49%的樣本是1(極端情況),該節點還是會被認為是0類的節點,但此時此刻進入這個節點的測試樣本點幾乎有一半的可能性應該是類別1。從數學上來說,類分布為(0,100%)的結點具有零不純性,而均衡分布 (50%,50%)的結點具有最高的不純性。如果節點本身不純,那測試樣本就很有可能被判斷錯誤,相對的節點越純,那樣本被判斷錯誤的可能性就越小。
如何計算不純度?
- 信息熵
信息論基礎
- 問題:現在有32支球隊,然后猜出誰是冠軍!
- 如果我們不知道球隊的任何信息情況下,我們可以這么猜:
- 你可能會亂猜那么猜對的幾率為1/32。
- 如果你沒猜錯一次需要付出一定的代價,則你就會設計方法提升猜你對的幾率而減少代價。
- 每次折半猜,將32只球隊以此編碼為1-32,則第一次你會問,冠軍在1-16中,在1-8中嗎等等這樣折半的猜,那么這樣勢必會減少猜錯的幾率,付出較少的代價。
- 折半猜的話只需要猜log32=5次(底數為2)就可以知道結果啦。
- 你可能會亂猜那么猜對的幾率為1/32。
- 如果我們不知道球隊的任何信息情況下,我們可以這么猜:
- 結論:
- 我們已經知道32只球隊猜對的代價為log32=5次,64只球隊猜對的代價為log64=6次,以信息論的角度來講的話,代價為5次或者代價為6次被稱為代價為5比特或者代價為6比特。
- 比特:就是信息論中信息度量的單位也叫做信息量。這個概念是由信息論的創始人【香農】提出的。
- 重點:香農在信息論中提出信息量的值會隨着更多有用信息的出現而降低。
- 繼續猜冠軍的問題:
- 如果將32只球隊的一些往期比賽勝負的數據進行公開,則《誰是冠軍》的信息量的值肯定會小於5比特,其精准的信息量的值計算法則為:注意信息量的值在信息論中被稱為信息熵
-
公式解釋:
-
在誰是冠軍例子中,n就是32,p(xi)就是某只球隊獲勝的概率,H為信息量的值叫做【信息熵】
- 信息熵(entropy):是一種信息的度量方式,表示信息的混亂程度,也就是說:信息越有序,信息熵越低(不純度或者信息量越低)。
-
比特or信息量也就是信息熵的單位。那么在誰是冠軍的例子中每一個球隊獲勝的概率為1/32,通過折半計算的代價也就是信息熵為5:
- 5 = - (1/32log1/32 + 1/32log1/32 + ......),因為log1/32=-5(2**-5==1/32)為負數,所以求和后加一個負號表示正的結果5。5就是該事件的信息熵。
- 如果獲知了球隊的往期獲勝數據公開后,則德國獲勝概率為1/4,西班牙為1/5,中國為1/20,則帶入香農公式中為:
- 5 >= - (1/5log1/5 + 1/32+log1/32 + 1/4+log1/4+......)結果值一定小於5
- 結論:信息熵和消除不確定性是相關聯的
- 信息熵越大則表示信息的不確定性越大,猜對的代價大
- 信息熵越小則表示信息的不確定性越小,猜對的代價小
-
信息增益
- 為什么越重要的特征要放在樹的越靠上的節點位置呢?
- 因為我們的分類結果是要從樹的根節點開始自上而下的進行分步判斷從而得到正確的划分結論。越重要的節點作為樹中越靠上的節點可以減少基於該樹進行分類的更多的不確定性。
- 比如:將年齡作為根節點進行見面或者不見面的分類,可以比把收入作為根節點進行見或者不見的分類要降低了更多的不確定性。因為年齡如果太大的話直接就不見了,如果年齡適中則繼續根據樹下面的節點特征繼續進行判斷。如果將收入作為根節點,則收入高的話也不可以直接就見或者不見,還得考慮年紀問題,樣貌問題等等。
- 因為我們的分類結果是要從樹的根節點開始自上而下的進行分步判斷從而得到正確的划分結論。越重要的節點作為樹中越靠上的節點可以減少基於該樹進行分類的更多的不確定性。
- 如何衡量決策樹中節點(特征)的重要性呢?如何理解特診的重要性呢?
- 重要性:如果一個節點減少分類的不確定性越明顯,則該節點就越重要。
- 年齡要比收入可以減少更多見與不見分類結果的不確定性。
- 使用信息增益衡量特征的重要性
- 重要性:如果一個節點減少分類的不確定性越明顯,則該節點就越重要。
- 信息增益:
- 在根據某個特征划分數據集之前之后信息熵發生的變化or差異叫做信息增益,知道如何計算信息增益,獲得計算增益最高的特征就是最好的選擇。
- 信息增益作為決策樹的划分依據,決定決策樹怎么畫,每個特征作為節點存放位置的確定。
- 信息增益g(D,A)計算公式為:公式其實看不看得懂不重要,重要的是求解的思路
- 公式解釋:信息增益 = 划分前熵 - 划分后熵
- 總之需要計算出每個特征的信息增益,特征的信息增益越大,則表示該特征越重要,應該放在決策樹越靠上的位置!!!
構建決策樹
- 在構造決策樹時,我們需要解決的第一個問題就是,當前數據集上哪個特征在划分數據分類時起決定性的作用。為了找到決定性的特征,划分出最好的結果,我們必須評估每個特征。那么在構造過程中,你要解決三個重要的問題:
- 選擇哪個屬性作為根節點;
- 選擇哪些屬性作為子節點;
- 什么時候停止並得到目標狀態,即葉節點。
- 接下來以氣象數據為例子,來說明決策樹的構建過程:
- 在沒有使用特征划分類別的情況下,有9個yes和5個no,當前的熵為:
- 假設我們以 outlook 特征作為決策樹的根節點划分數據集,對該特征每項指標分別統計:在不同的取值下 play 和 no play 的次數:
- 此時各分支的熵計算如下:
--- p(xi)指的是某一個節點(sunny)中,某一類別占據該節點總類別的比例
- 因此如果用特征outlook來划分數據集的話,總的熵為:
- 每一個outlook的組成的信息熵乘以outlook組成占總樣本的比例
- 那么最終得到特征屬性outlook帶來的信息增益為:
- g(outlook)=0.940−0.694=0.246
- 然后用同樣的方法,可以分別求出temperature,humidity,windy的信息增益分別為:
- IG(temperature)=0.029
- IG(humidity)=0.152
- IG(windy)=0.048
- 可以得出使用outlook特征所帶來的信息增益最大。因此第一次切分過程將采用outlook字段進行切分數據集。
- 第一次切分完畢后,分成了三個數據集sunny,overcast,rain。期中overcast所指向的數據集純度為1,因此不用在對其進行切分。而剩下兩個純度不為1則需要對其繼續切分。然而對sunny數據集而言使用humidity特征進行切分后節點純度就變為1了,則不再進行繼續切分,同理對rain而言使用windy特征進行切分純度也變為了1不需要再次進行切分。最終決策樹為如下:
ID3的局限性
- 不能直接處理連續型數據集(標簽是連續型的),若要使用ID3處理連續型變量,則首先需要對連續變量進行離散化
- 連續性數據集是指數據的目標值為連續性,則無法計算某類別樣例數量占總類別樣例的占比。
- 對缺失值較為敏感,使用ID3之前需要提前對缺失值進行處理
- 存在缺失值則信息熵的公式無法計算結果
- 沒有剪枝的設置,容易導致過擬合,即在訓練集上表現很好,測試集上表現很差
其他算法:
- 信息熵:
- C4.5信息增益比
- 分支度:
- 在C4.5中,首先通過引入分支度的概念,來對信息增益的計算方法進行修正。而分支度的計算公式仍然是基於熵的算法,只是將信息熵計算公式中的p(xi)改成了p(vi),p(vi)即某子節點的總樣本數占父節點總樣本數比例。這樣的一個分支度指標,讓我們在切分的時候,自動避免那些分類水平太多,信息熵減小過快的特征影響模型,減少過擬合情況。
- 其中,i表示父節點的第i個子節點,vi表示第i個子節點樣例數,P(vi)表示第i個子節點擁有樣例數占父節點總樣例數的比例。很明顯,IV可作為懲罰項帶入子節點的信息熵計算中。所以IV值會隨着葉子節點上樣本量的變小而逐漸變大,這就是說一個特征中如果標簽分類太多(outlook特征的標簽分類有rain,overcast,sunny)即使信息熵比較大,但是IV大的話,則信息熵除以IV后就會變小,每個葉子上的IV值就會非常大,樹的分值就會越細。
- 分支度:
- 最終,在C4.5中,使用之前的信息增益除以分支度作為分支的參考指標,該指標被稱作Gain Ratio(信息增益比),計算公是為:
- 增益比例是我們決定對哪一列進行分枝的標准,我們分枝的是數字最大的那一列,本質是信息增益最大,分支度又較小的列
(也就是純度提升很快,但又不是靠着把類別分特別細來提升的那些特征)。IV越大,即某一列的分類水平越 多,Gain ratio
實現的懲罰比例越大。當然,我們還是希望GR越大越好
- CART(基尼系數)
- CART 的全稱是分類與回歸樹。從這個名字中就應該知道,CART 既可以用於分類問題,也可以用於回歸問題。
- CART 與 ID3,C4.5 不同之處在於 CART 生成的樹必須是二叉樹。也就是說,無論是回歸還是分類問題,無論特征是離散的還是連續的,無論屬性取值有多個還是兩個,內部節點只能根據屬性值進行二分。
如何選取使用何種算法
- 在實際使用中,信息熵和基尼系數的效果基本相同。信息熵的計算比基尼系數緩慢一些,因為基尼系數的計算不涉及對數。另外,因為信息熵對不純度更加敏感,所以信息熵作為指標時,決策樹的生長會更加“精細”,因此對於高維數據或者噪音很多的數據,信息熵很容易過擬合,基尼系數在這種情況下效果往往比較好。當模型擬合程度不足的時候,即當模型在訓練集和測試集上都表 現不太好的時候,使用信息熵。當然,這些不是絕對的。
- API:
- class sklearn.tree.DecisionTreeClassifier(criterion=’gini’, splitter=’best’, max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, class_weight=None, presort=False)[source]
創建一顆決策樹
- 使用datasets中的紅酒數據集
from sklearn import tree from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split # 提取樣本數據 dt = load_wine() feature = dt.data target = dt.target # 切分樣本數據 x_train,x_test,y_train,y_test = train_test_split(feature,target,test_size=0.2,random_state=2020) # criterion='entropy'使用信息熵構建決策樹 clf = DecisionTreeClassifier(criterion='entropy') clf.fit(x_train,y_train) # 多次執行會發現模型評分不一樣 clf.score(x_test,y_test) # 0.9444444444444444,0.9722222222222222
為何每次測評的分數不一致呢?
- 決策樹在建樹時,是靠優化節點來追求一棵最優化的樹,但最優的節點能夠保證構建出一顆最優的樹嗎?不能!sklearn表示,既然一棵樹不能保證最優,那就建更 的不同的樹,然后從中取最好的。怎樣從一組數據集中建不同的樹呢?在每次分枝時,不使用全部特征,而是隨機選取一部分特征,從中選取不純度相關指標最優的作為分枝用的節點。這樣,每次生成的樹也就不同了,非分數就會不同。
參數random_state
- 參數random_state 隨機選擇不同的特征來構建決策樹
- random_state用來設置分枝中的隨機模式的參數,默認None,在高維度時隨機性會表現更明顯,低維度的數據(比如鳶尾花數據集),隨機性幾乎不會顯現。輸入任意整數,會一直長出同一棵樹,讓模型穩定下來
clf = DecisionTreeClassifier(criterion='entropy',random_state=2020) clf.fit(x_train,y_train) clf.score(x_test,y_test) # 0.9722222222222222
畫決策樹
在anaconda的navigator中open terminal中執行:
- conda install graphviz(如果全部完成還是報錯請執行 conda install python-graphviz)
- pip install graphviz
- 重啟終端服務即可
import graphviz feature_name = ['酒精','蘋果酸','灰','灰的鹼性','鎂','總酚','類黃酮','非黃烷類酚類','花青素','顏色強度','色調','od280/od315稀釋葡萄酒','脯氨酸'] dot_data = tree.export_graphviz(clf, # 訓練好的決策樹模型 out_file=None, # 圖片保存路徑 feature_names= feature_name, # 指定特征名稱 class_names=["琴酒","雪莉","貝爾摩德"], # 分類類別 filled=True, # 使用顏色表示分類結果 ) graph = graphviz.Source(dot_data) graph
特征的重要屬性
- clf.feature_importances_ 返回特征的重要性 以后可以用決策樹對特征進行選擇
clf.feature_importances_ # 返回特征的重要性 array([0.0147939 , 0. , 0. , 0.00896494, 0. , 0. , 0.4874266 , 0.01618011, 0. , 0.30751403, 0. , 0. , 0.16512041]) # 返回特征的重要性 feature_name = ['酒精','蘋果酸','灰','灰的鹼性','鎂','總酚','類黃酮','非黃烷類酚類','花青素','顏 色強度','色調','od280/od315稀釋葡萄酒','脯氨酸'] [*zip(feature_name,clf.feature_importances_)] [('酒精', 0.01479390227172555), ('蘋果酸', 0.0), ('灰', 0.0), ('灰的鹼性', 0.008964941814890645), ('鎂', 0.0), ('總酚', 0.0), ('類黃酮', 0.48742660098390633), ('非黃烷類酚類', 0.01618010841300014), ('花青素', 0.0), ('顏 色強度', 0.30751403321904724), ('色調', 0.0), ('od280/od315稀釋葡萄酒', 0.0), ('脯氨酸', 0.16512041329743002)]
參數splitter
- splitter也是用來控制決策樹中的隨機選項的,有兩種輸入值:
- 輸入”best",決策樹在分枝時雖然隨機,但是還是會優先選擇更重要的特征進行分枝(重要性可以通過屬性feature_importances_查看)
- 輸入“random",決策樹在分枝時會更加隨機,樹會因為含有更多的不必要信息而更深更大,並因這些不必要信息而降低對訓練集的擬合。這也是防止過擬合的一種方式。
- 當你預測到你的模型會過擬合,用splitter和random_state這兩個參數來幫助你降低樹建成之后過擬合的可能性。
clf = tree.DecisionTreeClassifier(criterion="entropy" ,random_state=2020 ,splitter="random") clf = clf.fit(x_train, y_train) score = clf.score(x_test, y_test) score # 0.9444444444444444
剪枝參數
- 在不加限制的情況下,一棵決策樹會生長到衡量不純度的指標最優,或者沒有更多的特征可用為止。這樣的決策樹 往往會過擬合,這就是說,它會在訓練集上表現很好,在測試集上卻表現糟糕。我們收集的樣本數據不可能和整體 的狀況完全一致,因此當一棵決策樹對訓練數據有了過於優秀的解釋性,它找出的規則必然包含了訓練樣本中的噪 聲,並使它對未知數據的擬合程度不足。
- 為了讓決策樹有更好的泛化性,我們要對決策樹進行剪枝。剪枝策略對決策樹的影響巨大,正確的剪枝策略是優化 決策樹算法的核心。sklearn為我們提供了不同的剪枝策略:
- max_depth:限制樹的最大深度,超過設定深度的樹枝全部剪掉
- 這是用得最廣泛的剪枝參數,在高維度低樣本量時非常有效。決策樹多生長一層,對樣本量的需求會增加一倍,所 以限制樹深度能夠有效地限制過擬合。在集成算法中也非常實用。實際使用時,建議從=3開始嘗試,看看擬合的效 果再決定是否增加設定深度。
- min_samples_leaf & min_samples_split:
- min_samples_leaf限定,一個節點在分枝后的每個子節點都必須包含至少min_samples_leaf個訓練樣本,否則分 枝就不會發生,或者,分枝會朝着滿足每個子節點都包含min_samples_leaf個樣本的方向去發生。一般搭配max_depth使用。這個參數的數量設置得太小會引 起過擬合,設置得太大就會阻止模型學習數據。一般來說,建議從=5開始使用。
- min_samples_split限定,一個節點必須要包含至少min_samples_split個訓練樣本,這個節點才允許被分枝,否則 分枝就不會發生。
- max_depth:限制樹的最大深度,超過設定深度的樹枝全部剪掉
import graphviz clf = tree.DecisionTreeClassifier(criterion="entropy" ,random_state=30 ,splitter="random" ,max_depth=4 # 樹最多只能4層,超過就會剪掉,不算根節點 ,min_samples_leaf=10 # 一個節點分支后每個葉子必須最少有10個樣本,否則不分枝 ,min_samples_split=20 # 節點必須有20個樣本才允許分支,否則就不能分枝 ) clf = clf.fit(x_train, y_train) dot_data = tree.export_graphviz(clf ,feature_names= feature_name ,class_names=["琴酒","雪莉","貝爾摩德"] ,filled=True ,out_file = None#圖片保存路徑 ) graph = graphviz.Source(dot_data) graph
案例應用、泰坦尼克號乘客生存分類
- 泰坦尼克號的沉沒是世界上最嚴重的海難事故之一,今天我們通過分類樹模型來預測一下哪些人可能成為幸存者。 數據集為data.csv
特征介紹
- Survived:是否生存
- Pclass:船票等級,表示乘客社會經濟地位
- Name,Sex,Age
- SibSp:泰坦尼克號上的兄弟姐妹/配偶數
- Parch:泰坦尼克號上的父母/子女數量
- Ticket:船票號
- Fare:票價
- Cabin:船艙號
- Embarked:登船港口號
import pandas as pd from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split data = pd.read_csv(r"./data.csv",index_col = 'PassengerId') data.head()
data.info() <class 'pandas.core.frame.DataFrame'> Int64Index: 891 entries, 1 to 891 Data columns (total 11 columns): Survived 891 non-null int64 Pclass 891 non-null int64 Name 891 non-null object Sex 891 non-null object Age 714 non-null float64 SibSp 891 non-null int64 Parch 891 non-null int64 Ticket 891 non-null object Fare 891 non-null float64 Cabin 204 non-null object Embarked 889 non-null object dtypes: float64(2), int64(4), object(5) memory usage: 83.5+ KB # 刪除缺失值較多和無關的特征 data.drop(labels=['Cabin','Name','Ticket'],inplace=True,axis=1) # 填充age列 data["Age"] = data["Age"].fillna(data["Age"].mean()) # 清洗空值 data.dropna(inplace=True) data.head()
#將性別轉換成數值型數據 data["Sex"] = (data["Sex"]== "male").astype("int") data.head()
# 將三分類變量轉換為數值型變量 labels = data["Embarked"].unique().tolist() data["Embarked"] = data["Embarked"].map(lambda x: labels.index(x)) data.info() <class 'pandas.core.frame.DataFrame'> Int64Index: 889 entries, 1 to 891 Data columns (total 8 columns): Survived 889 non-null int64 Pclass 889 non-null int64 Sex 889 non-null int32 Age 889 non-null float64 SibSp 889 non-null int64 Parch 889 non-null int64 Fare 889 non-null float64 Embarked 889 non-null int64 dtypes: float64(2), int32(1), int64(5) memory usage: 59.0 KB X = data.iloc[:,data.columns != "Survived"] y = data.iloc[:,data.columns == "Survived"] from sklearn.model_selection import train_test_split Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3) clf = DecisionTreeClassifier(random_state=25) clf = clf.fit(Xtrain, Ytrain) score_ = clf.score(Xtest, Ytest) score_ # 0.7677902621722846
用網格搜索調整參數
Grid Search:一種調參手段;窮舉搜索:在所有候選的參數選擇中,通過循環遍歷,嘗試每一種可能性,表現最好的參數就是最終的結果。其原理就像是在數組里找最大值。(為什么叫網格搜索?以有兩個參數的模型為例,參數a有3種可能,參數b有4種可能,把所有可能性列出來,可以表示成一個3*4的表格,其中每個cell就是一個網格,循環過程就像是在每個網格里遍歷、搜索,所以叫grid search)
import numpy as np from sklearn.model_selection import GridSearchCV parameters = {'splitter':('best','random') ,'criterion':("gini","entropy") ,"max_depth":[*range(1,10)] ,'min_samples_leaf':[*range(1,50,5)] } clf = DecisionTreeClassifier(random_state=25) GS = GridSearchCV(clf, parameters, cv=10) # cv交叉驗證 GS.fit(Xtrain,Ytrain) GS.best_params_ {'criterion': 'entropy', 'max_depth': 6, 'min_samples_leaf': 6, 'splitter': 'best'} GS.best_score_ # 0.8362007168458782