咱們這裏介紹一下一個比較簡單的機器學習系統----決策樹. 它的概念最容易理解, 由於人類的許多決策實際上就是一個決策樹.html
一般使用的分類迴歸樹(class and regress tree)是一個二叉樹。它的形式通常爲:node
每一個方框表明一個節點. 每一個非葉子節點有2個分支, 一個是斷定True, 一個斷定False. 分別走兩個不一樣的分支. 葉子節點具備決策權. 任何一個輸入從root出發, 老是會達到且惟一到達一個葉子節點. 這就是決策樹的工做原理.python
決策樹有兩種節點: 中間節點和葉子節點。git
每一箇中間節點有4個參數:
a) 斷定函數。 是一個特徵的取值。 當特徵小於等於這個值得時候決策路徑走左邊, 當特徵大於這個值得時候決策樹走右邊。
b) 不純度值(impurity value). 是當前節點的不純度值. 關於不純度值得意義後面會講到. 他反應了當前節點的預測能力.
c) 覆蓋樣本個數(n_samples). 是指參與此節點決策的樣本個數. 父親節點(p)和兩個孩子節點(l,r)的樣本個數的關係爲: n_samples(p) = n_samples(l) + n_samples(r) 覆蓋樣本個數越多, 說明斷定函數越穩定. 實際上很容易看出來, 全部的葉子節點所對應的樣本是總樣本的一個劃分.
d) 節點取值(node value). 節點取值是一個數組. 數組的長度爲類目個數. value = [997, 1154] 表示在2151個樣本數中, 有997個屬於class1, 1154屬於class2. (這是分類樹的意義, 會歸數的取值規則後面會講.)github
每一個葉子節點有3個參數. 除了沒有決策函數以外, 其餘參數意義同樣.算法
決策樹最重要的概念就是不純函數(I)的概念. 當一個節點須要分割的時候, 實際上就是找到一個合適的特徵的一個合適的取值做爲閾值(thresh)進行分割. 那麼問題來了, 怎麼找到那個合適的特徵的合適的取值呢? 主要的依據就是不純度的變化(delta I). 首先咱們給出不純度函數的定義. 不純度函數不是一個具體的函數, 它是知足一系列約束的函數的總稱.數組
根據輸出實例的取值範圍不一樣. 決策樹有不一樣的種類. 若是輸出實例是離散的, 那麼決策樹是一個分類樹; 若是輸出實例是連續的, 那麼決策樹是一個迴歸樹.若是決策樹是分類樹. 那麼輸出空間定義爲輸出實例全部取值的集合. 這個集合是有限集合. 不失通常性, 使用{1,...,k}這可個取值. 不純度函數(I)的定義爲:dom
每一項其實就是屬於類目c_i的機率, 記爲p_i.機器學習
如上公式能夠看出不純度函數的定義域是長度爲k的向量, 向量每一個數的取值爲0~1, 且加和爲1. 第i個數是特徵矩陣中屬於類別i的特徵向量個數在整個樣本個數(n_sample)的佔比.且必須知足以下約束:函數
當全部樣本都屬於同一類時候I取最小值. 即I在點(1,0,...,0),(0,1,...,0),...,(0,..,0,1)(1,0,...,0),(0,1,...,0), ..., (0,..,0,1)(1,0,...,0),(0,1,...,0),...,(0,..,0,1)取最小值.
當樣本中每一個類目下樣本個數相同時I取最大值. 即I在點(1/k,..,1/k)取最大值.
I對於定義域中每一個取值p_1,...,p_k是對稱的. 即I(p_1, p_2,...,p_k) = I(p_2,p_1,..,p_k)等. 從函數圖像的角度理解, 就是函數必定是關於值座標軸對稱.
I必須是絕度凸函數(strickly concave)即設p和p'(注意這裏是一個長度爲k的向量)爲定義域下兩個可能的取值. 那麼
另一個概念是不純度變化(impurity reduction).
咱們回到決策樹的結構, 每一個父節點的兩個子節點都是對父節點的劃分. 那麼如何評價此次劃分呢? 因而咱們引入了不純度變化(impurity reduction)的概念. 咱們看着公式來理解:
考慮通常性咱們設X_1,X_2...X_s是特徵空間X的一個劃分. 不純度變化定義爲:
這個公式很好理解,令s=2, 那麼 X_1,X_2是對於原空間的一個劃分. 按理說, 一個好的劃分應該讓不純度變低, 以便讓類目歸屬更加清晰. 公式後面一個累加和實際上就是這兩個劃分的不純度的指望. 原不純度減去劃分後的不純度的指望就是減小的不純度的差值. 顯然這個差值越大說明劃分讓子節點的純度更"純".
另外, 須要強調一點, 根據不純度函數的第三個約束, 即不純度函數是定義域下的凸函數, 能夠保證不純度變化(impurity reduction) 大於等於0.當且僅當全部劃分的樣本數至關取0.
可這麼說, 分類決策樹節點劃分的依據是找到一個特徵的一個取值, 根據這個劃分是的不純度縮減量最大.
下面咱們介紹兩個經常使用不純度函數, 信息熵(info entropy)和基尼指數(gini index).
首先介紹一下信息熵的概念. 咱們把樣本抽取過程當作一次隨機試驗A, 那麼A有k個可能的輸出A_1,A_2,...,A_k . 對應於k個分類. 那麼A的信息熵定義爲:
信息熵知足不純度函數的定義. 因此咱們定義:
把這個不純度函數的定義帶入到不純度函數的公式中就能夠獲得相應的不純度變化函數.
這個函數很出名, 咱們把它寫出來(後面的基尼指數就不寫了.)
按照教課書的習慣, 當不純度函數爲信息熵時不純度變化又叫作信息增益(info gain).
這裏強調一下無論是信息熵仍是基尼指數, 他們都是不純函數的一種表達, 不純度變化的計算沒有任何變化. 咱們也能夠本身撰寫不純度函數. 當k=2時候, 咱們能夠吧信息熵和基尼指數在二維座標上圖形畫出來.
能夠看出來這兩個方法的區別很小. 實際過程當中使用哪一個方法做爲不純度函數效果不會有太大變化.
咱們如今瞭解了分類決策樹在每次分割過程當中如何評價分割的好壞, 一遍每次找到最佳分割點. 下面咱們繼續介紹迴歸數是如何定義不純度函數的.
咱們考慮一下會歸樹的構建過程. 當決策樹只有一個節點的時候(root節點), 這個節點包含全部待測試樣本. 若是咱們須要選擇一個數來預測函數的取值, 咱們會選哪一個? 因爲咱們沒有任何多餘的信息, 根據最大似然原則, 咱們取全部樣本取值的均值, 做爲預測值.
一樣的道理隨着決策樹的創建, 全部的葉子節點是root節點的一個劃分. 每一個葉子節點都充當一個預測器的角色. 每一個葉子節點的預測值是每一個節點包含的樣本取值的均值.
那麼對於迴歸決策樹來講, 咱們的任務是如何有效的劃分讓每一個葉子節點更具備表明性. 若是讓一個葉子節點更具備表明性, 咱們直觀的感覺是這個節點的樣本都趨同於均值(指望), 實際上就是方差較小. 這正是迴歸決策樹不純度函數的定義的理論依據.
對於給定的訓練集:
Y是連續變量. 考慮如何生成迴歸數.考慮一顆分類樹, 每一個葉子節點都對應一組機率值, 表示達到這個葉子節點的樣本分到每一個類目下的機率. 迴歸數基本結構和分類數同樣, 不一樣的是每一個葉子節點都表示對於到達這個葉子節點的樣本的預測值(f(x)). f(x)等於這個葉子節點全部輸入實例x_i對應的輸出y_i的均值.有的葉子節點是對樣本的一個劃分R_1, R_2, ..., R_m
舉個例子:
這顆迴歸樹是對拋物線y=1-x^2 ( -1 <x< 1)模擬, 咱們把原函數和預測函數花在同一個座標系統.
我看觀察圖形能夠看出, 迴歸樹的特色是使用連續的折線來擬合曲線. 由於在每一個葉子節點的取值是固定的, 而這顆迴歸樹只有8個葉子節點.
迴歸樹的構建和分類數構建方法相似. 一樣是須要找個一個劃分, 使得不純函數的縮減最大. 可是上面所介紹的不純度函數是根據分類樹定義的. 咱們須要定義適應迴歸樹的不純度函數.
在迴歸數中每一個非葉子節點都是樣本空間的一個子集的處理單元. 某個子集爲X_m每一個樣本x有2個屬性, 一個是實際輸出y, 另外一個是預測輸出hat(y). 上面介紹過hat(y)是經過這個節點下全部y的均值算出來的, hat(y)是這個節點下全部y的指望. 反應的是整體上的擬合程度. 那麼另一個衡量集合穩定性的指標是方差, 它衡量hat(y)的表明性. 方差越小, 說明hat(y)越具備表明性. 所以咱們能夠定義一種不純度函數, 就是這個節點下輸出值的方差.
一樣的帶入不純度變化的公式, 通過必要的化簡咱們獲得:
值得注意的是, 公式中有2處對於當前節點來講是常數. 只有最小二乘有實際意義. 咱們最大化不純度變化, 就是最小化最小二乘函數.
通常的教科書直接寫成這樣的公式:
這種方法又叫作"最小二乘法".
在本文中咱們給出一個符合不純度函數定義的解釋. 這樣保證迴歸樹和決策樹在實現上是統一的.
上面介紹了決策樹一個重要概念, 不純函數. 不純函數不只是分類樹的概念, 也是迴歸樹的概念. 它們在形式上是統一的. 這點頗有意義, 下面咱們分析sklearn源碼時候能夠發現, 在設計決策樹時候沒有區分分類和迴歸樹, 他們的不一樣都被封裝在不純函數的定義和計算節點的輸出中了.
上面一章介紹了分類和迴歸數在某個節點如何選擇合適的特徵和特徵取值進行分裂. 這一章介紹決策樹的構建方法, 即如何決定每步應該分裂的節點. 決策樹的構建通常有2種方法
深度優先
廣度優先
名稱 | 圖像 | 說明 |
---|---|---|
廣度優先 | ![]() |
廣度優先按照層次來構建樹的. 首先根據合適的不純度函數來分裂root成2個節點; 而後依次分裂第二層的2個節點; 依次遞推. |
深度優先 | ![]() |
深度優先採用遞歸的思想, 在每一個節點都是優先有左邊的子樹建好, 再建右邊子樹 |
無論是深度優先仍是廣度優先, 決策樹算法都須要知道何時一個節點應該做爲葉子節點. 若是沒有約束決策樹會一直建設下去知道節點只有一個類目(或者只有一個取值)才中止. 這樣會致使決策樹變得很是龐大, 引起過擬合問題.
通常來講, 當以下條件其中之一知足的時候, 當前節點中止構建, 做爲決策樹的葉子節點.
參數 | 意義 | 終止條件 |
---|---|---|
min_samples_split | 當前節點容許分裂的最小樣本數 | 當前節點樣本數小於這個值時候 |
min_samples_leaf | 葉子節點最少樣本數 | 任何分裂不能致使子節點的樣本數小於此值, 不然禁止分裂 |
min_impurity_split | 分裂的不純度閾值 | 當前節點不純度小於此值時不分裂 |
max_path | 數的最大深度 | 當前節點的深度大於等於此值是不分裂 |
這些控制條件能夠控制數的規模, 由於根據不純度變化的定義, 將全部的節點都放在惟一的葉子節點(這樣每一個葉子節點不純度都是0)中不純度變化最大. 這顯然不是咱們想要的.
經過上述的說明, 決策樹的預測就很是的簡單了. 決策樹中只有葉子節點有預測功能. 一個測試樣本從root出發選擇正確的路徑, 必定會走到一個葉子節點. 葉子節點的值即爲決策樹對這個>樣本的預測.
若是是分類樹. 葉子節點給出每一個類別的佔比. 機率最大的類別做爲這個葉子節點的預測值. 其機率值爲置信度.
若是是迴歸樹. 葉子節點的全部樣本的輸出的平均值做爲這個測試樣本的預測值.
本文的結構實際上就是按照sckit-learn中的決策樹進行設計的. 源代碼在: https://github.com/scikit-learn/scikit-learn/tree/master/sklearn/tree .
首先介紹一下主要文件:
criterion.py* 主要定義了各類不純度函數及其計算和轉化方法.
主要類 | 功能描述 |
---|---|
abstract Criterion | 定義一系列計算某個不純度或者不純度縮減的方法 1. node_impurity: 計算當前節點的不純度 2. children_impurity: 計算2個子節點的不純度 3. impurity_improvement: 計算當前節點的不純度縮減量 4. proxy_impurity_improvement: 因爲當前節點的不純度是一個常數, 所以在比較不純度縮減量時候有更加簡單的方法, 這個方法在分裂過程當中最經常使用, impurity_improvement僅當須要計算不純度縮減絕對值時才用 5. node_value: 當前節點的值, 用於預測. 當決策樹是分類樹時它計算每一個類目的機率, 當決策樹是迴歸數是, 計算全部樣本輸出的均值, 做爲輸出值 |
Class ClassificationCriterion | 繼承 Criterion; 重寫node_value方法, 適應分類樹的計算 |
Class Entropy | 繼承ClassificationCriterion; 重寫impurity各個方法, 符合entropy的定義 |
Class Gini | 繼承ClassificationCriterion; |
Class RegressionCriterion | 繼承 Criterion; 重寫node_value方法, 適應迴歸樹的計算 |
class MSE | 繼承 RegressionCriterion 主要實現上文提到迴歸數的不純度計算方法 |
splitter.py* 主要解決一些工程性的問題. 根據不純度算法的要求, 咱們要在每一個節點遍歷全部特徵的全部取值. 在性能角度須要考慮:
若是某個特徵取值是連續的, 是否必定須要遍歷全部取值? 若是相鄰的取值差距很小是否能夠直接跳過?
有沒有一些折中的方案是速度和質量的折中? 好比一些隨機算法?
主要類 | 功能描述 |
---|---|
Abstract Splitter | 抽象類, 定義分割須要的基本方法 |
class BestSplitter | 繼承Splitter 最優質的分割方法, 每次分割幾乎遍歷全部全部特徵的全部取值, 可是爲了加速, 有一個叫step的參數, 若是相鄰的兩個取值間隔小於step就直接忽略 |
class RandomSplitter | 繼承Splitter 採用隨機算法沒有遍歷特徵的全部值, 通常都是使用BestSplitter |
這個文件是講全部的功能拼裝在一塊兒造成一個能夠獨立使用決策樹類. 首先它聲明瞭一個TreeBuilder的系列類, 用於實現前文所說的深度優先建樹和廣度優先建樹.
這是源代碼中爲惟一一個python文件(其餘都是cython文件). 他主要封裝了_tree.py* 定義和主流機器學習庫兼容的方法體系.
本章, 咱們給出一個完整的實例.這個例子很簡單, 可是咱們仍是能夠發現參數調整對於決策樹質量的重要性.
這個實例很簡單. 首先須要使用DecisionTreeRegressor來聲明一個迴歸樹. 而後使用fit來訓練, 最後使用predict來預測結果.
圖像中咱們看到有點欠擬合, 咱們加大max_depth=3和max_depth=5
咱們看出來max_depth=5就已經有點過擬合. 可是咱們對max_depth=3還有有點不滿意.
咱們進一步改進, 維持max_depth=5不變, 增長min_samples_leaf=5的參數. 效果進一步提高.
能夠看到參數對於決策樹的質量來講很是重要.
同時咱們注意到在0附近無論設置什麼參數預測效果都不好. 這是由迴歸樹的性質決定的. 迴歸決策樹對於稀疏的數據的預測效果是很是差的. 咱們從不純度函數的定義就能夠理解. 不純度函數是一個葉子節點的方差, 要求方差儘量小, 這樣越是比較趨同的樣本越容易被分到同一個節點內, 致使原本就稀疏的節點更加稀疏, 稀疏點附近的均值根本就沒有表明性.
通常來講, 機器學習都須要特徵歸一化, 目的是讓特徵之間的比較能夠在同一個量綱上進行. 可是從數據構建過程來看, 不純函數的計算和比較都是單特徵的. 全部決策樹不須要數據的歸一>化. 可是有點須要注意, 從上文中對splitter的源碼分析中能夠看出, 決策樹爲了加速遍歷沒有真正遍歷全部取值, 當特徵的絕對值過小的時候會致使相鄰值的間隔小於step, 所以儘可能讓特>徵值不要過小(大於0.01比較保險).
在gini函數小節中咱們比較了gini和entroy在兩元下的圖形. 能夠看到基本上沒有區別. 有研究代表不一樣的不純度函數對決策樹產生的影響在2%之內[1].
事實上不多有實際案例說明選擇不純度函數有顯著的做用. 因此對於分類決策樹選擇gini, 對於迴歸選擇MSE, 這樣的默認配置能夠知足絕大多數的需求.
決策樹的重要參數都是防止過擬合的. 我認爲2個參數必定要設置:
min_samples_leaf 這個sklearn的默認值是1. 經驗上必須大於100, 若是一個節點都沒有100個樣本支持他的決策, 通常都被認爲是過擬合.
max_path 這個參數控制樹的規模. 決策樹是一個很是直觀的機器學習方法. 通常咱們都會把它的決策樹結構打印出來觀察, 若是深度太深對於咱們的理解是有難度的. max_path也是防止>過擬合的有效手段.
咱們回到不純度函數變化公式的自己:
咱們假設決策樹每一個節點能夠有多個子樹. 舉個極端的例子, 某一個特徵的全部取值都不相同, 那麼能夠找到一個劃分方法(只要足夠多的子樹)可讓每一個子樹都有惟一的類別. 那麼此時公>式的後半段爲0. 這樣不純度變化取到最大值. 很明顯這是一個算法上的偏見, 已經造成了過擬合
.
可是若是是二叉樹就能夠有效的避免這個問題. 他迫使特徵有多個取值這樣的優點無效.
決策樹的主要問題是容易造成過擬合. 若是咱們經過各類剪枝和條件限制, 雖然能夠避免過擬合, 可是會犧牲特徵的有效性. 舉個例子:
樣本有1w個測試記錄
feature的數量是1k個
爲了保證模型的有效性, 規定每一個葉子節點包含的最少樣本數爲100
在構造決策樹的過程當中咱們能夠斷言節點個數不會超過100個, 這樣不少feature不只沒有屢次分裂, 甚至有些特徵根本沒法參與決策.
爲了解決決策樹一系列的問題(這裏不一一列舉), 統計學家再也不深刻決策樹的結構而是提出另一個思路: 可以經過構造不一樣的簡單的決策樹共同決策? 這有點"三個臭皮匠頂一個諸葛亮"的感受. 我會在下一個文章具體介紹一下這個方法, 即隨機森林. 它是一個更加有效和經常使用的機器學習算法.
http://www.quora.com/Machine-Learning/Are-gini-index-entropy-or-classification-error-measures-causing-any-difference-on-Decision-Tree-classification ↩