原文:Predicting Loan Credit Risk using Apache Spark Machine Learning Random Forests
做者:Carol McDonald,MapR解決方案架構師
翻譯:KK4SBB
責編:周建丁(zhoujd@csdn.net)javascript
在本文中,我將向你們介紹如何使用Apache Spark的spark.ml庫中的隨機森林算法來對銀行信用貸款的風險作分類預測。Spark的spark.ml庫基於DataFrame,它提供了大量的接口,幫助用戶建立和調優機器學習工做流。結合dataframe使用spark.ml,可以實現模型的智能優化,從而提高模型效果。html
分類算法是一類監督式機器學習算法,它根據已知標籤的樣本(如已經明確交易是否存在欺詐)來預測其它樣本所屬的類別(如是否屬於欺詐性的交易)。分類問題須要一個已經標記過的數據集和預先設計好的特徵,而後基於這些信息來學習給新樣本打標籤。所謂的特徵便是一些「是與否」的問題。標籤就是這些問題的答案。在下面這個例子裏,若是某個動物的行走姿態、游泳姿式和叫聲都像鴨子,那麼就給它打上「鴨子」的標籤。java
咱們來看一個銀行信貸的信用風險例子:git
決策樹是一種基於輸入特徵來預測類別或是標籤的分類模型。決策樹的工做原理是這樣的,它在每一個節點都須要計算特徵在該節點的表達式值,而後基於運算結果選擇一個分支通往下一個節點。下圖展現了一種用來預測信用風險的決策樹模型。每一個決策問題就是模型的一個節點,「是」或者「否」的答案是通往子節點的分支。github
融合學習算法結合了多個機器學習的算法,從而獲得了效果更好的模型。隨機森林是分類和迴歸問題中一類經常使用的融合學習方法。此算法基於訓練數據的不一樣子集構建多棵決策樹,組合成一個新的模型。預測結果是全部決策樹輸出的組合,這樣可以減小波動,而且提升預測的準確度。對於隨機森林分類模型,每棵樹的預測結果都視爲一張投票。得到投票數最多的類別就是預測的類別。算法
咱們使用德國人信用度數據集,它按照一系列特徵屬性將人分爲信用風險好和壞兩類。咱們能夠得到每一個銀行貸款申請者的如下信息:sql
存放德國人信用數據的csv文件格式以下:shell
1,1,18,4,2,1049,1,2,4,2,1,4,2,21,3,1,1,3,1,1,1 1,1,9,4,0,2799,1,3,2,3,1,2,1,36,3,1,2,3,2,1,1 1,2,12,2,9,841,2,4,2,2,1,4,1,23,3,1,1,2,1,1,1
在這個背景下,咱們會構建一個由決策樹組成的隨機森林模型來預測是否守信用的標籤/類別,基於如下特徵:apache
本教程將使用Spark 1.6.1數組
按照教程指示,登陸MapR沙箱,用戶名爲user01,密碼爲mapr。將樣本數據文件複製到你的沙箱主目錄下/user/user01 using scp。(注意,你可能須要先更新Spark的版本)打開spark shell:
$spark-shell --master local[1]
首先,咱們須要引入機器學習相關的包。
import org.apache.spark.ml.classification.RandomForestClassifier import org.apache.spark.ml.evaluation.BinaryClassificationEvaluator import org.apache.spark.ml.feature.StringIndexer import org.apache.spark.ml.feature.VectorAssembler import sqlContext.implicits._ import sqlContext._ import org.apache.spark.ml.tuning.{ ParamGridBuilder, CrossValidator } import org.apache.spark.ml.{ Pipeline, PipelineStage }
咱們用一個Scala的case類來定義Credit的屬性,對應於csv文件中的一行。
// define the Credit Schema case class Credit( creditability: Double, balance: Double, duration: Double, history: Double, purpose: Double, amount: Double, savings: Double, employment: Double, instPercent: Double, sexMarried: Double, guarantors: Double, residenceDuration: Double, assets: Double, age: Double, concCredit: Double, apartment: Double, credits: Double, occupation: Double, dependents: Double, hasPhone: Double, foreign: Double )
下面的函數解析一行數據文件,將值存入Credit類中。類別的索引值減去了1,所以起始索引值爲0.
// function to create a Credit class from an Array of Double def parseCredit(line: Array[Double]): Credit = { Credit( line(0), line(1) - 1, line(2), line(3), line(4) , line(5), line(6) - 1, line(7) - 1, line(8), line(9) - 1, line(10) - 1, line(11) - 1, line(12) - 1, line(13), line(14) - 1, line(15) - 1, line(16) - 1, line(17) - 1, line(18) - 1, line(19) - 1, line(20) - 1 ) } // function to transform an RDD of Strings into an RDD of Double def parseRDD(rdd: RDD[String]): RDD[Array[Double]] = { rdd.map(_.split(",")).map(_.map(_.toDouble)) }
接下去,咱們導入germancredit.csv文件中的數據,存爲一個String類型的RDD。而後咱們對RDD作map操做,將RDD中的每一個字符串通過ParseRDDR函數的映射,轉換爲一個Double類型的數組。緊接着是另外一個map操做,使用ParseCredit函數,將每一個Double類型的RDD轉換爲Credit對象。toDF()函數將Array[[Credit]]類型的RDD轉爲一個Credit類的Dataframe。
// load the data into a RDD val creditDF= parseRDD(sc.textFile("germancredit.csv")).map(parseCredit).toDF().cache() creditDF.registerTempTable("credit") DataFrame的printSchema()函數將各個字段含義以樹狀的形式打印到控制檯輸出。 // Return the schema of this DataFrame creditDF.printSchema root |-- creditability: double (nullable = false) |-- balance: double (nullable = false) |-- duration: double (nullable = false) |-- history: double (nullable = false) |-- purpose: double (nullable = false) |-- amount: double (nullable = false) |-- savings: double (nullable = false) |-- employment: double (nullable = false) |-- instPercent: double (nullable = false) |-- sexMarried: double (nullable = false) |-- guarantors: double (nullable = false) |-- residenceDuration: double (nullable = false) |-- assets: double (nullable = false) |-- age: double (nullable = false) |-- concCredit: double (nullable = false) |-- apartment: double (nullable = false) |-- credits: double (nullable = false) |-- occupation: double (nullable = false) |-- dependents: double (nullable = false) |-- hasPhone: double (nullable = false) |-- foreign: double (nullable = false) // Display the top 20 rows of DataFrame creditDF.show +-------------+-------+--------+-------+-------+------+-------+----------+-----------+----------+----------+-----------------+------+----+----------+---------+-------+----------+----------+--------+-------+ |creditability|balance|duration|history|purpose|amount|savings|employment|instPercent|sexMarried|guarantors|residenceDuration|assets| age|concCredit|apartment|credits|occupation|dependents|hasPhone|foreign| +-------------+-------+--------+-------+-------+------+-------+----------+-----------+----------+----------+-----------------+------+----+----------+---------+-------+----------+----------+--------+-------+ | 1.0| 0.0| 18.0| 4.0| 2.0|1049.0| 0.0| 1.0| 4.0| 1.0| 0.0| 3.0| 1.0|21.0| 2.0| 0.0| 0.0| 2.0| 0.0| 0.0| 0.0| | 1.0| 0.0| 9.0| 4.0| 0.0|2799.0| 0.0| 2.0| 2.0| 2.0| 0.0| 1.0| 0.0|36.0| 2.0| 0.0| 1.0| 2.0| 1.0| 0.0| 0.0| | 1.0| 1.0| 12.0| 2.0| 9.0| 841.0| 1.0| 3.0| 2.0| 1.0| 0.0| 3.0| 0.0|23.0| 2.0| 0.0| 0.0| 1.0| 0.0| 0.0| 0.0| | 1.0| 0.0| 12.0| 4.0| 0.0|2122.0| 0.0| 2.0| 3.0| 2.0| 0.0| 1.0| 0.0|39.0| 2.0| 0.0| 1.0| 1.0| 1.0| 0.0| 1.0| | 1.0| 0.0| 12.0| 4.0| 0.0|2171.0| 0.0| 2.0| 4.0| 2.0| 0.0| 3.0| 1.0|38.0| 0.0| 1.0| 1.0| 1.0| 0.0| 0.0| 1.0| | 1.0| 0.0| 10.0| 4.0| 0.0|2241.0| 0.0| 1.0| 1.0| 2.0| 0.0| 2.0| 0.0|48.0| 2.0| 0.0| 1.0| 1.0| 1.0| 0.0| 1.0| | 1.0| 0.0| 8.0| 4.0| 0.0|3398.0| 0.0| 3.0| 1.0| 2.0| 0.0| 3.0| 0.0|39.0| 2.0| 1.0| 1.0| 1.0| 0.0| 0.0| 1.0| | 1.0| 0.0| 6.0| 4.0| 0.0|1361.0| 0.0| 1.0| 2.0| 2.0| 0.0| 3.0| 0.0|40.0| 2.0| 1.0| 0.0| 1.0| 1.0| 0.0| 1.0| | 1.0| 3.0| 18.0| 4.0| 3.0|1098.0| 0.0| 0.0| 4.0| 1.0| 0.0| 3.0| 2.0|65.0| 2.0| 1.0| 1.0| 0.0| 0.0| 0.0| 0.0| | 1.0| 1.0| 24.0| 2.0|