Python數據科學:正則化方法
本文主要介紹,Python數據科學:正則化方法。正則化方法的出現,通過收縮方法(正則化方法)進行回歸。
正則化方法主要包括嶺回歸與LASSO回歸。
一、嶺回歸
嶺回歸通過人為加入的懲罰項(約束項),對回歸系數進行估計,為有偏估計。
有偏估計,允許估計有不大的偏度,以換取估計的誤差顯著減小,并在其殘差平方和為最小的原則下估計回歸系數。
通常嶺回歸方程中的R²會稍低于線性回歸分析,但回歸系數的顯著性往往明顯高于普通線性回歸。
這里不對相應的理論知識進行細說,說實話小F也是暈乎乎...
所以選擇先調包,看看效果是啥樣的。
使用機器學習框架scikit-learn進行嶺回歸參數的選擇(正則化系數)。
數據是書中的數據,已上傳網盤,公眾號回復「正則化」,即可獲取。
scikit-learn當中的模型不會默認對數據標準化,必須手動執行。
標準化后的數據可以消除量綱,讓每個變量的系數在一定意義下進行直接比較。
- import numpy as np
- import pandas as pd
- import matplotlib.pyplot as plt
- from sklearn.linear_model import Ridge
- from sklearn.linear_model import RidgeCV
- from sklearn.preprocessing import StandardScaler
- # 消除pandas輸出省略號情況及換行情況
- pd.set_option('display.max_columns', 500)
- pd.set_option('display.width', 1000)
- # 讀取數據,skipinitialspace:忽略分隔符后的空白
- df = pd.read_csv('creditcard_exp.csv', skipinitialspace=True)
- # 獲取信用卡有支出的行數據
- exp = df[df['avg_exp'].notnull()].copy().iloc[:, 2:].drop('age2', axis=1)
- # 獲取信用卡無支出的行數據,NaN
- exp_new = df[df['avg_exp'].isnull()].copy().iloc[:, 2:].drop('age2', axis=1)
- # 選擇4個連續變量,分別是年齡 收入 當地小區價格 當地人均收入
- continuous_xcols = ['Age', 'Income', 'dist_home_val', 'dist_avg_income']
- # 標準化
- scaler = StandardScaler()
- # 解釋變量,二維數組
- X = scaler.fit_transform(exp[continuous_xcols])
- # 被解釋變量,一維數組
- y = exp['avg_exp_ln']
- # 生成正則化系數
- alphas = np.logspace(-2, 3, 100, base=10)
- # 使用不同的正則化系數對模型進行交叉驗證
- rcv = RidgeCV(alphas=alphas, store_cv_values=True)
- # 使用數據集訓練(fit)
- rcv.fit(X, y)
- # 輸出最優參數,正則化系數及相應模型R²
- print('The best alpha is {}'.format(rcv.alpha_))
- print('The r-square is {}'.format(rcv.score(X, y)))
- # 訓練好后使用transform進行數據轉換
- X_new = scaler.transform(exp_new[continuous_xcols])
- # 使用模型對數據做預測
- print(np.exp(rcv.predict(X_new)[:5]))
輸出結果如下。
最優正則化系數為0.29,模型R²為0.475。
并使用最優正則化系數下的嶺回歸模型預測數據。
對不同正則化系數下模型的均方誤差進行可視化。
- # 正則化系數搜索空間當中每輪交叉驗證的結果,模型的均方誤差
- cv_values = rcv.cv_values_
- n_fold, n_alphas = cv_values.shape
- # 模型均方誤差上下波動值
- cv_mean = cv_values.mean(axis=0)
- cv_std = cv_values.std(axis=0)
- ub = cv_mean + cv_std / np.sqrt(n_fold)
- lb = cv_mean - cv_std / np.sqrt(n_fold)
- # 繪制折線圖,x軸是指數型形式
- plt.semilogx(alphas, cv_mean, label='mean_score')
- # y1(lb)和y2(ub)之間進行填充
- plt.fill_between(alphas, lb, ub, alpha=0.2)
- plt.xlabel('$\\alpha$')
- plt.ylabel('mean squared errors')
- plt.legend(loc='best')
- plt.show()
輸出結果如下。
發現正則化系數在40或50以下時,模型的均方誤差相差不大。
當系數超過該閾值時,均方誤差則快速上升。
所以正則化系數只要小于40或50,模型的擬合效果應該都不錯。
- 正則化系數越小則模型擬合越好,但過擬合情況也越容易發生。
- 正則化系數越大,則越不容易過擬合,但模型的偏差越大。
RidgeCV通過交叉驗證,可以快速返回“最優”的正則化系數。
當這只是基于數值計算的,可能最終結果并不符合業務邏輯。
比如本次模型的變量系數。
- # 輸出模型的變量系數
- print(rcv.coef_)
- # 輸出結果
- [ 0.03321449 -0.30956185 0.05551208 0.59067449]
發現收入的系數為負值,這肯定是不合理的。
下面通過嶺跡圖進行進一步分析。
嶺跡圖是在不同正則化系數下變量系數的軌跡。
- ridge = Ridge()
- coefs = []
- # 不同正則化系數下的變量系數
- for alpha in alphas:
- ridge.set_params(alpha=alpha)
- ridge.fit(X, y)
- coefs.append(ridge.coef_)
- # 繪制變量系數隨正則化系數變化的軌跡
- ax = plt.gca()
- ax.plot(alphas, coefs)
- ax.set_xscale('log')
- plt.xlabel('alpha')
- plt.ylabel('weights')
- plt.title('Ridge coefficients as a function of the regularization')
- plt.axis('tight')
- plt.show()
輸出結果。
- ①有兩個變量的系數在不同的正則化系數下都很接近于0,那么可以選擇刪除。
- ②正則化系數越大,對變量系數的懲罰越大,所有變量的系數都趨近于0。
- ③有一個變量的系數變化非常大(有正有負),說明該系數的方差大,存在共線性的情況。
綜合模型均方誤差和嶺跡圖的情況,選取正則化系數為40。
- 如果大于40,則模型均方誤差增大,模型擬合效果變差。
- 如果小于40,則變量系數不穩定,共線性沒有得到抑制。
那么就來看看,當正則化系數為40時,模型變量系數的情況。
- ridge.set_params(alpha=40)
- ridge.fit(X, y)
- # 輸出變量系數
- print(ridge.coef_)
- # 輸出模型R²
- print(ridge.score(X, y))
- # 預測數據
- print(np.exp(ridge.predict(X_new)[:5]))
- # 輸出結果
- [0.03293109 0.09907747 0.04976305 0.12101456]
- 0.4255673043353688
- [934.79025945 727.11042209 703.88143602 759.04342764 709.54172995]
發現變量系數都為正值,符合業務直覺。
收入和當地人均收入這兩個變量可以保留,另外兩個刪除。
二、LASSO回歸
LASSO回歸,在令回歸系數的絕對值之和小于一個常數的約束條件下,使殘差平方和最小化。
從而能夠產生某些嚴格等于0的回歸系數,得到解釋力較強的模型。
相比嶺回歸,LASSO回歸還可以進行變量篩選。
使用LassoCV交叉驗證確定最優的正則化系數。
- # 生成正則化系數
- lasso_alphas = np.logspace(-3, 0, 100, base=10)
- # 使用不同的正則化系數對模型進行交叉驗證
- lcv = LassoCV(alphas=lasso_alphas, cv=10)
- # 使用數據集訓練(fit)
- lcv.fit(X, y)
- # 輸出最優參數,正則化系數及相應模型R²
- print('The best alpha is {}'.format(lcv.alpha_))
- print('The r-square is {}'.format(lcv.score(X, y)))
- # 輸出結果
- The best alpha is 0.04037017258596556
- The r-square is 0.4426451069862233
發現最優的正則化系數為0.04,模型R²為0.443。
接下來獲取不同正則化系數下的變量系數軌跡。
- lasso = Lasso()
- lasso_coefs = []
- # 不同正則化系數下的變量系數
- for alpha in lasso_alphas:
- lasso.set_params(alpha=alpha)
- lasso.fit(X, y)
- lasso_coefs.append(lasso.coef_)
- # 繪制變量系數隨正則化系數變化的軌跡
- ax = plt.gca()
- ax.plot(lasso_alphas, lasso_coefs)
- ax.set_xscale('log')
- plt.xlabel('alpha')
- plt.ylabel('weights')
- plt.title('Lasso coefficients as a function of the regularization')
- plt.axis('tight')
- plt.show()
輸出結果。
發現隨著正則化系數的增大,所有變量的系數會在某一閾值突降為0。
其中緣由與LASSO回歸方程有關,不細說。
輸出LASSO回歸的變量系數。
- print(lcv.coef_)
- # 輸出結果
- [0. 0. 0.02789489 0.26549855]
發現前兩個變量被篩選掉了,即年齡和收入。
為啥和嶺回歸的結果不一樣呢???
三、總結
坑留的有點多,待小F慢慢填...