線性回歸 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中,我們得到
我們對這個函數求導函數得到
如果直接這樣解方程,求出最小值,當然也可以,但是通用性不夠。所以用了另外一種方式:叫做梯度下降的方式去求解。
關於梯度下降,我后面再進行探討和學習,現在只是簡單的理解其中的含義。
簡單的理解,就是在一個凸函數中,隨機的選擇一個點,然后算出這個點的斜率,然后讓這個點減去斜率*一個速率,然后這個點就會向着最低點移動,直到到達最低點的時候,斜率=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]
但是從圖中,我們可以看出來,擬合出來的直線,很明顯不能非常完美的貼合所有的數據。可能這些數據的分布,不是呈簡單線性相關。有可能是一個曲線或者拋物線的形式。隨后,我講嘗試進行多元的擬合。