spark機器學習從0到1之spark機器算法從入門到實戰(十八)


第1章 機器學習概述

1.1 機器學習是啥?

  機器學習(Machine Learning, ML)是一門多領域交叉學科,涉及概率論、統計學、逼近論、凸分析、算法復雜度理論等多門學科。專門研究計算機怎樣模擬或實現人類的學習行為,以獲取新的知識或技能,重新組織已有的知識結構使之不斷改善自身的性能。
  即通過算法使計算機能夠模擬人類的判別能力

1.2 機器學習能干啥?

1.3 機器學習有啥?

1.4 機器學習怎么用?

第2章 機器學習的相關概念

2.1 數據集

  一組數據的集合被稱作數據集,用於模型訓練的數據集叫訓練集,用於測試的數據集叫測試集。一個數據集包含多條數據,一條數據包含多個屬性。
  

2.2 泛化能力

  是指機器學習通過訓練集進行模型的訓練之后對未知的輸入的准確判斷能力。

2.3 過擬合和欠擬合

  過擬合是指在利用訓練數據進行模型訓練的時候,模型過多的依賴訓練數據中過多的特征屬性。欠擬合是指沒有通過訓練集達到識別的能力。
  

2.4 維度、特征

  對於西瓜數據集,色澤、根蒂、敲聲就是維度,也叫特征值。
  

2.5 模型

  模型就是復雜的數學相關函數,只是該函數具有很多的未知的參數,通過訓練集訓練來確定模型中的參數,生成的已知參數的函數就是模型。就是一種映射

2.6 學習

  學習就是根據業務數據構建模型的過程
  機器學習分為有監督學習和無監督學習,有監督學習是指訓練集中有明確的標記,如下數據集:各種特征的西瓜是不是好瓜,有明確的標記。分類就是典型的有監督學習
  無監督學習是指訓練集中沒有明確的標記,聚類就是典型的無監督學習

第3章 算法常用指標

3.1 精確率和召回率

  考慮一個二分問題,即將實例分成正類(positive)或負類(negative)。對一個二分問題來說,會出現四種情況。如果一個實例是正類並且也被預測成正類,即為真正類(True positive),如果實例是負類被預測成正類,稱之為假正類(False positive)。相應地,如果實例是負類被預測成負類,稱之為真負類(True negative),正類被預測成負類則為假負類(false negative)。
  TP:正確肯定的數目
  FN:漏報,沒有正確找到的匹配的數目
  FP:誤報,給出的匹配是不正確的
  TN:正確拒絕的非匹配對數
  列聯表如下表所示,1 代表正類,0 代表負類:
  
  
  精確率(正確率)和召回率是廣泛用於信息檢索和統計學分類領域的兩個度量值,用來評價結果的質量。其中精度是檢索出相關文檔數與檢索出的文檔總數的比率,衡量的是檢索系統的查准率;召回率是指檢索出的相關文檔數和文檔庫中所有的相關文檔數的比率,衡量的是檢索系統的查全率。
  一般來說,Precision 就是檢索出來的條目(比如:文檔、網頁等)有多少是准確的,Recall 就是所有准確的條目有多少被檢索出來了,兩者的定義分別如下:
  Precision = 提取出的正確信息條數 / 提取出的信息條數
  Recall = 提取出的正確信息條數 / 樣本中的信息條數
  為了能夠評價不同算法的優劣,在 Precision 和 Recall 的基礎上提出了 F1 值的概念,來對 Precision 和 Recall 進行整體評價。F1 的定義如下:
  F1值 = 正確率 * 召回率 * 2 / (正確率 + 召回率)
  

不妨舉這樣一個例子:

某池塘有 1400 條鯉魚,300 只蝦,300 只鱉。現在以捕鯉魚為目的。撒一大網,逮着了 700 條鯉魚,200 只蝦,100 只鱉。那么,這些指標分別如下:
  正確率 = 700 / (700 + 200 + 100) = 70%
  召回率 = 700 / 1400 = 50%
  F1值 = 70% * 50% * 2 / (70% + 50%) = 58.3%
不妨看看如果把池子里的所有的鯉魚、蝦和鱉都一網打盡,這些指標又有何變化:
  正確率 = 1400 / (1400 + 300 + 300) = 70%
  召回率 = 1400 / 1400 = 100%
  F1值 = 70% * 100% * 2 / (70% + 100%) = 82.35%

 

  由此可見,正確率是評估捕獲的成果中目標成果所占得比例;召回率,顧名思義,就是從關注領域中,召回目標類別的比例;而 F1 值,則是綜合這二者指標的評估指標,用於綜合反映整體的指標。
  當然希望檢索結果 Precision 越高越好,同時 Recall 也越高越好,但事實上這兩者在某些情況下有矛盾的。比如極端情況下,我們只搜索出了一個結果,且是准確的,那么 Precision 就是 100%,但是 Recall 就很低;而如果我們把所有結果都返回,那么比如 Recall 是 100%,但是 Precision 就會很低。因此在不同的場合中需要自己判斷希望 Precision 比較高或是 Recall 比較高。如果是做實驗研究,可以繪制 Precision-Recall 曲線來幫助分析。

3.2 TPR、FPR & TNR

引入兩個新名詞。
其一是真正類率(true positive rate, TPR),計算公式為:
  TPR = TP / (TP + FN)
刻畫的是分類器所識別出的正實例占所有正實例的比例。
另一個是負正類率(false positive rate, FPR),計算公式為:
  FPR = FP / (FP + TN)
計算的是分類器錯認為正類的負實例占所有負實例的比例。
還有一個真負類率(True Negative Rate, TNR),也稱為 specificity,計算公式為:
  TNR = TN /(FP + TN) = 1 - FPR

3.3 綜合評價指標 F-measure

  Precision 和 Recall 指標有時候會出現的矛盾的情況,這樣就需要綜合考慮他們,最常見的方法就是 F-Measure(又稱 為F-Score)。
  F-Measure 是 Precision 和 Recall 加權調和平均:
  
  當參數 α=1 時,就是最常見的 F1。因此,F1 綜合了 P 和 R 的結果,當 F1 較高時則能說明試驗方法比較有效。

3.4 其他一些評估參數

3.5 ROC 曲線、AUC

3.5.1為什么引入 ROC 曲線?

  原因一:在一個二分類模型中,對於所得到的連續結果,假設已確定一個閥值,比如說 0.6,大於這個值的實例划歸為正類,小於這個值則划到負類中。如果減小閥值,減到 0.5,固然能識別出更多的正類,也就是提高了識別出的正例占所有正例 的比類,即 TPR,但同時也將更多的負實例當作了正實例,即提高了 FPR。為了形象化這一變化,引入 ROC,ROC 曲線可以用於評價一個分類器
  原因二:在類不平衡的情況下,如正樣本 90 個,負樣本 10 個,直接把所有樣本分類為正樣本,得到識別率為 90%。但這顯然是沒有意義的。單純根據 Precision 和 Recall 來衡量算法的優劣已經不能表征這種病態問題。

3.5.2什么是 ROC 曲線?

  ROC(Receiver Operating Characteristic)翻譯為 “接受者操作特性曲線”。曲線由兩個變量 1-specificity 和 Sensitivity 繪制。1-specificity=FPR,即負正類率。Sensitivity 即是真正類率,TPR(True positive rate),反映了正類覆蓋程度。這個組合以 1-specificity 對 sensitivity,即是以代價 (costs) 對收益 (benefits)。
  此外,ROC 曲線還可以用來計算 “均值平均精度”(mean average precision),這是當你通過改變閾值來選擇最好的結果時所得到的平均精度(PPV)。
  為了更好地理解 ROC 曲線,我們使用具體的實例來說明:
  如在醫學診斷中,判斷有病的樣本。那么盡量把有病的揪出來是主要任務,也就是第一個指標 TPR,要越高越好。而把沒病的樣本誤診為有病的,也就是第二個指標 FPR,要越低越好。
  不難發現,這兩個指標之間是相互制約的。如果某個醫生對於有病的症狀比較敏感,稍微的小症狀都判斷為有病,那么他的第一個指標應該會很高,但是第二個指標也就相應地變高。最極端的情況下,他把所有的樣本都看做有病,那么第一個指標達到1,第二個指標也為1。
  我們以 FPR 為橫軸,TPR 為縱軸,得到如下 ROC 空間。
  我們可以看出,左上角的點 (TPR=1,FPR=0) 為完美分類,也就是這個醫生醫術高明,診斷全對。點 A(TPR>FPR),醫生A的判斷大體是正確的。中線上的點 B(TPR=FPR),也就是醫生B全都是蒙的,蒙對一半,蒙錯一半。下半平面的點 C(TPR<FPR),這個醫生說你有病,那么你很可能沒有病,醫生C的話我們要反着聽,為真庸醫。上圖中一個閾值,得到一個點。現在我們需要一個獨立於閾值的評價指標來衡量這個醫生的醫術如何,也就是遍歷所有的閾值,得到 ROC 曲線。
  還是一開始的那幅圖,假設如下就是某個醫生的診斷統計圖,直線代表閾值。我們遍歷所有的閾值,能夠在 ROC 平面上得到如下的 ROC 曲線。
  
  曲線距離左上角越近,證明分類器效果越好。
  
  如上,是三條 ROC 曲線,在 0.23 處取一條直線。那么,在同樣的低 FPR=0.23 的情況下,紅色分類器得到更高的 PTR。也就表明,ROC 越往上,分類器效果越好。我們用一個標量值 AUC 來量化它。

3.5.3什么是 AUC?

  AUC 值為 ROC 曲線所覆蓋的區域面積,顯然,AUC 越大,分類器分類效果越好。
  AUC = 1,是完美分類器,采用這個預測模型時,不管設定什么閾值都能得出完美預測。絕大多數預測的場合,不存在完美分類器。
  0.5 < AUC < 1,優於隨機猜測。這個分類器(模型)妥善設定閾值的話,能有預測價值。
  AUC = 0.5,跟隨機猜測一樣(例:丟銅板),模型沒有預測價值。
  AUC < 0.5,比隨機猜測還差;但只要總是反預測而行,就優於隨機猜測。
  AUC 的物理意義:假設分類器的輸出是樣本屬於正類的 socre(置信度),則 AUC 的物理意義為,任取一對(正、負)樣本,正樣本的 score 大於負樣本的 score 的概率。

3.5.4 怎樣計算 AUC?

  第一種方法:AUC 為 ROC 曲線下的面積,那我們直接計算面積可得。面積為一個個小的梯形面積之和。計算的精度與閾值的精度有關。
  第二種方法:根據 AUC 的物理意義,我們計算正樣本 score 大於負樣本的 score 的概率。取 N*M(N為正樣本數,M為負樣本數)個二元組,比較 score,最后得到 AUC。時間復雜度為 O(N*M)
  第三種方法:與第二種方法相似,直接計算正樣本 score 大於負樣本的概率。我們首先把所有樣本按照 score 排序,依次用 rank 表示他們,如最大 score 的樣本,rank=n(n=N+M),其次為 n-1。那么對於正樣本中 rank 最大的樣本 rank_max,有 M-1 個其他正樣本比他 score 小,那么就有(rank_max-1)-(M-1)個負樣本比他 score 小。其次為 (rank_second-1)-(M-2)。最后我們得到正樣本大於負樣本的概率,時間復雜度為 O(N+M)
  MSE:Mean Squared Error
  均方誤差:是指參數估計值與參數真值之差平方的期望值。
  MSE 可以評價數據的變化程度,MSE 的值越小,說明預測模型描述實驗數據具有更好的精確度。
  
  RMSE
  均方誤差:均方根誤差是均方誤差的算術平方根。
  
  MAE:Mean Absolute Error
  平均絕對誤差:是絕對誤差的平均值。
  平均絕對誤差能更好地反映預測值誤差的實際情況。
  
  fi 表示預測值,yi 表示真實值。
  SD:standard Deviation
  標准差:標准差是方差的算術平方根。標准差能反映一個數據集的離散程度。平均數相同的兩組組數據,標准差未必相同。
  

3.6 Spark MLlib 是啥?

機器學習之常見應用框架

Spark MLlib

第4章 凸優化算法

不嚴格的說,凸優化就是在標准優化問題的范疇內,要求目標函數和約束函數是凸函數的一類優化問題。

注意:中國大陸數學界某些機構關於函數凹凸性定義和國外的定義是相反的。Convex Function 在某些中國大陸的數學書中指凹函數。Concave Function 指凸函數。但在中國大陸涉及經濟學的很多書中,凹凸性的提法和其他國家的提法是一致的,也就是和數學教材是反的。舉個例子,同濟大學高等數學教材對函數的凹凸性定義與本條目相反,本條目的凹凸性是指其上方圖是凹集或凸集,而同濟大學高等數學教材則是指其下方圖是凹集或凸集,兩者定義正好相反。

4.1 梯度下降

4.2 牛頓法

4.3 擬牛頓法

4.4 BFGS 算法

第5章 L1、L2 正則化

5.1 從經驗風險最小化到結構經驗最小化

5.2 范數與正則項

5.3 貝葉斯先驗

第6章 線性回歸算法

6.1 數學模型

  線性回歸是利用被稱為線性回歸方程的最小平方函數對一個或者多個自變量和因變量之間關系進行建模的一種回歸分析。這種函數式一個或者多個被稱為回歸系數的模型參數的線性組合。
  在統計學中,線性回歸(Linear Regression) 是利用稱為線性回歸方程的最小平方函數對一個或多個自變量和因變量之間關系進行建模的一種回歸分析。這種函數是一個或多個稱為回歸系數的模型參數的線性組合。
  回歸分析中,只包括一個自變量和一個因變量,且二者的關系可用一條直線近似表示,這種回歸分析稱為一元線性回歸分析。如果回歸分析中包括兩個或兩個以上的自變量,且因變量和自變量之間是線性關系,則稱為多元線性回歸分析。

6.2 線性回歸的應用

  通過大量樣本的試驗學習到線性函數,然后根據新的樣本的特征數據,預測結果。

6.2 Spark MLlib 實現

示例代碼:

package com.atguigu.mllib

import org.apache.log4j.{Level, Logger}
import org.apache.spark.mllib.regression.{LinearRegressionModel, LinearRegressionWithSGD}
import org.apache.spark.mllib.util.MLUtils
import org.apache.spark.{SparkConf, SparkContext}

object LinearRegression { def main(args: Array[String]): Unit = { // 屏蔽日志 Logger.getLogger("org.apache.spark").setLevel(Level.ERROR) Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF) // 創建 SparkContext val conf = new SparkConf().setMaster("local[4]").setAppName("LinearRegression") val sc = new SparkContext(conf) // 加載數據樣本 val path = "D:\\learn\\JetBrains\\workspace_idea\\spark\\doc\\data.txt"; // 通過提供的工具類加載樣本文件 val data = MLUtils.loadLibSVMFile(sc, path).cache() // 或者通過 RDD 轉換加載 /* val data = sc.textFile(path).map { line => val parts = line.split(' ') LabeledPoint(parts(0).toDouble, Vectors.dense(parts.tail.map(_.split(":")(1).toDouble))) }.cache() */ // 迭代次數 val numIterations = 100 // 梯度下降步長 val stepSize = 0.00000001 // 訓練模型 val model = LinearRegressionWithSGD.train(data, numIterations, stepSize) // 模型評估 val valuesAndPreds = data.map { point => // 根據模型預測 Label 值 val prediction = model.predict(point.features) println(s"【真實值】:${point.label} ;【預測值】:${prediction}") (point.label, prediction) } // 求均方誤差 val MSE = valuesAndPreds.map { case (v, p) => math.pow((v - p), 2) }.mean() println("訓練模型的均方誤差為 = " + MSE) // 保存模型 model.save(sc, "target/tmp/scalaLinearRegressionWithSGDModel") // 重新加載模型 val sameModel = LinearRegressionModel.load(sc, "target/tmp/scalaLinearRegressionWithSGDModel") sc.stop() } }

 

輸出結果如下:

【真實值】:-9.490009878824548      ;【預測值】:7.708618803157486E-9
【真實值】:-1.1838791995691869      ;【預測值】:1.1953486679306154E-8 【真實值】:0.2577820163584905 ;【預測值】:-2.460347544748461E-9 【真實值】:-1.5856680515554806 ;【預測值】:1.43032697303707E-8 【真實值】:-13.039928064104615 ;【預測值】:-2.909264331661566E-10 【真實值】:-4.438869807456516 ;【預測值】:-4.3817348405900043E-10 【真實值】:-17.428674570939506 ;【預測值】:7.864237801670372E-9 【真實值】:-19.782762789614537 ;【預測值】:2.749919462104237E-9 ...... ...... 訓練模型的均方誤差為 = 106.31223022762704

 

第7章 FPGrowth 關聯規則算法

7.1算法思想

  FPGrowth 算法通過構造一個 FPTree 樹結構來壓縮數據記錄,使得挖掘頻繁項集只需要掃描兩次數據記錄,而且該算法不需要生成候選集合,所以效率會比較高。如何從購物籃里面發現 尿布+啤酒 的最佳組合。 >   我們以以下數據集為例:
  
  注意:牛奶、面包叫做項,{ 牛奶、面包 } 叫做項集。項集出現的次數叫做支持度。T* 表示用戶每次的購物清單。
  FPGrowth挖掘過程如下圖所示:
  

7.2 Spark MLlib 實現

示例代碼如下:

package com.atguigu.mllib

import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.mllib.fpm.FPGrowth

object FPGrowth extends App { // 屏蔽日志 Logger.getLogger("org.apache.spark").setLevel(Level.ERROR) Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF) // 創建 SparkContext val conf = new SparkConf().setMaster("local[4]").setAppName("FPGrowth") val sc = new SparkContext(conf) // 加載數據樣本 val path = "D:\\learn\\JetBrains\\workspace_idea\\spark\\doc\\fpgrowth.txt"; // 創建交易樣本 val transactions = sc.textFile(path).map(_.split(" ")).cache() println(s"交易樣本的數量為: ${transactions.count()}") // 最小支持度 [0,1] val minSupport = 0.4 // 計算的並行度 val numPartition = 2 // 訓練模型 val model = new FPGrowth() .setMinSupport(minSupport) .setNumPartitions(numPartition) .run(transactions) // 打印模型結果 println(s"經常一起購買的物品集的數量為: ${model.freqItemsets.count()}") model.freqItemsets.collect().foreach { itemset => println(itemset.items.mkString("[", ",", "]") + ", " + itemset.freq) } sc.stop() }

 

輸出結果如下:

交易樣本的數量為: 6
經常一起購買的物品集的數量為: 18 [t], 3 [t,x], 3 [t,x,z], 3 [t,z], 3 [s], 3 [s,x], 3 [z], 5 [y], 3 [y,t], 3 [y,t,x], 3 [y,t,x,z], 3 [y,t,z], 3 [y,x], 3 [y,x,z], 3 [y,z], 3 [x], 4 [x,z], 3 [r], 3

 

第8章 協同過濾推薦算法

8.1 算法思想

  比如你想看一個電影,但是不知道具體看哪一部,你會怎么做?有兩種辦法,一種是問問周圍興趣相似的朋友,看看他們最近有什么好的電影推薦。另外一種是看看電影的相似程度,比如都喜歡看僵屍片,那就會找電影名帶有僵屍、喪屍之類的電影。
  協同過濾算法就是基於上面的思想,主要包含基於用戶的協同過濾推薦算法以及基於物品的協同過濾推薦算法。
  實現協同過濾,一般需要幾個步驟:
  1、收集用戶偏好。
  2、找到相似的用戶或者物品。
  3、計算推薦。

  協同過濾算法主要用於推薦系統,推薦系統是信息過載所采用的措施,面對海量的數據信息,從中快速推薦出符合用戶特點的物品。一些人的“選擇恐懼症”、沒有明確需求的人。
  • 解決如何從大量信息中找到自己感興趣的信息。
  • 解決如何讓自己生產的信息脫穎而出,受到大眾的喜愛。
  

8.2 相似性度量

8.3 Spark MLlib 實現

推薦數據的准備

協同過濾推薦架構

示例代碼如下:

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// scalastyle:off println
package com.spark.mllib

import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkConf, SparkContext}

import org.apache.spark.mllib.recommendation.ALS
import org.apache.spark.mllib.recommendation.MatrixFactorizationModel
import org.apache.spark.mllib.recommendation.Rating

object Recommendation { def main(args: Array[String]): Unit = { // 屏蔽日志 Logger.getLogger("org.apache.spark").setLevel(Level.ERROR) Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF) // 創建 SparkContext val conf = new SparkConf().setMaster("local[4]").setAppName("CollaborativeFiltering") val sc = new SparkContext(conf) // 加載數據 val path = "D:\\learn\\JetBrains\\workspace_idea\\spark\\doc\\test.data" val data = sc.textFile(path) val ratings = data.map(_.split(',') match { case Array(user, item, rate) => Rating(user.toInt, item.toInt, rate.toDouble) }) // 訓練模型 val rank = 50 val numIterations = 10 val model = ALS.train(ratings, rank, numIterations, 0.01) // 准備用戶數據 val usersProducts = ratings.map { case Rating(user, product, rate) => (user, product) } // 生成推薦結果 val predictions = model.predict(usersProducts).map { case Rating(user, product, rate) => ((user, product), rate) } // 對比結果 val ratesAndPreds = ratings.map { case Rating(user, product, rate) => ((user, product), rate) }.join(predictions) // 生成均方誤差 val MSE = ratesAndPreds.map { case ((user, product), (r1, r2)) => println(s"【用戶】:${user} 【物品】:${product} 【真實值】:${r1} 【預測值】:${r2}") val err = (r1 - r2) err * err }.mean() println("預測的均方誤差為 = " + MSE) // 保存模型 model.save(sc, "target/tmp/myCollaborativeFilter") // 加載模型 val sameModel = MatrixFactorizationModel.load(sc, "target/tmp/myCollaborativeFilter") sc.stop() } }

 

輸出結果如下:

【用戶】:4  【物品】:4  【真實值】:5.0  【預測值】:4.996434384228974
【用戶】:2  【物品】:1  【真實值】:5.0  【預測值】:4.9967879248395715 【用戶】:1 【物品】:1 【真實值】:5.0 【預測值】:4.9967879248395715 【用戶】:4 【物品】:2 【真實值】:5.0 【預測值】:4.996434384228974 【用戶】:1 【物品】:4 【真實值】:1.0 【預測值】:1.0001174801070112 【用戶】:4 【物品】:1 【真實值】:1.0 【預測值】:1.0001881676270354 【用戶】:2 【物品】:2 【真實值】:1.0 【預測值】:1.0001174801070112 【用戶】:3 【物品】:1 【真實值】:1.0 【預測值】:1.0001881676270354 【用戶】:2 【物品】:4 【真實值】:1.0 【預測值】:1.0001174801070112 【用戶】:3 【物品】:4 【真實值】:5.0 【預測值】:4.996434384228974 【用戶】:2 【物品】:3 【真實值】:5.0 【預測值】:4.9967879248395715 【用戶】:3 【物品】:2 【真實值】:5.0 【預測值】:4.996434384228974 【用戶】:1 【物品】:2 【真實值】:1.0 【預測值】:1.0001174801070112 【用戶】:3 【物品】:3 【真實值】:1.0 【預測值】:1.0001881676270354 【用戶】:4 【物品】:3 【真實值】:1.0 【預測值】:1.0001881676270354 【用戶】:1 【物品】:3 【真實值】:5.0 【預測值】:4.9967879248395715 預測的均方誤差為 = 5.7700628235600924E-6

 

第9章 決策樹

9.1 算法思想

  決策樹(Decision Tree)是一種基本的分類與回歸方法。決策樹模型呈樹形結構,在分類問題中,表示基於特征對實例進行分類的過程。它可以認為是 if-then 規則的集合,也可以認為是定義在特征空間與類空間上的條件概率分布。相比朴素貝葉斯分類,決策樹的優勢在於構造過程不需要任何領域知識或參數設置,因此在實際應用中,對於探測式的知識發現,決策樹更加適用。
  分類決策樹模型是一種描述對實例進行分類的樹形結構。決策樹由結點和有向邊組成。結點有兩種類型:內部節點和葉節點,內部節點表示一個特征或屬性,葉節點表示一個類。
  分類的時候,從根節點開始,對實例的某一個特征進行測試,根據測試結果,將實例分配到其子結點;此時,每一個子結點對應着該特征的一個取值。如此遞歸向下移動,直至達到葉結點,最后將實例分配到葉結點的類中。
  舉一個通俗的例子,各位立志於脫單的單身男女在找對象的時候就已經完完全全使用了決策樹的思想。假設一位母親在給女兒介紹對象時,有這么一段對話:
  母親:給你介紹個對象。
  女兒:年紀多大了?
  母親:26。
  女兒:長的帥不帥?
  母親:挺帥的。
  女兒:收入高不?
  母親:不算很高,中等情況。
  女兒:是公務員不?
  母親:是,在稅務局上班呢。
  女兒:那好,我去見見。
  這個女生的決策過程就是典型的分類決策樹。相當於對年齡、外貌、收入和是否公務員等特征將男人分為兩個類別:見或者不見。假設這個女生的決策邏輯如下:
  
  上圖完整表達了這個女孩決定是否見一個約會對象的策略,其中綠色結點(內部結點)表示判斷條件,橙色結點(葉結點)表示決策結果,箭頭表示在一個判斷條件在不同情況下的決策路徑,圖中紅色箭頭表示了上面例子中女孩的決策過程。這幅圖基本可以算是一棵決策樹,說它 “基本可以算” 是因為圖中的判定條件沒有量化,如收入高中低等等,還不能算是嚴格意義上的決策樹,如果將所有條件量化,則就變成真正的決策樹了。

9.2 決策樹模型的兩種解釋

  分類決策樹模型是一種描述對實例進行分類的樹形結構。決策樹由結點和有向邊組成。結點有兩種類型:內部結點和葉節點。內部結點表示一個特征或屬性,葉節點表示一個類。

9.2.1 決策樹與 if-then 規則

  可以將決策樹看成一個 if-then 規則的集合。即由決策樹的根結點到葉節點的每一條路徑構建一條規則;路徑上內部結點的特征對應着規則的條件,而葉結點的類對應着規則的結論。
  決策樹的路徑或其對應的 if-then 規則集合的重要性質:互斥且完備(每一個實例都被一條路徑或一條規則所覆蓋,且只被一條路徑或一條規則所覆蓋,這里的覆蓋是指實例的特征與路徑上的特征一致或實例滿足規則的條件)

9.2.2 決策樹與條件概率分布

  決策樹還表示給定特征條件下類的條件概率分布,它定義在特征空間的一個划分。將特征空間划分為互不相交的單元,並在每個單元定義一個類的概率分布就構成了一個條件概率分布。決策樹的每一條路徑對應於划分中的一個單元。
  假設 X 為表示特征的隨機變量,Y 為表示類的隨機變量,那么這個條件概率分布可以表示為 P(X|Y),各葉結點上的條件概率往往偏向於某一個類,即屬於某一類的概率越大。決策樹分類時將該結點的實例強行分到條件概率大的那一類去。

9.3 特征選擇

9.4 Spark MLlib 實現

示例代碼如下:

package com.atguigu.mllib

import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.mllib.tree.DecisionTree
import org.apache.spark.mllib.tree.model.DecisionTreeModel
import org.apache.spark.mllib.util.MLUtils


object DecisionTreeApp extends App { // 屏蔽日志 Logger.getLogger("org.apache.spark").setLevel(Level.ERROR) Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF) // 創建 SparkContext val conf = new SparkConf().setMaster("local[4]").setAppName("DecisionTree") val sc = new SparkContext(conf) val path = "D:\\learn\\JetBrains\\workspace_idea\\spark\\sparkmllib_decision_tree\\src\\main\\resources\\data.txt" // 加載數據文件 val data = MLUtils.loadLibSVMFile(sc, path) // 將數據集切分為 70% 的訓練數據集和 30% 的測試數據集 val splits = data.randomSplit(Array(0.7, 0.3)) val (trainingData, testData) = (splits(0), splits(1)) // 訓練決策樹模型 // Empty categoricalFeaturesInfo indicates all features are continuous. val numClasses = 2 val categoricalFeaturesInfo = Map[Int, Int]() val impurity = "gini" val maxDepth = 5 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("分類錯誤度 = " + testErr) println("訓練的決策樹模型:\n" + model.toDebugString) // 保存決策樹模型 model.save(sc, "target/tmp/myDecisionTreeClassificationModel") // 重新讀取決策樹模型 val sameModel = DecisionTreeModel.load(sc, "target/tmp/myDecisionTreeClassificationModel") sc.stop() }

 

輸出結果如下:

分類錯誤度 = 0.06896551724137931
訓練的決策樹模型:
DecisionTreeModel classifier of depth 2 with 5 nodes If (feature 406 <= 20.0) If (feature 99 <= 0.0) Predict: 0.0 Else (feature 99 > 0.0) Predict: 1.0 Else (feature 406 > 20.0) Predict: 1.0

 

第10章 隨機森林算法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM