1. 程式人生 > >spark廈大-----邏輯斯蒂迴歸分類器--spark.mllib

spark廈大-----邏輯斯蒂迴歸分類器--spark.mllib

來源:http://mocom.xmu.edu.cn/article/show/58578f482b2730e00d70f9fc/0/1

方法簡介

​ 邏輯斯蒂迴歸(logistic regression)是統計學習中的經典分類方法,屬於對數線性模型。logistic迴歸的因變數可以是二分類的,也可以是多分類的。

基本原理

logistic分佈

​ 設X是連續隨機變數,X服從logistic分佈是指X具有下列分佈函式和密度函式:

F(x)=P(xx)=11+e(xμ)/γF(x)=P(x≤x)=11+e−(x−μ)/γ

f(x)=F(x)=e(xμ)/γγ(1+e(xμ)/γ)2f(x)=F′(x)=e−(x−μ)/γγ(1+e−(x−μ)/γ)2

​ 其中,μμ為位置引數,γγ為形狀引數。

f(x)f(x)F(x)F(x)影象如下,其中分佈函式是以(μ,12)(μ,12)為中心對陣,γγ越小曲線變化越快。

二項logistic迴歸模型:

​ 二項logistic迴歸模型如下:

P(Y=1|x)=exp(wx+b)1+exp(wx+b)P(Y=1|x)=exp(w⋅x+b)1+exp(w⋅x+b)

P(Y=0|x)=11+exp(wx+b)P(Y=0|x)=11+exp(w⋅x+b)

​ 其中,xRnx∈Rn是輸入,Y0,1Y∈0,1是輸出,w稱為權值向量,b稱為偏置,wxw⋅x為w和x的內積。

引數估計

​ 假設:

P(Y=1|x)=π(x),P(Y=0|x)=1π(x)P(Y=1|x)=π(x),P(Y=0|x)=1−π(x)

​ 則採用“極大似然法”來估計w和b。似然函式為:

Ni=1[π(xi)]yi[1π(xi)]1yi∏i=1N[π(xi)]yi[1−π(xi)]1−yi

​ 為方便求解,對其“對數似然”進行估計:

L(w)=Ni=1[yilogπ(xi)+(1yi)log(1π(xi))]L(w)=∑i=1N[yilog⁡π(xi)+(1−yi)log⁡(1−π(xi))]

​ 從而對L(w)L(w)求極大值,得到ww的估計值。求極值的方法可以是梯度下降法,梯度上升法等。

示例程式碼

1. 匯入需要的包:

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.mllib.classification.{LogisticRegressionWithLBFGS, LogisticRegressionModel}
import org.apache.spark.mllib.evaluation.MulticlassMetrics
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.mllib.linalg.{Vectors,Vector}

2. 讀取資料:

​ 首先,讀取文字檔案;然後,通過map將每行的資料用“,”隔開,在我們的資料集中,每行被分成了5部分,前4部分是鳶尾花的4個特徵,最後一部分是鳶尾花的分類。把這裡我們用LabeledPoint來儲存標籤列和特徵列。

LabeledPoint在監督學習中常用來儲存標籤和特徵,其中要求標籤的型別是double,特徵的型別是Vector。這裡,先把鶯尾花的分類進行變換,"Iris-setosa"對應分類0,"Iris-versicolor"對應分類1,其餘對應分類2;然後獲取鶯尾花的4個特徵,儲存在Vector中。

scala> val data = sc.textFile("G:/spark/iris.data")
data: org.apache.spark.rdd.RDD[String] = G:/spark/iris.data MapPartitionsRDD[1]
at textFile at :28

scala>     val parsedData = data.map { line =>
     |     val parts = line.split(',')
     |     LabeledPoint(if(parts(4)=="Iris-setosa") 0.toDouble else if (parts(4)
=="Iris-versicolor") 1.toDouble else
     |       2.toDouble, Vectors.dense(parts(0).toDouble,parts(1).toDouble,parts
(2).toDouble,parts(3).toDouble))
     |     }
parsedData: org.apache.spark.rdd.RDD[org.apache.spark.mllib.regression.LabeledPo
int] = MapPartitionsRDD[2] at map at :30

​ 然後,把資料列印看一下:

scala> parsedData.foreach { x => println(x) }
(1.0,[6.0,2.9,4.5,1.5])
(0.0,[5.1,3.5,1.4,0.2])
(1.0,[5.7,2.6,3.5,1.0])
(0.0,[4.9,3.0,1.4,0.2])
(1.0,[5.5,2.4,3.8,1.1])
(0.0,[4.7,3.2,1.3,0.2])
(1.0,[5.5,2.4,3.7,1.0])
(0.0,[4.6,3.1,1.5,0.2])
... ...

3. 構建模型

​ 接下來,首先進行資料集的劃分,這裡劃分60%的訓練集和40%的測試集:

scala> val splits = parsedData.randomSplit(Array(0.6, 0.4), seed = 11L)
splits: Array[org.apache.spark.rdd.RDD[org.apache.spark.mllib.regression.Labeled
Point]] = Array(MapPartitionsRDD[3] at randomSplit at :32, MapPartition
sRDD[4] at randomSplit at :32)

scala> val training = splits(0).cache()
training: org.apache.spark.rdd.RDD[org.apache.spark.mllib.regression.LabeledPoin
t] = MapPartitionsRDD[3] at randomSplit at :32

scala> val test = splits(1)
test: org.apache.spark.rdd.RDD[org.apache.spark.mllib.regression.LabeledPoint] =
 MapPartitionsRDD[4] at randomSplit at :32

​ 然後,構建邏輯斯蒂模型,用set的方法設定引數,比如說分類的數目,這裡可以實現多分類邏輯斯蒂模型:

scala> val model = new LogisticRegressionWithLBFGS().
     |       setNumClasses(3).
     |       run(training)
model: org.apache.spark.mllib.classification.LogisticRegressionModel = org.apach
e.spark.mllib.classification.LogisticRegressionModel: intercept = 0.0, numFeatur
es = 8, numClasses = 3, threshold = 0.5

​ 接下來,呼叫多分類邏輯斯蒂模型用的predict方法對測試資料進行預測,並把結果儲存在MulticlassMetrics中。這裡的模型全名為LogisticRegressionWithLBFGS,加上了LBFGS,表示Limited-memory BFGS。其中,BFGS是求解非線性優化問題(L(w)​求極大值)的方法,是一種秩-2更新,以其發明者Broyden, Fletcher, Goldfarb和Shanno的姓氏首字母命名。

scala> val predictionAndLabels = test.map { case LabeledPoint(label, features) =>
     |       val prediction = model.predict(features)
     |       (prediction, label)
     |     }
predictionAndLabels: org.apache.spark.rdd.RDD[(Double, Double)] = MapPartitionsR
DD[56] at map at :40

這裡,採用了test部分的資料每一行都分為標籤label和特徵features,然後利用map方法,對每一行的資料進行model.predict(features)操作,獲得預測值。並把預測值和真正的標籤放到predictionAndLabels中。我們可以打印出具體的結果資料來看一下:

(0.0,0.0)
(1.0,1.0)
(0.0,0.0)
(2.0,1.0)
(0.0,0.0)
(2.0,1.0)
(0.0,0.0)
(1.0,1.0)
(0.0,0.0)
... ...

可以看出,大部分的預測是對的。但第4行的預測與實際標籤不同。

4. 模型評估

​ 最後,我們把模型預測的準確性打印出來:

scala> val metrics = new MulticlassMetrics(predictionAndLabels)
metrics: org.apache.spark.mllib.evaluation.MulticlassMetrics = org.apache.spark.
mllib.evaluation.MulticlassMetrics@2bd9ef8c

scala>     val precision = metrics.precision
precision: Double = 0.9180327868852459

scala>     println("Precision = " + precision)
Precision = 0.9180327868852459