1. 程式人生 > >機器學習之決策樹——學習總結

機器學習之決策樹——學習總結

決策樹學習總結

機器學習的應用越來越廣泛,特別是在資料分析領域。本文是我學習決策樹演算法的一些總結。

機器學習簡介

機器學習 (Machine Learning) 是近 20 多年興起的一門多領域交叉學科,涉及概率論、統計學、逼近論、凸分析、演算法複雜度理論等多門學科。簡而言之,機器學習是通過學習老知識(訓練樣本),得出自己的認知(模型),去預測未知的結果。

  • 學習方式
    • 監督式學習
      • 從給定的訓練資料集中學習出一個函式,當新的資料到來時,可以根據此函式預測結果。訓練資料集中的目標由人標註的。常見的演算法有迴歸分析和統計分類
    • 非監督式學習
      • 與監督式學習相比,訓練集沒有人為標註的結果,常見的演算法有聚類
    • 半監督式學習
      • 訓練集部分被標識,部分沒有被標識。常見的演算法有SVM
    • 強化學習
      • 輸入資料作為模型的反饋,模型對此作出調整。常見的演算法有時間差學習
  • 機器學習演算法分類
    • 決策樹演算法
      • 根據資料屬性,採用樹狀結構建立決策模型。常用來解決分類和迴歸問題。
      • 常見演算法:CART(Classification And Regression Tree),ID3,C4.5,隨機森林等
    • 迴歸演算法
      • 對連續值預測,如邏輯迴歸LR等
    • 分類演算法
      • 對離散值預測,事前已經知道分類,如k-近鄰演算法
    • 聚類演算法
      • 對離散值預測,事前對分類未知,如k-means演算法
    • 神經網路
      • 模擬生物神經網路,可以用來解決分類和迴歸問題
      • 感知器神經網路(Perceptron Neural Network) ,反向傳遞(Back Propagation)和深度學習(DL)
    • 整合演算法
      • 整合幾種學習模型進行學習,將最終預測結果進行彙總
      • Boosting、Bagging、AdaBoost、隨機森林 (Random Forest) 等

決策樹演算法

  • 初識決策樹
    決策樹演算法是藉助於樹的分支結構實現分類。以相親約會決策為例,下圖是建立好的決策樹模型,資料的屬性有4個:年齡、長相、收入、是否公務員,根據此模型,可以得到最終是見或者不見。
    這裡寫圖片描述
    這樣,我們對決策樹有個初步認識:

    • 葉子節點:存放決策結果
    • 非葉子節點:特徵屬性,及其對應輸出,按照輸出選擇分支
    • 決策過程:從根節點出發,根據資料的各個屬性,計算結果,選擇對應的輸出分支,直到到達葉子節點,得到結果
  • 構建決策樹
    通過上述例子,構建過程的關鍵步驟是選擇分裂屬性,即年齡、長相、收入、公務員這4個屬性的選擇先後次序。分裂屬性是在某個節點處按照某一特徵屬性的不同劃分構造不同的分支,其目標是讓各個分裂子集儘可能的“純”,即每個子集儘量都屬於同一分類項。分裂屬性分3種情況:

    • 屬性是離散值且不要求生成二叉樹
      • 屬性的每個值作為一個分支
    • 屬性是離散值且要求生成二叉樹
      • 按照“屬於”和“不屬於”分成2個分支
    • 屬性是連續值
      • 確定一個分裂點split_point,按照>split_point和<=split_point生成2個分支

    注意,決策樹使用自頂向下遞迴分治法,並採用不回溯的貪心策略分裂屬性的選擇演算法很多,這裡介紹3種常用的演算法:資訊增益(Information gain)、增益比率(gain ratio)、基尼指數(Gini index)

  • 資訊增益(Information Gain)
    基於香濃的資訊理論,資訊熵表示不確定度,均勻分佈時,不確定度最大,此時熵就最大。當選擇某個特徵對資料集進行分類時,資料集分類後的資訊熵會比分類前的小,其差值即為資訊增益。資訊增益可以衡量某個特徵對分類結果的影響大小,越大越好。
    • 典型演算法:ID3
    • 資料集D中,有m個類別,\( p_i \)表示D中屬於類別i的概率,此資料集的資訊熵定義為:Info(D)=_i=1mp_ilog_2(p_i)
    • 以屬性R作為分裂屬性,R有k個不同的取值,將資料D劃分成k組,按R分裂後的資料集的資訊熵為:Info_R(D)=_j=1k|D_j||D|×Info(D_j)
    • 資訊增益,即為劃分前後,資訊熵之差:Gain(R)=Info(D)InfoR(D)
    • 在每層分裂時,選擇使得Gain(R)最大的屬性作為分裂屬性
    • 缺點:此公式偏向資料量多的屬性,如果樣本分佈不均,則會導致過擬合。假如上述例子中包括人名屬性,每個人名均不同,顯然以此屬性作為劃分,資訊增益最高,但是,很明顯,以此屬性作為劃分毫無意義
  • 資訊增益比率(Gain Ratio)
    針對上述方法問題,此方法引入分裂資訊SplitInfo_R(D)=_j=1k|D_j|D×log_2(|D_j|D))
    • 典型演算法:C4.5
    • 資訊增益比率定義為:GainRatio(R)=Gain(R)SplitInfo_R(D)
    • 缺點:\( SplitInfo_R(D) \)可能取值為0,此時無意義;當期趨於0時,GainRatio也不可信,改進措施是在分母加一個平滑,這裡加所有分裂資訊的平均值\( GainRatio(R)=\frac{Gain(R)}{\overline{SplitInfo(D)}+SplitInfo_R(D)} \)
  • 基尼指數(Gini index)
    另外一種資料不純度的度量方法,定義為:Gini(D)=1_i=1mp_i2
    其中,m為資料集D中類別的個數,\( p_i \)表示D中屬於類別i的概率,如果所有記錄都屬於同一個類中,則P1=1,Gini(D)=0。
    • 典型演算法:CART
    • 以屬性R作為分裂屬性,R有k個不同的取值,將資料D劃分成k組,按R分裂後的資料集的基尼指數為:Gini_R(D)=_i=1k|D_i||D|Gini(D_i)
    • 計算劃分前後基尼指數之差Gini(R)=Gini(D)Gini_R(D)計算Gini(R)增量最大的屬性作為最佳分裂屬性。

spark中實現

具體程式碼參考spark原始碼包下的org.apache.spark.examples.mllib.DecisionTreeClassificationExampleDecisionTree.trainClassifier的實現步驟,核心程式碼在RandomForest.run()方法

  • 根據輸入資料,構建RDD[LabeledPoint],儲存label和features
  • 根據資料,構建metaData,包括feature個數、樣本資料條數、分類個數等
    • val metadata =
      DecisionTreeMetadata.buildMetadata(retaggedInput, strategy, numTrees, featureSubsetStrategy)
  • 計算每個feature的可能劃分點split1、split2。。。split(n-1)劃分成n個bin
    • val splits = findSplits(retaggedInput, metadata, seed)
    • 連續值:取樣資料,根據不同值個數和步長進行劃分
    • 離散:
      • unorder:特徵種類為binsNum(分類個數不大,且為多分類)
      • order:迴歸、二分類、多分類且數量很大,都使用二分類
  • 根據feature的split,計算每條資料在每個feature下所在的bin,生成新的RDD[TreePoint(Label, featuresBin[])]
    • val treeInput = TreePoint.convertToTreeRDD(retaggedInput, splits, metadata)
  • bagging取樣(示例中,不需要取樣,因為只生成一個tree)
    • val baggedInput = BaggedPoint
      .convertToBaggedRDD(treeInput, strategy.subsamplingRate, numTrees, withReplacement, seed)
      .persist(StorageLevel.MEMORY_AND_DISK)
  • 新建樹根root,放到queue中,迴圈直到佇列為空
    • 選擇多個訓練樹節點,同時進行訓練,根據指定的maxMemoryUsage進行個數計算
      • val (nodesForGroup, treeToNodeToIndexInfo) =
        RandomForest.selectNodesToSplit(nodeQueue, maxMemoryUsage, metadata, rng)
    • 按照Gini係數,找到當前樹節點中,最佳的feature分裂點和最佳bin分割點
      • RandomForest.findBestSplits(baggedInput, metadata, topNodes, nodesForGroup,
        treeToNodeToIndexInfo, splits, nodeQueue, timer, nodeIdCache)
      • 遍歷資料,mapPartition,每個樹節點LearnNode維護一個DTStatsAggregator(存放,每個feature的每個bin的資料個數)
      • 進行DTStatsAggregator的聚合merge
      • 按照Gini係數,找到最佳的feature下的最佳split

引數設定

可以通過設定一些引數,調整演算法或調優,詳細參考spark官網介紹

  • 演算法設定
    • algo:決策樹型別,分類或迴歸,Classification or Regression
    • numClasses: 分類問題設定分類個數
    • categoricalFeaturesInfo:指定哪些feature是離散值,並指定離散值的個數
  • 停止條件設定
    • maxDepth:樹最大深度
    • minInstancesPerNode:每個樹節點最小的訓練資料個數,如果小於此值,則不進行分裂
    • minInfoGain:最小資訊增益,決定當前樹節點是否進行分裂
  • 調優引數
    • maxBins:用於連續特徵值的分散化,最多劃分類個數
    • maxMemoryInMB:增大,可以提高同時訓練的樹節點的個數,從而減少訓練時間,但是,每次訓練會增大資料的傳輸量
    • subsamplingRate:訓練森林時使用,每次取樣的比例
    • impurity:純度度量函式,必須和演算法algo相匹配

參考文件