線性迴歸是利用被稱爲線性迴歸方程的最小平方函數對一個或多個自變量和因變量之間關係進行建模的一種迴歸分析。這種函數是一個或者多個被稱爲迴歸係數的模型參數的線性組合。
1.一元線性迴歸
找到一條直線能夠最大程度上擬合二維空間中出現的點。
2.多元線性迴歸
如果自變量多餘1個,那麼就要求一個多元函數去擬合空間中的點。
二元線性迴歸:
n元線性迴歸:
要求什麼?
要求使得所有點到這條線的誤差最小。
誤差最小化:
要求參數θ的最優解,使得所有點到這條線的誤差最小。
如果將y表示樣本的真實值,h_θ (x)表示樣本的預測值,那麼損失函數是:
3.最小二乘法
最小二乘法:函數求導,令導數爲0。
若XTX不可逆,不可使用。實際中,若XTX階過高,仍然需要使用梯度下降的方式計算數值解。
4.梯度下降法
將求函數最小值想象成下山。注意局部最優解。
一個在山頂的人的下山邏輯:
1、找到下山最快的坡度
2、沿着這個坡度走一段距離a。
3、重複1、2步驟,直到到山底。
1)批量梯度下降算法
1、遍歷與此前高度相同的位置的下山最快的坡度
2)隨機梯度下降算法
1、只遍歷當前位置的下山最快的坡度
梯度下降算法:
- 初始化θ(隨機初始化)。
- 迭代,新的θ能夠使得J(θ)更小。
- 如果J(θ)能夠繼續減少不收斂,返回2)。 α稱爲學習率,也叫步長。
5.線性迴歸的應用
通過大量樣本的實驗學習到線性函數,然後根據新的樣本外的特徵數據,預測結果。
6.代碼實現
- 創建SparkContext。
- 讀取訓練集。
- 訓練模型。
- 使用模型,進行預測。
- 評估模型,將預測值與真實值作比較。
- 【Option】保存模型,方便下次使用。
- 關閉sparkContext。
package com.dengdan
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 = {
val conf = new SparkConf().setMaster("local[4]").setAppName("LinearRegression")
val sc = new SparkContext(conf)
val path = "D:\\idea_workspace2020\\spark\\sparkMLib\\linear_regression\\src\\main\\resources\\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 numInterations = 100
//梯度下降步長
val stepSize = 0.00000001
//訓練模型
val model = LinearRegressionWithSGD.train(data, numInterations, 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(s"訓練模型的均方誤差=${MSE}")
val modelPath = "target/tmp/scalaLinearRegressionWithSGDModel"
//保存模型
model.save(sc, modelPath)
//重新加載模型
val sameModel = LinearRegressionModel.load(sc, modelPath)
sc.stop()
}
}