1. 程式人生 > >用Python開始機器學習(3:資料擬合與廣義線性迴歸)

用Python開始機器學習(3:資料擬合與廣義線性迴歸)

機器學習中的預測問題通常分為2類:迴歸分類

簡單的說迴歸就是預測數值,而分類是給資料打上標籤歸類。

本文講述如何用Python進行基本的資料擬合,以及如何對擬合結果的誤差進行分析。

本例中使用一個2次函式加上隨機的擾動來生成500個點,然後嘗試用1、2、100次方的多項式對該資料進行擬合。
擬合的目的是使得根據訓練資料能夠擬合出一個多項式函式,這個函式能夠很好的擬合現有資料,並且能對未知的資料進行預測。

程式碼如下:

import matplotlib.pyplot as plt
import numpy as np
import scipy as sp
from scipy.stats import norm
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn import linear_model

''' 資料生成 '''
x = np.arange(0, 1, 0.002)
y = norm.rvs(0, size=500, scale=0.1)
y = y + x**2

''' 均方誤差根 '''
def rmse(y_test, y):
    return sp.sqrt(sp.mean((y_test - y) ** 2))

''' 與均值相比的優秀程度,介於[0~1]。0表示不如均值。1表示完美預測.這個版本的實現是參考scikit-learn官網文件  '''
def R2(y_test, y_true):
    return 1 - ((y_test - y_true)**2).sum() / ((y_true - y_true.mean())**2).sum()


''' 這是Conway&White《機器學習使用案例解析》裡的版本 '''
def R22(y_test, y_true):
    y_mean = np.array(y_true)
    y_mean[:] = y_mean.mean()
    return 1 - rmse(y_test, y_true) / rmse(y_mean, y_true)


plt.scatter(x, y, s=5)
degree = [1,2,100]
y_test = []
y_test = np.array(y_test)


for d in degree:
    clf = Pipeline([('poly', PolynomialFeatures(degree=d)),
                    ('linear', LinearRegression(fit_intercept=False))])
    clf.fit(x[:, np.newaxis], y)
    y_test = clf.predict(x[:, np.newaxis])

    print(clf.named_steps['linear'].coef_)
    print('rmse=%.2f, R2=%.2f, R22=%.2f, clf.score=%.2f' %
      (rmse(y_test, y),
       R2(y_test, y),
       R22(y_test, y),
       clf.score(x[:, np.newaxis], y)))    
    
    plt.plot(x, y_test, linewidth=2)
    
plt.grid()
plt.legend(['1','2','100'], loc='upper left')
plt.show()

該程式執行的顯示結果如下:

[-0.16140183  0.99268453]
rmse=0.13, R2=0.82, R22=0.58, clf.score=0.82

[ 0.00934527 -0.03591245  1.03065829]
rmse=0.11, R2=0.88, R22=0.66, clf.score=0.88
[  6.07130354e-02  -1.02247150e+00   6.66972089e+01  -1.85696012e+04
......

-9.43408707e+12  -9.78954604e+12  -9.99872105e+12  -1.00742526e+13
-1.00303296e+13  -9.88198843e+12  -9.64452002e+12  -9.33298267e+12
  -1.00580760e+12]

rmse=0.10, R2=0.89, R22=0.67, clf.score=0.89

顯示出的coef_就是多項式引數。如1次擬合的結果為

y = 0.99268453x -0.16140183 

這裡我們要注意這幾點:

1、誤差分析

做迴歸分析,常用的誤差主要有均方誤差根(RMSE)和R-平方(R2)。

RMSE是預測值與真實值的誤差平方根的均值。這種度量方法很流行(Netflix機器學習比賽的評價方法),是一種定量的權衡方法。

R2方法是將預測值跟只使用均值的情況下相比,看能好多少。其區間通常在(0,1)之間。0表示還不如什麼都不預測,直接取均值的情況,而1表示所有預測跟真實結果完美匹配的情況。

R2的計算方法,不同的文獻稍微有不同。如本文中函式R2是依據scikit-learn官網文件實現的,跟clf.score函式結果一致。

而R22函式的實現來自Conway的著作《機器學習使用案例解析》,不同在於他用的是2個RMSE的比值來計算R2。

我們看到多項式次數為1的時候,雖然擬合的不太好,R2也能達到0.82。2次多項式提高到了0.88。而次數提高到100次,R2也只提高到了0.89。

2、過擬合

使用100次方多項式做擬合,效果確實是高了一些,然而該模型的據測能力卻極其差勁。

而且注意看多項式係數,出現了大量的大數值,甚至達到10的12次方。

這裡我們修改程式碼,將500個樣本中的最後2個從訓練集中移除。然而在測試中卻仍然測試所有500個樣本。

clf.fit(x[:498, np.newaxis], y[:498])

這樣修改後的多項式擬合結果如下:


[-0.17933531  1.0052037 ]
rmse=0.12, R2=0.85, R22=0.61, clf.score=0.85
[-0.01631935  0.01922011  0.99193521]
rmse=0.10, R2=0.90, R22=0.69, clf.score=0.90

...

rmse=0.21, R2=0.57, R22=0.34, clf.score=0.57

僅僅只是缺少了最後2個訓練樣本,紅線(100次方多項式擬合結果)的預測發生了劇烈的偏差,R2也急劇下降到0.57。

而反觀1,2次多項式的擬合結果,R2反而略微上升了。

這說明高次多項式過度擬合了訓練資料,包括其中大量的噪音,導致其完全喪失了對資料趨勢的預測能力。前面也看到,100次多項式擬合出的係數數值無比巨大。人們自然想到通過在擬合過程中限制這些係數數值的大小來避免生成這種畸形的擬合函式。

其基本原理是將擬合多項式的所有係數絕對值之和(L1正則化)或者平方和(L2正則化)加入到懲罰模型中,並指定一個懲罰力度因子w,來避免產生這種畸形係數。

這樣的思想應用在了嶺(Ridge)迴歸(使用L2正則化)、Lasso法(使用L1正則化)、彈性網(Elastic net,使用L1+L2正則化)等方法中,都能有效避免過擬合。更多原理可以參考相關資料。

下面以嶺迴歸為例看看100次多項式的擬合是否有效。將程式碼修改如下:

clf = Pipeline([('poly', PolynomialFeatures(degree=d)),
                    ('linear', linear_model.Ridge ())])
clf.fit(x[:400, np.newaxis], y[:400])

結果如下:


[ 0.          0.75873781]
rmse=0.15, R2=0.78, R22=0.53, clf.score=0.78
[ 0.          0.35936882  0.52392172]
rmse=0.11, R2=0.87, R22=0.64, clf.score=0.87
[  0.00000000e+00   2.63903249e-01   3.14973328e-01   2.43389461e-01
   1.67075328e-01   1.10674280e-01   7.30672237e-02   4.88605804e-02
   ......
   3.70018540e-11   2.93631291e-11   2.32992690e-11   1.84860002e-11
   1.46657377e-11]
rmse=0.10, R2=0.90, R22=0.68, clf.score=0.90

可以看到,100次多項式的係數引數變得很小。大部分都接近於0.

另外值得注意的是,使用嶺迴歸之類的懲罰模型後,1次和2次多項式迴歸的R2值可能會稍微低於基本線性迴歸。

然而這樣的模型,即使使用100次多項式,在訓練400個樣本,預測500個樣本的情況下不僅有更小的R2誤差,而且還具備優秀的預測能力。