ml筆記1: 線性回歸之梯度下降

梯度下降示意圖

本文理論部份基于Andew Ng的公開(kāi)課遍膜,工程實(shí)踐來(lái)自 Spark ML捷雕。我是個(gè)愚鈍的人叁鉴,純理論學(xué)不動(dòng)。


Linear Regression

機(jī)器學(xué)習(xí)是一個(gè)歸納與演繹的過(guò)程江醇,根據(jù)已有數(shù)據(jù)集濒憋,訓(xùn)練出模型(歸納),去預(yù)測(cè)未知的世界(演繹)陶夜。在公開(kāi)課里以波士頓房?jī)r(jià)為第一個(gè)例子凛驮,我在趕集房產(chǎn)頻道爬了部份小區(qū)數(shù)據(jù),用于學(xué)習(xí)

總價(jià)(w) 面積(m^2) 臥室
498 125 3
370 87 2
498 125 3
510 116 2
1185 350 5

上面只是部分?jǐn)?shù)據(jù)条辟,房?jī)r(jià)一般和地理位置黔夭,面積,朝向羽嫡,是否學(xué)區(qū)相關(guān)本姥,這些指標(biāo)統(tǒng)稱(chēng)為 feature , 如果只考濾面積這個(gè)特征,我們畫(huà)一下數(shù)據(jù)分布圖

房?jī)r(jià)散點(diǎn)圖

如果我們?cè)侔雅P室這個(gè) feature 考慮進(jìn)去杭棵,那么新的散點(diǎn)圖就是三維的

房?jī)r(jià)三維散點(diǎn)圖

對(duì)于多維 N 個(gè)特征婚惫,雖然無(wú)法對(duì)應(yīng)現(xiàn)實(shí)世界物理模型,但是可以對(duì)應(yīng)矩陣魂爪,大家腦補(bǔ)


公式推導(dǎo)

對(duì)于只有一個(gè)特征的線性公式

h(x)=??0 +??1??1

簡(jiǎn)書(shū)沒(méi)有數(shù)學(xué)公式編輯先舷,上面??0中的0是小標(biāo),實(shí)際上應(yīng)該是??0??0滓侍,但是我們默認(rèn)第0個(gè)特征值為1蒋川,即 ??0=1,所以可以如此簡(jiǎn)寫(xiě)撩笆。

h(x)=??0 +??1??1 +??2??2 =∑???????? =??T??

對(duì)于擁有多個(gè)特征的線性公式也很好理解尔破,其中??和??均為列向量,??T是??的轉(zhuǎn)置向量浇衬,T是??的上標(biāo)。函數(shù) h(x) 可以表示為兩個(gè)向量的點(diǎn)積(內(nèi)積)餐济,我們最終就是要解出列向量??耘擂,使得這條直線更合理。

最理想的線性擬合

這里明顯有個(gè)離群點(diǎn)絮姆,[170,96 3] 這組數(shù)據(jù)異常醉冤,涉及到數(shù)據(jù)抽取和清洗秩霍,暫時(shí)不提。

如何衡量哪組??更合理

我們定義一個(gè)函數(shù)蚁阳,叫做 cost function , 或是 loss function . 這個(gè)函數(shù)來(lái)衡量某一特定??時(shí)铃绒,所擬合的失真程度,這個(gè)程度越小越合理螺捐。

J(θ) = 1/2 ∑(h??(??(??)) ? ??(??))^2

其中 J 是向量??的函數(shù)颠悬,h??(??(??)) 為給定??預(yù)測(cè)出的??(??)值。函數(shù)為預(yù)測(cè)值與對(duì)應(yīng)真實(shí)值差的平方和定血,最后要乘以1/2, 方便求導(dǎo)時(shí)使系統(tǒng)為1.

初始默認(rèn) ?? 是一個(gè)N維的零(列)向量赔癌,那么此時(shí) J 肯定非常大,目的就是找到一組 ?? 使這個(gè)損失函數(shù) J 取最小值澜沟。所以我們需要每次改變?? 值灾票,不斷試錯(cuò)。

??動(dòng)態(tài)求解

上圖迭代了四次茫虽,終于找到最優(yōu)解刊苍。


梯度下降示意圖

梯度下降

公開(kāi)課使用梯度下降法求近似解,求 θ 最終變成了求 J(θ) 極小值濒析。梯度方向由 J(θ) 對(duì) θ 的偏導(dǎo)數(shù)確定正什,由于極小值,所以為偏導(dǎo)數(shù)的反方向悼枢。

θj :=θj ?α ( J(θ))'

公式中 θj 是每次迭代前的值減去一個(gè)變量埠忘,α 稱(chēng)為學(xué)習(xí)速率,這個(gè)值不能過(guò)大馒索,可能跳過(guò)極值莹妒,過(guò)小也會(huì)影響收斂速度。( J(θ))' 是 J(θ) 對(duì) θ 的偏導(dǎo)數(shù)(沒(méi)找到好的公式編輯器)绰上。當(dāng)我們只考濾一個(gè)樣本的時(shí)候旨怠,對(duì)J(θ)鏈?zhǔn)角髮?dǎo)

求J(θ)偏導(dǎo)數(shù)

由上圖可知導(dǎo)數(shù)結(jié)果是一個(gè)矢量與向量積。h??(??) ? ?? 是估計(jì)值與真實(shí)值之差蜈块,??j 是當(dāng)前樣本特征值鉴腻,為列量向。同理推導(dǎo)出當(dāng)我們有 m 個(gè)樣本時(shí)的梯度為:

θj:=θj+α∑(y(i)?hθ(x(i)))x(i)

就是說(shuō)我們每次迭代 θ百揭,迭代值 α∑(y(i)?hθ(x(i)))x(i), 這塊初次接觸有點(diǎn)繞口爽哎,通過(guò)閱讀源碼加深理解。

Spark 訓(xùn)練模型

Python 也有很好的機(jī)器學(xué)習(xí)庫(kù)器一,相比更通用適合學(xué)習(xí)课锌。Spark mllib 也比較成熟,借助 RDD 可以實(shí)現(xiàn)大數(shù)據(jù)分布式計(jì)算,訓(xùn)練模型效率更高效渺贤。先來(lái)看看用 Spark 實(shí)現(xiàn)例子中的 Linear Regression

準(zhǔn)備數(shù)據(jù)

數(shù)據(jù)格式為 Label, feature1,feature2,feature3.... 本文中只有2個(gè)特征雏胃,其中術(shù)語(yǔ) Label 對(duì)應(yīng) price, feature1 對(duì)應(yīng)面積,feature2 對(duì)應(yīng)臥室數(shù)量志鞍。

498,125 3
670,141 3
600,137 3
650,150 3

打開(kāi) spark-shell 加載數(shù)據(jù)

scala> val data = sc.textFile("/Users/dzr/code/spark-mllib-data/house.data")
data: org.apache.spark.rdd.RDD[String] = /Users/dzr/code/spark-mllib-data/house.data MapPartitionsRDD[1] at textFile at <console>:27

加載數(shù)據(jù)文件瞭亮,生成 RDD[String],生產(chǎn)環(huán)境數(shù)據(jù)一般從HDFS中獲取固棚,本機(jī)只是用來(lái)演示和訓(xùn)練模型统翩。加載數(shù)據(jù)后,要把數(shù)據(jù)做特殊處理玻孟。

scala> import org.apache.spark.mllib.regression.LabeledPoint
scala> import org.apache.spark.mllib.linalg.Vectors
scala> val trainSet = data.map {line=>
      val parts = line.split(',')
      LabeledPoint(parts(0).toDouble,Vectors.dense(parts(1).split(' ').map(_.toDouble)))}
trainSet: org.apache.spark.rdd.RDD[org.apache.spark.mllib.regression.LabeledPoint] = MapPartitionsRDD[3] at map at <console>:31

scala> trainSet.take(2).foreach(println)
(498.0,[125.0,3.0])
(670.0,[141.0,3.0])
Spark 線性回歸術(shù)語(yǔ)
  • SGD: Stochastic Gradient Descent 隨機(jī)梯度下降
  • LabeledPoint: Class that represents the features and labels of a data point, 線性回歸屬于監(jiān)督學(xué)習(xí)唆缴,在給定觀測(cè)特征對(duì)應(yīng)的值叫做 label
  • Weight: 權(quán)重是一個(gè)列向量,就是我們要求得的 ??
  • Intercept: 簡(jiǎn)單的理解為 y 軸的截距黍翎,即當(dāng)各特征均為零值時(shí)的觀測(cè)默認(rèn)值面徽。這項(xiàng)的意義在于,他能捕捉到未觀察到的誤差(比如我們可能忽略了其它有影響的特征)
失敗的建模
scala> import org.apache.spark.mllib.regression._
scala> val numIterations = 100 // 設(shè)置迭代次數(shù)
numIterations: Int = 100 

scala> val stepSize = 1 // 每次迭代步長(zhǎng)
stepSize: Int = 1

scala> val minBatchFraction = 1.0 // 樣本參與迭代比例
minBatchFraction: Double = 1.0
scala> val model = LinearRegressionWithSGD.train(trainSet, numIterations,stepSize,minBatchFraction)
model: org.apache.spark.mllib.regression.LinearRegressionModel = org.apache.spark.mllib.regression.LinearRegressionModel: intercept = 0.0, numFeatures = 2
scala> model.weights
res48: org.apache.spark.mllib.linalg.Vector = [NaN,NaN]

scala> model.intercept
res49: Double = 0.0

很詭異的事情誕生了匣掸,model.weights 列向量居然是 NaN, 也就是說(shuō)不是有效的 double 浮點(diǎn)數(shù)趟紊,model.intercept 是0.0也不很正常。為什么用 Matlab 就能擬合出結(jié)果碰酝,而 Spark 就失敗了霎匈?

學(xué)習(xí)速率

咨詢(xún)了(靚麗青春無(wú)敵的美少女學(xué))同事,給兩個(gè)建義:特征數(shù)據(jù)做歸一化處理送爸,調(diào)整學(xué)習(xí)速率铛嘱。首先做的是歸一化處理,將特征標(biāo)準(zhǔn)差標(biāo)準(zhǔn)化(均值0, 標(biāo)準(zhǔn)差1)袭厂,還是得到 NaN 值墨吓。然后調(diào)整 stepSize ,從1, 0.1, 0.01, 0.001,0.0001開(kāi)始測(cè)試纹磺,終于在0.001時(shí)得到擬合值帖烘。

scala> val model = LinearRegressionWithSGD.train(trainSet, 100,0.0001)
model: org.apache.spark.mllib.regression.LinearRegressionModel = org.apache.spark.mllib.regression.LinearRegressionModel: intercept = 0.0, numFeatures = 2

scala> model.weights //擬合
res227: org.apache.spark.mllib.linalg.Vector = [4.225755672693632,0.09458364813972062]

scala> model.predict(new DenseVector(Array(98,3))) // 進(jìn)行預(yù)測(cè),98平橄杨,3居的房子大概414萬(wàn)人民幣
res228: Double = 414.4078068683951

這里還有個(gè)問(wèn)題秘症,在迭代次數(shù)不變,不斷調(diào)小 stepSize 時(shí)式矫,會(huì)取不到極小值乡摹。當(dāng)數(shù)據(jù)已經(jīng)做歸一化處理時(shí),學(xué)習(xí)速率可以稍大一些采转。最后預(yù)測(cè)房?jī)r(jià)函數(shù)為

h(x)= 4.22 * ??1 + 0.09 * ??2

可以直觀的看到房?jī)r(jià)每平4.22W趟卸,并且和第二個(gè)特征rooms關(guān)系不大。

loss cost

擬合的效果好不好,最終要看損失值和均方根誤差


scala> val prediction = model.predict(trainSet.map(_.features))
prediction: org.apache.spark.rdd.RDD[Double] = MapPartitionsRDD[10732] at mapPartitions at GeneralizedLinearAlgorithm.scala:69


scala> val predictionAndLabel = prediction.zip(trainSet.map(_.label))
predictionAndLabel: org.apache.spark.rdd.RDD[(Double, Double)] = ZippedPartitionsRDD2[10734] at zip at <console>:45

scala> for(i<-0 to prediction.collect.length -1) {
     | println(predictionAndLabel.collect()(i)._1 + "\t" + predictionAndLabel.collect()(i)._2)}

scala> val loss = predictionAndLabel.map {
     | case (p, l) =>
     | val err = p - l
     | err * err }.reduce(_+_)
loss: Double = 13322.402139229554

scala> val rmse = math.sqrt(loss/prediction.collect.length)
rmse: Double = 28.85567766838698
預(yù)測(cè)值                   真實(shí)值
528.5032100311231       498.0
596.1153007942212       670.0
579.2122781034467       600.0
634.1471018484639       650.0
295.99206438483367      320.0
579.2122781034467       550.0

可以看到 rmse 為28.8

小結(jié)

邊學(xué)邊動(dòng)手實(shí)踐還是蠻快的锄列,終于看到了ML的冰山一角。還有分類(lèi)算法什么的惯悠,慢慢看吧邻邮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市克婶,隨后出現(xiàn)的幾起案子筒严,更是在濱河造成了極大的恐慌,老刑警劉巖情萤,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸭蛙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡筋岛,警方通過(guò)查閱死者的電腦和手機(jī)娶视,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)睁宰,“玉大人肪获,你說(shuō)我怎么就攤上這事∑馍担” “怎么了孝赫?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)红符。 經(jīng)常有香客問(wèn)我青柄,道長(zhǎng),這世上最難降的妖魔是什么预侯? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任致开,我火速辦了婚禮,結(jié)果婚禮上雌桑,老公的妹妹穿的比我還像新娘喇喉。我一直安慰自己,他們只是感情好校坑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布拣技。 她就那樣靜靜地躺著,像睡著了一般耍目。 火紅的嫁衣襯著肌膚如雪膏斤。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,079評(píng)論 1 285
  • 那天邪驮,我揣著相機(jī)與錄音莫辨,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛沮榜,可吹牛的內(nèi)容都是我干的盘榨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蟆融,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼草巡!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起型酥,我...
    開(kāi)封第一講書(shū)人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤山憨,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后弥喉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體郁竟,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年由境,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了棚亩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡藻肄,死狀恐怖蔑舞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嘹屯,我是刑警寧澤攻询,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站州弟,受9級(jí)特大地震影響钧栖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜婆翔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一拯杠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧啃奴,春花似錦潭陪、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至瘟则,卻和暖如春黎炉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背醋拧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工慷嗜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留淀弹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓庆械,卻偏偏與公主長(zhǎng)得像薇溃,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子干奢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容