1、正則化原理概述
1.1 正則化簡述
當(dāng)將線性回歸和邏輯回歸等模型應(yīng)用到某些特定的機(jī)器學(xué)習(xí)應(yīng)用時(shí),經(jīng)常會(huì)遇到過擬合 (over-fitting)的問題,可能會(huì)導(dǎo)致模型效果很差。 而正則化(regularization)則可以減少過擬合問題。
正則化項(xiàng)是結(jié)構(gòu)風(fēng)險(xiǎn)最小化策略的實(shí)現(xiàn),可以理解為是接在損失函數(shù)后的額外項(xiàng),可以看做是損失函數(shù)的懲罰項(xiàng),懲罰項(xiàng)對(duì)損失函數(shù)的某些參數(shù)進(jìn)行限制。簡單來說,正則化是一種為了減小測試誤差的行為(有時(shí)候會(huì)增加訓(xùn)練誤差)。使用正則化,降低模型的復(fù)雜度。
1.2 正則化類型
1.2.1 L1 正則化
L1 正則化通常稱為 Lasso 正則,公式為:

一般回歸分析中回歸w表示特征的系數(shù),從上式可以看到正則化項(xiàng)是對(duì)系數(shù)做了處理(限制)。L1正則化是指權(quán)值向量w中各個(gè)元素的絕對(duì)值之和,通常表示為∣∣w∣∣1。
一般會(huì)在正則化項(xiàng)之前添加一個(gè)系數(shù),一般用α表示,也用λ表示,這個(gè)系數(shù)需要自己指定。
L1正則化可以產(chǎn)生參數(shù)稀疏解,即讓系數(shù)等于0,假設(shè)L1正則化的損失函數(shù)為:

其中J0是原始的損失函數(shù),加號(hào)后面的一項(xiàng)是L1正則化項(xiàng),α是正則化系數(shù)。注意到L1正則化是權(quán)值的絕對(duì)值之和,J是帶有絕對(duì)值符號(hào)的函數(shù),因此J是不完全可微的。機(jī)器學(xué)習(xí)的任務(wù)就是要通過一些方法(比如梯度下降)求出損失函數(shù)的最小值。當(dāng)我們?cè)谠紦p失函數(shù)J0后添加L1正則化項(xiàng)時(shí),相當(dāng)于對(duì)J0做了一個(gè)約束。
如下圖所示:假設(shè)模型只有二個(gè)參數(shù),為w1和w2,L1正則化項(xiàng)α∣∣w∣∣1為圖中正方形部分,參數(shù)既要落在正方形部分,又要離損失函數(shù)最近,因此圖中與y軸相交點(diǎn)為稀疏解,因此L1可用于特征選擇,也可以防止過擬合。

正則化前面的系數(shù)α,可以控制L圖形的大小。α越小,L的圖形越大(下圖中的黑色方框);α越大,L的圖形就越小,可以小到黑色方框只超出原點(diǎn)范圍一點(diǎn)點(diǎn),這是最優(yōu)點(diǎn)的值(w1,w2)=(0,w)中的w可以取到很小的值。
1.2.2 L2 正則化
L2 正則化通常稱為嶺回歸,公式為:
?
由公式可見,L2正則化項(xiàng)是在損失函數(shù)式中加上α∣∣w∣∣2^2,L1正則化是指權(quán)值向量w中各個(gè)元素的平方和然后再求平方根。
假設(shè)L2正則化的損失函數(shù)為:

同樣可以畫出他們?cè)诙S平面上的圖形,如下:

二維平面下L2正則化的函數(shù)圖形是個(gè)圓,與方形相比,被磨去了棱角。因此J0與L相交時(shí)使得w1或w2等于零的機(jī)率小了許多,這就是為什么L2正則化不具有稀疏性的原因。
L2正則化可以防止模型過擬合(overfitting),擬合過程中通常都傾向于讓權(quán)值盡可能小,最后構(gòu)造一個(gè)所有參數(shù)都比較小的模型。因?yàn)橐话阏J(rèn)為參數(shù)值小的模型比較簡單,能適應(yīng)不同的數(shù)據(jù)集,也在一定程度上避免了過擬合現(xiàn)象。
1.3 正則化參數(shù)
1.3.1 L1參數(shù)
假設(shè)有如下帶L1正則化項(xiàng)的代價(jià)函數(shù):

其中x是要估計(jì)的參數(shù),相當(dāng)于上文中提到的w以及θ注意到L1正則化在某些位置是不可導(dǎo)的,當(dāng)λ足夠大時(shí)可以使得F(x)在x=0時(shí)取到最小值。
1.3.2 L2參數(shù)
λ越大,θj衰減得越快,λ越大,L2圓的半徑越小,最后求得損失函數(shù)最值時(shí)各參數(shù)也會(huì)變得很小。
2、sklearn代碼實(shí)現(xiàn)
2.1 多項(xiàng)式預(yù)測
# 導(dǎo)入所需的包
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import Ridge #在sklearn的linear_model下的Ridge類中已經(jīng)對(duì)L2進(jìn)行封裝
# 創(chuàng)建數(shù)據(jù)集
np.random.seed(42)
x = np.random.uniform(-3, 3, size=100)
X = x.reshape(-1, 1)
# y = 0.5x + 3并加入噪聲
noise = np.random.normal(0, 1,size=100)
noise = noise.reshape(-1, 1)
y = 0.5 * X + 3 + noise
np.random.seed(666)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
# 封裝多項(xiàng)式函數(shù),定義PipeLine
def PolynomialRegression(degree):
return Pipeline(
[
('poly', PolynomialFeatures(degree=degree)),
('std', StandardScaler()),
('lin_reg', LinearRegression())
]
)
# 畫出回歸模型預(yù)測值形成的模型曲線
def plot_model(model):
X_plot = np.linspace(-3, 3, 100).reshape(-1, 1)
y_plot = model.predict(X_plot)
plt.scatter(x, y)
plt.plot(X_plot[:, 0], y_plot, color='r')
plt.axis([-3, 3, 0, 6])
plt.show()
# 使用degree=20的多項(xiàng)式回歸
poly = PolynomialRegression(degree=20)
poly.fit(X_train, y_train)
y_test_predict = poly.predict(X_test)
mse = mean_squared_error(y_test, y_test_predict)
print('多項(xiàng)式回歸MSE:', mse)
plot_model(poly)
運(yùn)行結(jié)果:
多項(xiàng)式回歸MSE: 167.9401086729357

2.2 L2正則化
由上圖可見使用degree=20的多項(xiàng)式回歸,得到的模型必然是個(gè)過擬合的模型。下面使用L2進(jìn)行模型范化,對(duì)比結(jié)果。
# 使用L2正則化進(jìn)行模型范化
def RidgeRegression(degree, alpha):
return Pipeline(
[
('poly', PolynomialFeatures(degree=degree)),
('std', StandardScaler()),
('lin_reg', Ridge(alpha=alpha))
]
)
# 傳入一個(gè)alpha參數(shù),alpha=1
ridge1 = RidgeRegression(degree=20, alpha=1)
ridge1.fit(X_train, y_train)
y_test_predict = ridge1.predict(X_test)
mse = mean_squared_error(y_test_predict, y_test)
print('L2正則化后MSE:', mse)
plot_model(ridge1)
運(yùn)行結(jié)果:
L2正則化后MSE: 1.1888759304218448

使用L2對(duì)模型進(jìn)行正則化后的預(yù)測值的MSE可看出,模型的準(zhǔn)確度大幅提升,曲線平滑許多。
2.3 L1正則化
數(shù)據(jù)源取上面定義的數(shù)據(jù)集,測試L1正則化的效果。
# 使用L1正則化
from sklearn.linear_model import Lasso
def LassoRegression(degree, alpha):
return Pipeline(
[
('poly', PolynomialFeatures(degree=degree)),
('std', StandardScaler()),
('lin_reg', Lasso(alpha=alpha))
]
)
# 傳入一個(gè)alpha參數(shù),alpha=1
lasso1 = LassoRegression(20, 1)
lasso1.fit(X_train, y_train)
y_predict = lasso1.predict(X_test)
mse = mean_squared_error(y_predict, y_test)
print('L1正則化后MSE: ', mse)
plot_model(lasso1)
運(yùn)行結(jié)果:
L1正則化后MSE: 1.8408939659515595

由上圖可見,L1正則化系數(shù)過大造成模型欠擬合,下面調(diào)整正則化系數(shù),使用系數(shù)=0.01看看效果。
# 使用L1正則化
from sklearn.linear_model import Lasso
def LassoRegression(degree, alpha):
return Pipeline(
[
('poly', PolynomialFeatures(degree=degree)),
('std', StandardScaler()),
('lin_reg', Lasso(alpha=alpha))
]
)
# 傳入一個(gè)alpha參數(shù),alpha=0.01
lasso1 = LassoRegression(20, 0.01)
lasso1.fit(X_train, y_train)
y_predict = lasso1.predict(X_test)
mse = mean_squared_error(y_predict, y_test)
print('L1正則化后MSE: ', mse)
plot_model(lasso1)
運(yùn)行結(jié)果:
L1正則化后MSE: 1.1496080843259966

由上圖可見,模型準(zhǔn)確率已經(jīng)得到很大的提升了。因此得出正則化系數(shù)與Lasso回歸的關(guān)系。正則化系數(shù)越大,模型泛化能力越強(qiáng),正則化系數(shù)越小,泛化能力越弱。
?
正則化原理參考文章:https://blog.csdn.net/jinping_shi/article/details/52433975