在線性回歸問題中比較常用的一種算法就是最小二乘法(OLS),其核心思想是:通過最小化誤差的平方和尋找數據的最佳函數匹配。
但是普通的OLS最常見的一個問題是容易過度擬合:即在樣本數據集上屬性值(x)和目標值(y)是一一對應的。這樣的結果看似擬合效果
很好,但是在新數據集上的誤差卻會很大。
解決這個問題,目前主要有兩種思路:前向逐步回歸和懲罰線性回歸。之所以說是兩種思路,而不是兩種算法,是因為以這兩種思想
為基礎,形成了兩種算法族,尤其是后者有多種較出名的算法(例如嶺回歸、套索回歸、最小角度回歸、Glmnet等)。
前向逐步回歸基本算法思路:遍歷屬性中的每一列,找到均方誤差(MSE)之和最小的一列(即效果最佳的列),然后尋找和這列組合效果
最好的第二列屬性,依次類推直到所有的列。在這個過程中MSE--屬性個數在坐標系中行成的曲線會有明顯的變化,可以通過觀察曲線得到
想要的結果,或者通過打印出來的MES值獲得最終結果。
懲罰線性回歸基本算法思路:在普通最小二乘法的公式中添加一個懲罰項。如果最小二乘法以下面的數學公式表達:
,那么套索(Lasso)回歸的公式為:
.其中,α||W||=α(|w1|+|w2|+...+|Wn|)。
Lasso通過構造一個懲罰函數得到一個較為精煉的模型,使得它壓縮一些系數,同時設定一些系數為零,也就是說Lasso的系數向量是稀疏的。
Lasso是采用的L1范數正則化(OLS在變量選擇方面的三種擴展方法中的一種,也叫收縮方法): L1范數是指向量中各個元素絕對值之和。
上面說了關於模型的問題,下面說說模型評估。
目前主要的模型性能評估方法也有兩種:預留測試集和n折交叉驗證。
預留測試集就是把樣本數據分成兩類:一類用於訓練模型,另一類用於測試模型。一般情況下測試集可以占所有數據的25%~35%。
n折交叉驗證就是把數據分成n份不相交的子集,以其中的一份作為測試集,另外n-1份作為訓練集。假如把數據分成5份,依次編號1~5,第一次把1號作為測試集,2、3、4、5號作為訓練集,第二次把2號作為測試集,1、3、4、5作為訓練集,依次類推,直到結束。
這里的功能核心是:sklearn.linear_model.LassoCV
LassoCV參數有很多,我們只用用到參數cv:表示使用幾折交叉驗證。
重點是介紹下相關屬性:
alpha_: 通過交叉驗證后得到的處罰系數,即公式中的α值
coef_: 參數向量(公式中的w)
mse_path_: 每次交叉驗證的均方誤差
alphas_: 驗證過程中使用過的alpha值
本次測試相關的理論基礎大概就這么多,下面開始實驗:數據來源
import numpy as np import matplotlib.pyplot as plt from sklearn import linear_model from sklearn.linear_model import LassoCV import os ##運行腳本所在目錄 base_dir=os.getcwd() data=np.loadtxt(base_dir+r"\wine.txt",delimiter=";") ##矩陣的長度:行數 dataLen = len(data) ##矩陣的寬度:列數 dataWid = len(data[0]) ##每列的均值 xMeans = [] ##每列的方差 xSD = [] ##歸一化樣本集 xNorm = [] ##歸一化標簽 lableNorm = [] ##第一次處理數據:計算每列的均值和方差 for j in range(dataWid): ##讀取每列的值 x = [data[i][j] for i in range(dataLen)] ##每列的均值 mean = np.mean(x) xMeans.append(mean) ##每列的方差 sd = np.std(x) xSD.append(sd) ##第二次處理數據:歸一化樣本集和標簽 for j in range(dataLen): ##樣本集歸一化 xn = [(data[j][i]-xMeans[i])/xSD[i] for i in range(dataWid-1)] xNorm.append(xn) ##標簽歸一化 ln = (data[j][dataWid-1]-xMeans[dataWid-1])/xSD[dataWid-1] lableNorm.append(ln) ##參數格式是數組形式,所以需要轉換一下 X=np.array(xNorm) Y=np.array(lableNorm) ##開始做交叉驗證:cv=10表示采用10折交叉驗證 wineModel = LassoCV(cv=10).fit(X,Y) ##打印出最佳解的每項的系數:[ 0,-0.22773828,0,0,-0.09423888, ##0.02215153,-0.09903605,0,-0.06787363,0.16804092,0.3750958 ] print(wineModel.coef_) ##打印出最佳解的懲罰系數:0.013561387701 print(wineModel.alpha_) ##繪圖 plt.figure() ##隨着alpha值的變化,均方誤差的變化曲線 plt.plot(wineModel.alphas_, wineModel.mse_path_, ':') ##驗證過程中,隨着alpha值的變化,均方誤差的平均曲線 plt.plot(wineModel.alphas_, wineModel.mse_path_.mean(axis=-1), label='Average MSE Across Folds', linewidth=2) ##每次驗證系統認為的最合適的alpha值 plt.axvline(wineModel.alpha_, linestyle='--', label='CV Estimate of Best alpha') plt.semilogx() plt.legend() ax = plt.gca() ax.invert_xaxis() plt.xlabel('alpha') plt.ylabel('Mean Square Error') plt.axis('tight') plt.show()
最佳解的懲罰系數和向量系數已經在代碼中以注釋的方式寫了,生成的結果圖如下:

