多元線性回歸公式推導及R語言實現


多元線性回歸

多元線性回歸模型

實際中有很多問題是一個因變量與多個自變量成線性相關,我們可以用一個多元線性回歸方程來表示。

為了方便計算,我們將上式寫成矩陣形式:

Y = XW

  • 假設自變量維度為N
  • W為自變量的系數,下標0 - N
  • X為自變量向量或矩陣,X維度為N,為了能和W0對應,X需要在第一行插入一個全是1的列。
  • Y為因變量
    那么問題就轉變成,已知樣本X矩陣以及對應的因變量Y的值,求出滿足方程的W,一般不存在一個W是整個樣本都能滿足方程,畢竟現實中的樣本有很多噪聲。最一般的求解W的方式是最小二乘法。

最小二乘法

我們希望求出的W是最接近線性方程的解的,最接近我們定義為殘差平方和最小,殘差的公式和殘差平方和的公式如下:

上面的公式用最小殘差平方和的方式導出的,還有一種思路用最大似然的方式也能推導出和這個一樣的公式,首先對模型進行一些假設:

  • 誤差等方差不相干假設,即每個樣本的誤差期望為0,每個樣本的誤差方差都為相同值假設為σ
  • 誤差密度函數為正態分布 e ~ N(0, σ^2)

簡單推導如下:

由此利用最大似然原理導出了和最小二乘一樣的公式。

最小二乘法求解

二次函數是個凸函數,極值點就是最小點。只需要求導數=0解出W即可。

模擬數據

我們這里用R語言模擬實踐一下,由於我們使用的矩陣運算,這個公式一元和多元都是兼容的,我們為了可視化方便一點,我們就用R語言自帶的women數據做一元線性回歸,和多元線性回歸的方式基本一樣。
women數據如下

> women
   height weight
1      58    115
2      59    117
3      60    120
4      61    123
5      62    126
6      63    129
7      64    132
8      65    135
9      66    139
10     67    142
11     68    146
12     69    150
13     70    154
14     71    159
15     72    164

體重和身高具有線性關系,我們做一個散點圖可以看出來:

我們用最小二乘推導出來的公式計算w如下

X <- cbind(rep(1, nrow(women)), women$height)
X.T <- t(X)
Y <- women$weight
w <- solve(X.T %*% X) %*% X.T %*% Y
> w
          [,1]
[1,] -87.51667
[2,]   3.45000
> lm.result <- lm(women$weight~women$height)
> lm.result

Call:
lm(formula = women$weight ~ women$height)

Coefficients:
 (Intercept)  women$height  
      -87.52          3.45

上面的R代碼w使我們利用公式計算出來的,下邊是R語言集成的線性回歸函數擬合出來的,可以看出我們的計算結果是正確的,lm的只是小數點取了兩位而已,將回歸出來的函數畫到圖中看下回歸的效果。

畫圖對應的R代碼如下,用R的感覺.....太飄逸了。

> png(file="chart2.png")
> plot(women$height, women$weight)
> lines(women$height, X %*% w)
> dev.off()

梯度下降法

除了用正規方程方式求解W,也可以用最常見的梯度下降法求得W,因為最小二乘是個凸函數,所以這里找到的極小點就是最小點。下面這段代碼用R寫還是非常容易的,但是剛開始step步長參數調的太大了,導致一直不收斂,我還
以為是程序錯誤,后來怎么看也沒寫錯,就把參數調了個很小值,結果就收斂了。step的這個取值其實應該是變化的,先大后下比較科學,我這個調的很小,需要接近500萬次才能收斂。

  • 初始化W 為全0向量,也可以隨機一個向量
  • 設置最大迭代次數,本例為了收斂設置了一個很大的數
  • 設置步長step,小了收斂很慢,大了不收斂.......
  • 求損失函數的梯度
  • W(k+1) 為 W(k) + 損失函數負梯度 * 步長step
  • 循環,直到梯度接近0

X <- cbind(rep(1, nrow(women)), women$height)
Y <- women$weight
maxIterNum <- 5000000;
step <- 0.00003;
W <- rep(0, ncol(X))
for (i in 1:maxIterNum){
    grad <- t(X) %*% (X %*% W -  Y);
    if (sqrt(as.numeric(t(grad) %*% grad)) < 1e-3){
        print(sprintf('iter times=%d', i));
        break;
    }
    W <- W - grad * step;
}
print(W);

輸出

[1] "iter times=4376771"

print(W);
[,1]
[1,] -87.501509
[2,] 3.449768

歸一化

上面的批量梯度下降為什么收斂如此之慢呢?原因很簡單,沒有做歸一化,做了歸一化,收斂速度快了非常非常多!!!!
正確代碼如下:

XScale = scale(women$height)
Ux = attr(XScale, "scaled:center")
Dx = attr(XScale, "scaled:scale")
YScale = scale(women$weight)
Uy = attr(YScale, "scaled:center")
Dy = attr(YScale, "scaled:scale")
X <- cbind(rep(1, nrow(women)), as.matrix(XScale))
Y <- as.matrix(YScale)
maxIterNum <- 5000;
step <- 0.001;
W <- rep(0, ncol(X))
for (i in 1:maxIterNum){
    grad <- t(X) %*% (X %*% W -  Y);
    if (sqrt(as.numeric(t(grad) %*% grad)) < 1e-6){
        print(sprintf('iter times=%d', i));
        break;
    }
    W <- W - grad * step;
}
print(W);
W0 = W[1]
Wn = W[2:length(W)]
Wn = Dy * Wn / Dx
W0 = Uy + Dy * W0 - Dy * Ux / Dx
W  = c(W0, Wn)
print(W);

輸出

[1] "iter times=1168"

print(W);
-88.53154 3.45000

更多精彩文章 http://h2cloud.org/


免責聲明!

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



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