【機器學習】--決策樹和隨機森林

1、前述node

決策樹是一種非線性有監督分類模型,隨機森林是一種非線性有監督分類模型。線性分類模型好比說邏輯迴歸,可能會存在不可分問題,可是非線性分類就不存在。
2、具體原理算法

ID3算法apache

一、相關術語dom

根節點:最頂層的分類條件
葉節點:表明每個類別號
中間節點:中間分類條件
分枝:表明每個條件的輸出
二叉樹:每個節點上有兩個分枝
多叉樹:每個節點上至少有兩個分枝機器學習

 二、決策樹的生成:函數

數據不斷分裂的遞歸過程,每一次分裂,儘量讓類別同樣的數據在樹的一邊,當樹的葉子節點的數據都是一類的時候,則中止分類。(if else 語句)

學習

三、如何衡量純粹度

舉例:測試

箱子1:100個紅球
箱子2:50個紅球  50個黑球
箱子3:10個紅球  30個藍球 60綠球
箱子4:各個顏色均10個球

spa

憑人的直覺感覺,箱子1是最純粹的,箱子4是最混亂的,如何把人的直覺感覺進行量化呢?
將這種純粹度用數據進行量化,計算機才能讀懂    scala

舉例:

 

 

度量信息混亂程度指標:

熵的介紹:

熵公式舉例:

 

熵表明不肯定性,不肯定性越大,熵越大。表明內部的混亂程度。

好比兩個集合  A有5個類別 每一個類別2個值 則每一個機率是0.2

好比B有兩個類別,每一個類別5個 ,則每一個機率是0.5

顯然0.5大於0.2因此熵大,混亂程度比較大。


信息熵H(X):信息熵是香農在1948年提出來量化信息的信息量的。熵的定義以下

n表明種類,每個類別中,p1表明某個種類的機率*log當前種類的機率,而後將各個類別計算結果累加。

以上例子車禍的信息熵是-(4/9log4/9+5/9log5/9)

條件熵:H(X,Y)相似於條件機率,在知道X的狀況下,Y的不肯定性

 

以上例子在知道溫度的狀況下,求車禍的機率。

hot 是3個,其中兩個沒有車禍,一個車禍,則3/9(2/3log2/3+1/3log1/3)。

mild是2個,其中一個車禍,一個沒有車禍,則2/9(1/2log1/2+1/2log1/2)

cool是4個,其中三個車禍,一個沒有車禍,則4/9(3/4log3/4+1/4log1/4)。

以上相加即爲已知溫度的狀況下,車禍的條件熵。

信息增益:表明的熵的變化程度
                 特徵Y對訓練集D的信息增益g(D,Y)= H(X) - H(X,Y)
以上車禍的信息熵-已知溫度的條件熵就是信息增益。

信息增益便是表示特徵X使得類Y的不肯定性減小的程度。
(分類後的專注性,但願分類後的結果是同類在一塊兒)

信息增益越大,熵的變化程度越大,分的越乾脆,越完全。不肯定性越小。

在構建決策樹的時候就是選擇信息增益最大的屬性做爲分裂條件(ID3),使得在每一個非葉子節點上進行測試時,都能得到最大的類別分類增益,使分類後數據集的熵最小,這樣的處理方法使得樹的平均深度較小,從而有效提升了分類效率。

 

C4.5算法:有時候給個特徵,它分的特別多,可是徹底分對了,好比訓練集裏面的編號
信息增益特別大,都甚至等於根節點了,那確定是不合適的
問題在於行編號的分類數目太多了,分類太多意味着這個特徵自己的熵大,大到都快是整個H(X)了
爲了不這種現象的發生,咱們不是用信息增益自己,而是用信息增益除以這個特徵自己的熵值看除以後的值有多大!這就是信息增益率,若是用信息增益率就是C4.5

 

CART算法:

CART使用的是GINI係數相比ID3和C4.5,CART應用要多一些,既能夠用於分類也能夠用於迴歸。

CART假設決策樹是二叉樹,內部結點特徵的取值爲「是」和「否」,左分支是取值爲「是」的分支,右分支是取值爲「否」的分支。這樣的決策樹等價於遞歸地二分每一個特徵,將輸入空間即特徵空間劃分爲有限個單元,並在這些單元上肯定預測的機率分佈,也就是在輸入給定的條件下輸出的條件機率分佈。

CART算法由如下兩步組成:

  1. 決策樹生成:基於訓練數據集生成決策樹,生成的決策樹要儘可能大;
  2. 決策樹剪枝:用驗證數據集對已生成的樹進行剪枝並選擇最優子樹,這時損失函數最小做爲剪枝的標準。

CART決策樹的生成就是遞歸地構建二叉決策樹的過程。CART決策樹既能夠用於分類也能夠用於迴歸。本文咱們僅討論用於分類的CART。對分類樹而言,CART用Gini係數最小化準則來進行特徵選擇,生成二叉樹。GINI係數實際上是用直線段代替曲線段的近似,GINI係數就是熵的一階近似。

公式以下:

 

 

好比兩個集合  A有5個類別 每一個類別2個值 則每一個機率是0.2

好比B有兩個類別,每一個類別5個 ,則每一個機率是0.5

假設C有一個類別,則基尼係數是0 ,類別越多,基尼係數越接近於1,因此

咱們但願基尼係數越小越好

CART生成算法以下:

輸入:訓練數據集中止計算的條件:
輸出:CART決策樹。

過程:

 

損失函數:

以上構建好分類樹以後,評價函數以下:

(但願它越小越好,相似損失函數了)

 

3、解決過擬合問題方法

 一、背景

葉子節點的個數做爲加權葉子節點的熵乘以加權的加和就是評價函數這就是損失函數,這個損失函數確定是越小越好了

如何評價呢?
用訓練數據來計算損失函數,決策樹不斷生長的時候,看看測試數據損失函數是否是變得越低了,
這就是交互式的作調參的工做,由於咱們可能須要作一些決策樹葉子節點的剪枝,由於並非樹越高越好,由於樹若是很是高的話,可能過擬合了。

二、解決過擬合兩種方法

剪枝

隨機森林

三、解決過擬合方法之剪枝

爲何要剪枝:決策樹過擬合風險很大,理論上能夠徹底分得開數據(想象一下,若是樹足夠龐大,每一個葉子節點不就一個數據了嘛)
剪枝策略:
預剪枝,後剪枝
預剪枝:邊創建決策樹邊進行剪枝的操做(更實用)
後剪枝:當創建完決策樹後來進行剪枝操做

預剪枝(用的多)
邊生成樹的時候邊剪枝,限制深度,葉子節點個數,葉子節點樣本數,信息增益量等樹的高度,每一個葉節點包含的樣本最小個數,每一個葉節點分裂的時候包含樣本最小的個數,每一個葉節點最小的熵值等max_depth min_sample_split min_sample_leaf min_weight_fraction_leaf,max_leaf_nodes max_features,增長min_超參 減少max_超參
後剪枝

 

葉子節點個數越多,損失越大
仍是生成一顆樹後再去剪枝,alpha值給定就行

後剪枝舉例:

 

四、解決過擬合方法之隨機森林

思想Bagging的策略:

從樣本集中重採樣(有可能存在重複)選出n個樣本在全部屬性上,對這n個樣本創建分類器(ID三、C4.五、CART、SVM、Logistic迴歸等)
重複上面兩步m次,產生m個分類器將待預測數據放到這m個分類器上,最後根據這m個分類器的投票結果,決定待預測數據屬於那一類(即少數服從多數的策略)

在Bagging策略的基礎上進行修改後的一種算法
從樣本集中用Bootstrap採樣選出n個樣本;
從全部屬性中隨機選擇K個屬性,選擇出最佳分割屬性做爲節點建立決策樹;
重複以上兩步m次,即創建m棵CART決策樹;
這m個CART造成隨機森林(樣本隨機,屬性隨機),經過投票表決結果決定數據屬於那一類。

當數據集很大的時候,咱們隨機選取數據集的一部分,生成一棵樹,重複上述過程,咱們能夠生成一堆形態萬千的樹,這些樹放在一塊兒就叫森林。

隨機森林之因此隨機是由於兩方面:樣本隨機+屬性隨機

選取過程:

某些特徵的全部行做爲每個樹的輸入數據。

而後把測試數據帶入到每個數中計算結果,少數服從多數,便可求出最終分類。

隨機森林的思考:

在隨機森林的構建過程當中,因爲各棵樹之間是沒有關係的,相對獨立的;在構建
的過程當中,構建第m棵子樹的時候,不會考慮前面的m-1棵樹。所以引出提高的算法,對分錯的樣本加權。

提高是一種機器學習技術,能夠用於迴歸和分類的問題,它每一步產生弱預測模型(如決策樹),並加權累加到總模型中;若是每一步的弱預測模型的生成都是依
據損失函數的梯度方式的,那麼就稱爲梯度提高(Gradient boosting)提高技術的意義:若是一個問題存在弱預測模型,那麼能夠經過提高技術的辦法獲得一個強預測模型。

4、代碼

決策樹:

決策樹的訓練集必須離散化,由於若是不離散化的話,分類節點不少。

 

package com.bjsxt.rf

import org.apache.spark.mllib.tree.DecisionTree
import org.apache.spark.mllib.util.MLUtils
import org.apache.spark.{SparkContext, SparkConf}

object ClassificationDecisionTree {
  val conf = new SparkConf()
  conf.setAppName("analysItem")
  conf.setMaster("local[3]")
  val sc = new SparkContext(conf)

  def main(args: Array[String]): Unit = {
    val data = MLUtils.loadLibSVMFile(sc, "汽車數據樣本.txt")
    // Split the data into training and test sets (30% held out for testing)
    val splits = data.randomSplit(Array(0.7, 0.3))
    val (trainingData, testData) = (splits(0), splits(1))
    //指明類別
    val numClasses=2
    //指定離散變量,未指明的都看成連續變量處理
    //1,2,3,4維度進來就變成了0,1,2,3
    //這裏天氣維度有3類,可是要指明4,這裏是個坑,後面以此類推
    val categoricalFeaturesInfo=Map[Int,Int](0->4,1->4,2->3,3->3)
    //設定評判標準
    val impurity="entropy"
    //樹的最大深度,太深運算量大也沒有必要  剪枝   防止模型的過擬合!!!
    val maxDepth=3
    //設置離散化程度,連續數據須要離散化,分紅32個區間,默認其實就是32,分割的區間保證數量差很少 這裏能夠實現把數據分到0-31這些數中去  這個參數也能夠進行剪枝
    val maxBins=32
    //生成模型
    val model =DecisionTree.trainClassifier(trainingData,numClasses,categoricalFeaturesInfo,impurity,maxDepth,maxBins)
   //測試
   val labelAndPreds = testData.map { point =>
     val prediction = model.predict(point.features)
     (point.label, prediction)
   }
    val testErr = labelAndPreds.filter(r => r._1 != r._2).count().toDouble / testData.count()//錯誤率的統計
    println("Test Error = " + testErr)
    println("Learned classification tree model:\n" + model.toDebugString)

     }
}

 樣本數據:

將第5列數據離散化。

結果:

深度爲3一共15個節點。

 隨機森林:

package com.bjsxt.rf

import org.apache.spark.{SparkContext, SparkConf}
import org.apache.spark.mllib.util.MLUtils
import org.apache.spark.mllib.tree.RandomForest

object ClassificationRandomForest {
  val conf = new SparkConf()
  conf.setAppName("analysItem")
  conf.setMaster("local[3]")
  val sc = new SparkContext(conf)
  def main(args: Array[String]): Unit = {
    //讀取數據
    val data =  MLUtils.loadLibSVMFile(sc,"汽車數據樣本.txt")
    //將樣本按7:3的比例分紅
    val splits = data.randomSplit(Array(0.7, 0.3))
    val (trainingData, testData) = (splits(0), splits(1))
    //分類數
    val numClasses = 2
    // categoricalFeaturesInfo 爲空,意味着全部的特徵爲連續型變量
    val categoricalFeaturesInfo =Map[Int, Int](0->4,1->4,2->3,3->3)
    //樹的個數
    val numTrees = 3 
    //特徵子集採樣策略,auto 表示算法自主選取
    //"auto"根據特徵數量在4箇中進行選擇
    // 1,all 所有特徵 2,sqrt 把特徵數量開根號後隨機選擇的 3,log2 取對數個 4,onethird 三分之一
    val featureSubsetStrategy = "auto"
    //純度計算
    val impurity = "entropy"
    //樹的最大層次
    val maxDepth = 3
    //特徵最大裝箱數,即連續數據離散化的區間
    val maxBins = 32
    //訓練隨機森林分類器,trainClassifier 返回的是 RandomForestModel 對象
    val model = RandomForest.trainClassifier(trainingData, numClasses, categoricalFeaturesInfo,
      numTrees, featureSubsetStrategy, impurity, maxDepth, maxBins)
    //打印模型
    println(model.toDebugString)
    //保存模型
   //model.save(sc,"汽車保險")
    //在測試集上進行測試
    val count = testData.map { point =>
    val prediction = model.predict(point.features)
//    Math.abs(prediction-point.label)
    (prediction,point.label)
     }.filter(r => r._1 != r._2).count()
    println("Test Error = " + count.toDouble/testData.count().toDouble)
  }
}

 

 結果:

根據DEBUGTREE畫圖舉例:

相關文章
相關標籤/搜索