1. 程式人生 > >機器學習(二):理解線性迴歸與梯度下降並做簡單預測

機器學習(二):理解線性迴歸與梯度下降並做簡單預測

# 預測從瞎猜開始 按[上一篇文章](https://mp.weixin.qq.com/s/-KsbtgOc3C3ry-8P5f8K-Q)所說,機器學習是應用數學方法在資料中發現規律的過程。既然數學是對現實世界的解釋,那麼我們迴歸現實世界,做一些對照的想象。 想象我們面前有一塊塑料泡沫做的白板,白板上分佈排列著數枚藍色的圖釘,隱約地它們似乎存在著某種規律,我們試著找出規律。 ![](https://img2020.cnblogs.com/blog/678094/202101/678094-20210119191206623-599818038.png) 白板上的圖釘(**資料**)如上圖所示,我們有沒有一種方法(**數學演算法**)來尋找規律(**模型解釋**)呢? 既然不知道怎麼做,那我們瞎猜吧! 我拿起兩根木棒在白板前比劃,試著用木棒表示資料的規律。我隨便放了放,如下圖所示: ![](https://img2020.cnblogs.com/blog/678094/202101/678094-20210119191212278-1194021959.png) 它們似乎都在一定程度上能表示藍色圖釘的規律,那麼問題來了,綠色(虛線)和紅色(實線)哪一個表示更好呢? # 損失函式(成本函式) 好與壞是很主觀的表達,主觀的感受是不可靠的,我們必須找到一種客觀的度量方式。我們想當然的認為誤差最小的表示,是最好的。那麼,我們引出一種量化誤差的方法---最小二乘法。 **最小二乘法**:使誤差的平方和最小的辦法,是一種誤差統計方法,二乘就是平方的意思。 $$ SE = \sum{(y_{pred} -y_{true})^2} $$ 最小二乘法的解釋是這樣的,我們用`預測值-實際值`表示單點的誤差,再把它們的`平方和`加到一起來表示整體誤差。(*平方的好處可以處理掉負數值,用絕對值的和也不是不可以。*)我們用這個最終值來表示損失(成本),而可以表示損失(成本)的函式就叫做損失函式(成本函式)。 ![](https://img2020.cnblogs.com/blog/678094/202101/678094-20210119191219506-774806832.png) 如上圖我們可以看到,藍色點到實線的距離就是我們要帶入公式的誤差。雖然它們看上去相近,但經過計算的結果是紅色實線(`y=3x+2`)的損失為27.03,而綠色實線(`y=4x+4`)的損失為29.54,顯然紅色模型優於綠色模型。 那麼,還有沒有比紅色實線更好的模型來表示資料呢?有沒有一種方式來找到它呢? # 梯度下降 我們把木棒(實線、模型)的表示數學化,我們既然可以用3、4做為x的係數,那我們當然可以嘗試別的數字。我們用如下公式表示這種關係: $$ y = wx + b $$ 其中,x和y是已知的,我們不斷調整`w`(**權重**)和`b`(**偏差**),然後再帶入損失函式以求得最小值的過程,就是**梯度下降**。 我們從-50開始到50結束設定`w`的值,我們通過隨機數來是指偏置`b`,然後再帶入損失函式計算我們的預測和實際值的誤差損失,得到如下曲線: ![](https://img2020.cnblogs.com/blog/678094/202101/678094-20210119191226273-18336417.png) **需要注意的是,我們繪製的影象是根據權重和損失繪製的曲線。而我們的模型表示是一條直線。** 我們可以看到,在上圖中我們是可以找到極小值的,大概在5左右,此處是我們損失最小的位置,這時我們的模型最能表示資料的規律。 梯度可以**完全**理解為導數,梯度下降的過程就是我們不斷求導的過程。 # 學習率(步長) 不斷調整權重和偏差來來尋找損失函式最小值的過程就是我們使用梯度下降方法擬合數據尋找最佳模型的過程。那麼既然我們有了解決方案,是不是該考慮如何提升效率了,我們如何快速地找到最低點? 想象一下,當你迷失在山上的濃霧之中,你能感覺到的只有你腳下路面的坡度。快速到達山腳的一個策略就是沿著最陡的方向下坡。梯度下降中的一個重要的引數就是每一步的**步長**(**學習率**),如果步長太小,演算法需要經過大量迭代才會收斂,如果步長太大,你可能會直接越過山谷,導致演算法發散,值越來越大。 設定步長為過小: ![](https://img2020.cnblogs.com/blog/678094/202101/678094-20210119191233323-1321986188.gif) 設定步長過大: ![](https://img2020.cnblogs.com/blog/678094/202101/678094-20210119191239329-1627715234.gif) 設定步長適當: ![](https://img2020.cnblogs.com/blog/678094/202101/678094-20210119191247017-1205714384.gif) 步長是演算法自己學習不出來的,它必須由外界指定。 這種演算法不能學習,需要人為設定的引數,就叫做**超引數**。 # 線性迴歸 最終我們找到了**線性**模型來解釋自變數x與因變數y之間的關係,這就是**線性迴歸**。迴歸的解釋是,事物總是傾向於朝著某種“平均”發展,這種**趨勢**叫做迴歸,所以迴歸多用於預測。 ![](https://img2020.cnblogs.com/blog/678094/202101/678094-20210119191254322-1387830309.png) 上圖,紅線是我們擬合出的最佳模型,在此模型上我們可以尋找到2.2,2.6,2.8的預測值,分別對應圖中的三個紅點。 這也是線性迴歸的基本意義。 # 程式碼實踐 準備資料: ``` import numpy as np import matplotlib.pyplot as plt np.random.seed(42) X = 2 * np.random.rand(10) y = 4 + 3 * X + np.random.randn(10) plt.plot(X, y, "bo") plt.xlabel("$X$", fontsize=18) plt.ylabel("$y$", rotation=0, fontsize=18) plt.axis([0, 2, 0, 15]) plt.show() ``` 繪製`y=3x+2`和`y=4x+4`兩條直線: ``` plt.plot(X, y, "bo") plt.plot(X, 3*X+2, "r-", lw="5", label = "y=3x+2") plt.plot(X, 4*X+4, "g:", lw="5", label = "y=4x+4") plt.xlabel("$X$", fontsize=18) plt.ylabel("$y$", rotation=0, fontsize=18) plt.axis([0, 2, 0, 15]) plt.legend(loc="upper left") plt.show() ``` 計算損失,並比較`y=3x+2`和`y=4x+4`兩條直線: ``` fig, ax_list = plt.subplots(nrows=1, ncols=2,figsize=(20,10)) ax_list[0].plot(X, y, "bo") ax_list[0].plot(X, 3*X+2, "r-", lw="5", label = "y=3x+2") loss = 0 for i in range(10): ax_list[0].plot([X[i],X[i]], [y[i],3*X[i]+2], color='grey') loss= loss + np.square(3*X[i]+2-y[i]) pass ax_list[0].axis([0, 2, 0, 15]) ax_list[0].legend(loc="upper left") ax_list[0].title.set_text('loss=%s'%loss) ax_list[1].plot(X, y, "bo") ax_list[1].plot(X, 4*X+4, "g:", lw="5", label = "y=4x+4") loss = 0 for i in range(10): ax_list[1].plot([X[i],X[i]], [y[i],4*X[i]+4], color='grey') loss= loss + np.square(4*X[i]+4-y[i]) pass ax_list[1].axis([0, 2, 0, 15]) ax_list[1].legend(loc="upper left") ax_list[1].title.set_text('loss=%s'%loss) fig.subplots_adjust(wspace=0.1,hspace=0.5) fig.suptitle("Calculate loss",fontsize=16) ``` 訓練模型,並預測: ``` from sklearn.linear_model import LinearRegression lr = LinearRegression() lr.fit(X.reshape(-1,1),y.reshape(-1,1)) X_test = [[2.2],[2.6],[2.8]] y_test = lr.predict(X_test) X_pred = 3 * np.random.rand(100, 1) y_pred = lr.predict(X_pred) plt.scatter(X,y, c='b', label='real') plt.plot(X_test,y_test, 'r', label='predicted point' ,marker=".", ms=20) plt.plot(X_pred,y_pred, 'r-', label='predicted') plt.xlabel("$X$", fontsize=18) plt.ylabel("$y$", rotation=0, fontsize=18) plt.axis([0, 3, 0, 15]) plt.legend(loc="upper left") loss = 0 for i in range(10): loss = loss + np.square(y[i]-lr.predict([[X[i]]])) plt.title("loss=%s"%loss) plt.show() ``` # 其他迴歸 要怎麼真正理解迴歸(regression)呢?通過大量的資料統計,個體小的豆子往往傾向於產生比其更大的後代,而個體大的豆子往往傾向於產生比其更小的後代,新產生的個體有向著豆子的平均值的一種趨勢,這種趨勢就是迴歸。我們本篇文章講的線性迴歸就是應用於**預測**的一種技術。這時,迴歸往往與分類相對。 線性迴歸、邏輯迴歸、多項式迴歸、逐步迴歸、嶺迴歸、套索(Lasso)迴歸、彈性網路(ElasticNet)迴歸是最常用的迴歸技術。我先對這些技術做一個簡單整理,讓大家把脈絡理清,等大家實際需要再深入探索。**試圖去窮盡知識只會把自己拖向疲累**。 | 名稱 | 解釋 | 公式 | | --- | --- | --- | | 線性迴歸(Linear Regression) | 一種以線性模型來建模自變數與因變數關係的方法 | $$ y = wx+b $$ | | 邏輯迴歸(Logistic Regression) | 對特定類別進行建模,用於二分類 | $$ y=\frac{1}{1+e^{-x}} $$ | | 多項式迴歸(Polynomial Regression) | 自變數 x 和因變數 y 之間的關係被建模為關於 x 的 n 次多項式 | $$ y=\beta_0 + \beta_1x + \beta_2x^2 + ... + \beta_mx^m + \varepsilon $$ (cαiyongji水印) | | 逐步迴歸(Stepwise Regression) | 將多個變數一個一個地引入到模型,找到其對模型影響大的變數 | | | 套索迴歸(Lasso Regression) | 稀疏矩陣,消除不重要的特徵,MSE+L1範數 | $$ J(\theta)=MSE(\theta) + \alpha\sum\mid\theta\mid $$ ,其中,α越大模型權重越小| | 嶺迴歸(Ridge Regression) | 正則化線性迴歸,增加模型自由度,防止過擬合,MSE+L2範數 | $$ J(\theta)=MSE(\theta) + \alpha\frac{1}{2}\sum\theta^2 $$ ,其中,α越大模型權重越小| | 彈性網路(ElasticNet) | 介於嶺迴歸和Lasso迴歸之間 | $$ J(\theta)=MSE(\theta) + \gamma\alpha\sum\mid\theta\mid + \alpha\frac{1-\gamma}{2}\sum\theta^2 $$ ,其中,γ介於0和1之間,接近0則更傾向於嶺迴歸,接近1則更傾向於Lasso