一次線性回歸分析詳解及推導


線性回歸 linear regression

我們需要根據一個人的工作年限 來預測他的 薪酬 (我們假設一個人的薪酬只要工作年限有關系)。

首先引入必要的類庫,並且獲得trainning data。

import tensorflow as tf
import pandas as pd
import numpy as np
unrate = pd.read_csv('SD.csv')
print(unrate)
    Year  Salary
0    1.0   39451
1    1.2   46313
2    1.4   37839
3    1.9   43633
4    2.1   39999
..   ...     ...
85  12.0  106247
86  12.5  117634
87  12.6  113300
88  13.3  123056
89  13.5  122537

[90 rows x 2 columns]

接着,我們用matplotlib繪制出工作年限和薪酬之間的關系的點狀圖,方便我們更加直觀的感受他們之間的關系。

from matplotlib import pyplot as plt

unrate = unrate.sort_values('Year')

plt.scatter(unrate['Year'],unrate['Salary'])

plt.show()

根據上圖的關系,我們可以看到:他們基本上還是成正相關的。考慮到只有一維數據,我們假定存在一個函數,可以描述工作年限和薪酬之間的關系。我們假定該函數為:$$ \hat{y} = Wx+b $$

$ \hat{y} $即為我們根據模型預測出來的數值。 $ \hat(y) $ 和實際數值y 之間的距離,即為我們預測的偏差值。即:$$ loss = \sum_{i=0}^{n} (y_i- \hat y_i)^2$$

</p>

我們先隨機的挑選W 和b ,並且計算一下loss。同時繪制出來預測的數值與原來的數值。

w = np.random.rand(1)
b = np.random.rand(1)

y_pred = (unrate['Year']*w + b)
loss = np.power((unrate['Year']*w + b)-unrate['Salary'],2).sum()

plt.scatter(unrate['Year'],unrate['Salary'])
plt.plot(unrate['Year'],y_pred)
plt.show()
print(w)
print(b)
print(loss)

[0.31944837]
[0.48968515]
698967170603.215

我們可以看到差距還是比較大的。

那么該怎么求w和b呢?

而我們工作的本質上就在尋找合適的W和b,從而達到loss最小。也就是找 $ loss = \sum_{i=0}^{n} (y_i- \hat y_i)^2$的最小值。

單純的從數學上來看。尋找一個函數的極值,就是找到它導數為0的駐點,然后去判斷哪些駐點為最小值。


我們把 $ \hat(y)$的計算公式帶入 loss中,我們得到

\[loss = \sum_{i=0}^{n} (y_i-Wx-b)^2 \]

我們對這個函數求導函數得到

\[\frac{dl}{dw}=\frac{dl}{d\hat{y}}*\frac{d\hat{y}}{dw} \]

\[\frac{dl}{dw}=-2\sum_{i=0}^{n}((y_i-\hat{y}_i)*\frac{d\hat{y}}{dw}) = -2\sum_{i=0}^{n}((y_i-\hat{y}_i)x_i) \]

\[\frac{dl}{db} = -2\sum_{i=0}^{n}(\frac{dl}{d\hat{y}_i}* \frac{d\hat{y}_i}{db})=-2\sum_{i=0}^{n}(y_i-\hat{y}_i) \]

如果直接這樣解方程,求出最小值,當然也可以,但是通用性不夠。所以用了另外一種方式:叫做梯度下降的方式去求解。

關於梯度下降,我后面再進行探討和學習,現在只是簡單的理解其中的含義。
梯度下降示意圖
簡單的理解,就是在一個凸函數中,隨機的選擇一個點,然后算出這個點的斜率,然后讓這個點減去斜率*一個速率,然后這個點就會向着最低點移動,直到到達最低點的時候,斜率=0,所以便不再變化。這樣的話,我們得到一個通用的辦法,就不用解方程了,任何函數,只要我們得到他的導函數,然后隨機一個點,重復梯度下降的步驟,就可以得到最合適的數值。

def train(w, b):
    learning_rate = 0.0001

    dw = np.sum((np.power(unrate['Year'],2)* w -np.transpose(unrate['Salary']-b)*unrate['Year']))
    db = np.sum(unrate['Salary']-(unrate['Year']*w-b))

    temp_w = w - learning_rate * dw
    temp_b = b - learning_rate * db
    w = temp_w
    b = temp_b
    return w, b

我們先來train一次,看看效果

w,b = train(w,b)

y_pred = (unrate['Year']*w + b)
loss = np.power((unrate['Year']*w + b)-unrate['Salary'],2).sum()

plt.scatter(unrate['Year'],unrate['Salary'])
plt.plot(unrate['Year'],y_pred)
plt.show()
print(w)
print(b)
print(loss)

[5430.27093385]
[-755.1422668]
246914588144.68262

看到有明顯的效果,我們來多嘗試幾次試試

for i in range(1000):
    w,b = train(w,b)
y_pred = (unrate['Year']*w + b)
loss = np.power((unrate['Year']*w + b)-unrate['Salary'],2).sum()

plt.scatter(unrate['Year'],unrate['Salary'])
plt.plot(unrate['Year'],y_pred)
plt.show()
print(w)
print(b)
print(loss)

[12742.12454444]
[-3940.07990295]
39663899737.785065

我們可以看到已經擬合出來一條直線,基本擬合了訓練的數據,這個時候,給定一個x值,我們都可以預測一個\(\hat{y}\)

x = 20
y_hat = w*x+b
print(y_hat)
[250902.4109859]

但是從圖中,我們可以看出來,擬合出來的直線,很明顯不能非常完美的貼合所有的數據。可能這些數據的分布,不是呈簡單線性相關。有可能是一個曲線或者拋物線的形式。隨后,我講嘗試進行多元的擬合。



免責聲明!

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



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