監督學習 | 線性迴歸 之正則線性模型原理及Sklearn實現


相關文章:

機器學習 | 目錄

機器學習 | 迴歸評估指標

機器學習 | 梯度下降原理及Python實現

監督學習 | 線性迴歸 之多元線性迴歸原理及Sklearn實現

監督學習 | 非線性迴歸 之多項式迴歸原理及Sklearn實現

監督學習 | 線性分類 之Logistic迴歸原理及Sklearn實現

1. 正則線性模型

在介紹正則線性模型(Regularized Linear Models)前,我們先來看一下一個例子,假設對於以下數據,我們分別使用多元線性迴歸和多項式迴歸進行擬合分類如下:

圖1 不同模型對數據的擬合

可以看到此時線性模型的錯誤分類點數爲2,而多項式迴歸模型的誤差爲0,因此此時計算機將會選擇第二個模型。但是這個模型有一個缺點,那就是過擬合了,但如何讓計算機避免過擬合呢,一個常見的方法就是對模型正則化,它擁有的自由度越低,就越不容易過度擬合。比如,將多項式模型正則化的簡單方法就是降低多項式的階數。

對線性模型來說,正則化通常通過約束模型的權重來實現。如剛纔的例子,如果我們爲模型的成本函數添加一個模型複雜度的話,就可以在挑選模型的時候考慮到模型的複雜度。

按照對模型複雜度的懲罰不同,我們有三種方法:嶺迴歸、套索迴歸和彈性網絡,分別對應三種正則化策略:L2 正則化、L1 正則化和 L1&L2 正則化。

p-範數:如果 X=[x1,x2,..,xn]X=[x_1,x_2,..,x_n] 那麼向量 x 的 p-範數就是:xp=(x1p+x2p++xnp)1p||x||_p=(|x_1|^p+|x_2|^p+\cdots+|x_n|^p)^{\frac{1}{p}} ,用得最多的還是 L1,L2L_1,L_2 範數:

L1L_1 範數:x1=(x1+x2++xn)||x||_1=(|x_1|+|x_2|+\cdots+|x_n|) ,即絕對值之和

L2L_2 範數:x2=(x12+x22++xn2)12||x||_2=(|x_1|^2+|x_2|^2+\cdots+|x_n|^2)^{\frac{1}{2}} ,即通常意義上的模

1.1 Ridge Regression(L2)

嶺迴歸(Ridge Regression,也叫作吉洪諾夫正則化)是線性迴歸的正則化版:在成本函數中添加一個等於 αi=1nθi2\alpha\sum_{i=1}^n\theta_i^2 的正則項。這使得學習中的算法不僅需要擬合數據,同時還要讓模型權重保持最小。

嶺迴歸模型成本函數:

(1)J(θ)=MSE(θ)+α12i=1nθi2J(\theta)=MSE(\theta)+\alpha\frac{1}{2}\sum_{i=1}^n\theta_i^2 \tag{1}

注意,正則項只能在訓練的時候添加到成本函數中,一旦訓練完成,就需要使用未經正則化的性能指標來評估模型性能。

超參數 α\alpha 控制的是對模型進行正則化的程度,如果 α=0\alpha=0 ,則嶺迴歸就是線性模型。如果 α\alpha 非常大,那麼所有的權重都非常接近於零,結果是一條穿過數據平均值的水平線。

注意,這裏偏置項 θ0\theta_0 沒有正則化。如果我們將 ww 定義爲特徵權重的向量(θ1\theta_1θn\theta_n),那麼正則項即正與 12(w2)2\frac{1}{2}(||w||_2)^2,其中 w2||w||_2 爲權重向量的 L2L_2 範數。而對於梯度下降,只需要在 MSEMSE 梯度向量上添加 αw\alpha w 即可。

在執行嶺迴歸之前,必須對數據進行縮放(例如使用 StandardScaler),因爲它對輸入特徵的大小非常敏感。大多數正則化模型都是如此。

與線性迴歸一樣,我們也可以在計算閉式方程或者執行梯度下降時,執行嶺迴歸。

閉式解的嶺迴歸:

(2)θ^=(XTX+αA)1XTy\hat{\theta}=(X^T\cdot X+\alpha A)^{-1}\cdot X^T \cdot y \tag{2}

其中 AA 是一個 n×nn \times n 的單位矩陣,除了左上單元格爲0,其他與偏置項對應。

下面是使用不同 α\alpha 值對某個線性數據進行訓練的幾種嶺迴歸模型,左邊直接對線性模型使用嶺迴歸(即對多元線性模型的成本函數添加模型複雜度),導致預測是線性的。而右邊,首先使用 PolynomialFeatures(degree=10) 對數據進行擴展(多項式迴歸),然後用 StandardScaler() 進行縮放,最後將嶺迴歸模型用於結果特徵:

圖2 不同 alpha 下的 嶺迴歸 與 多項式嶺迴歸

α\alpha 使得預測更加平坦,這降低了模型的方差,但是也提升了偏差。

代碼如下:

from sklearn.linear_model import Ridge, LinearRegression
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures, StandardScaler
import matplotlib.pyplot as plt

np.random.seed(42)
m = 20
X = 3 * np.random.rand(m, 1)
y = 1 + 0.5 * X + np.random.randn(m, 1) / 1.5
X_new = np.linspace(0, 3, 100).reshape(100, 1)

def plot_model(model_class, polynomial, alphas, **model_kargs):
    for alpha, style in zip(alphas, ("b-", "g--", "r:")):
        # 嶺迴歸如果alpha爲0,就變成了線性迴歸
        model = model_class(alpha, **model_kargs) if alpha > 0 else LinearRegression() 
        # 多項式嶺迴歸
        if polynomial:
            model = Pipeline([
                    ("poly_features", PolynomialFeatures(degree=10, include_bias=False)),
                    ("std_scaler", StandardScaler()),
                    ("regul_reg", model),
                ])
        model.fit(X, y)
        y_new_regul = model.predict(X_new)
        lw = 2 if alpha > 0 else 1
        plt.plot(X_new, y_new_regul, style, linewidth=lw, label=r"$\alpha = {}$".format(alpha))
    plt.plot(X, y, "b.", linewidth=3)
    plt.legend(loc="upper left", fontsize=15)
    plt.xlabel("$x_1$", fontsize=18)
    plt.axis([0, 3, 0, 4])

plt.figure(figsize=(8,4))
plt.subplot(121)
plot_model(Ridge, polynomial=False, alphas=(0, 10, 100), random_state=42)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.subplot(122)
plot_model(Ridge, polynomial=True, alphas=(0, 10**-5, 1), random_state=42)

plt.show()

1.1.1 Sklearn 實現

sklearn.linear_model.Ridge:

from sklearn.linear_model import Ridge

ridge_reg = Ridge(alpha=1.0, fit_intercept=True, normalize=False, copy_X=True, max_iter=None, tol=0.001, solver='auto', random_state=None)

ridge_reg.fit(X, y)
ridge_reg.predict([[X_pred]])
from sklearn.linear_model import Ridge

np.random.seed(42)
m = 20
X = 3 * np.random.rand(m, 1)
y = 1 + 0.5 * X + np.random.randn(m, 1) / 1.5

ridge_reg = Ridge(alpha=1, solver="cholesky", random_state=42)
ridge_reg.fit(X, y)
ridge_reg.predict([[1.5]])
array([[1.55071465]])
ridge_reg.intercept_, ridge_reg.coef_
(array([1.00650911]), array([[0.36280369]]))

與原迴歸模型 y=1+0.5×X+εy = 1 + 0.5 \times X + \varepsilon 很接近。


1.1.2 Ridge + SDG

利用隨機梯度下降來求解嶺迴歸。

1.1.2.1 Sklearn 實現

from sklearn.linear_model import SGDRegressor

ridge_sgd_reg = SGDRegressor(max_iter=50, tol=-np.infty, penalty="l2", random_state=42)
ridge_sgd_reg.fit(X, y.ravel())
ridge_sgd_reg.predict([[1.5]])
array([1.49905184])
ridge_sgd_reg.intercept_, ridge_sgd_reg.coef_
(array([0.63725132]), array([0.57453367]))

1.2 Lasso Regression(L1)

線性迴歸的另一種正則化,叫作最小絕對收縮和選擇算子迴歸(Least Absolute Shrinkage and Selection Operator Regression,簡稱Lasso 迴歸,或套索迴歸)。與嶺迴歸一樣,它也是像成本函數添加一個正則項,但是它增加的是權重向量的 L1L_1 範數,而不是 L2L_2 範數的平方的一半。

Lasso 迴歸成本函數:

(3)J(θ)=MSE(θ)+αi=1nθiJ(\theta)=MSE(\theta)+\alpha\sum_{i=1}^n|\theta_i| \tag{3}

圖 3 顯示內容與圖 2 相同,但是嶺迴歸模型換成了 Lasso 迴歸模型,同時 α\alpha 值較小。

Lasso 迴歸的一個重要特點是它傾向於完全消除掉最不重要特徵的權重(也就是將它們設置爲零)。例如,在圖 3 中右圖中的虛線(α=107\alpha=10^{-7})看起來像是二次的,快要接近於線性;因爲所有高階多項式的特徵權重的等於零。換句話說,Lasso 會回會自動執行特徵選擇並輸出一個係數模型(即只有很少的特徵有非零權重)。

圖3 不同 alpha 下的 Lasso 迴歸 與 多項式 Lasso 迴歸

代碼如下:

from sklearn.linear_model import Lasso

plt.figure(figsize=(8,4))
plt.subplot(121)
plot_model(Lasso, polynomial=False, alphas=(0, 0.1, 1), random_state=42)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.subplot(122)
plot_model(Lasso, polynomial=True, alphas=(0, 10**-7, 1), tol=1, random_state=42)

plt.show()

[外鏈圖片轉存失敗(img-rtHntb2V-1566830619833)(output_18_0.png)]

1.2.1 Sklearn 實現

sklearn.linear_model.Lasso:

from sklearn.linear_model import Lasso

lasso_reg = Lasso(alpha=1.0, fit_intercept=True, normalize=False, precompute=False, copy_X=True, max_iter=1000, tol=0.0001, warm_start=False, positive=False, random_state=None, selection='cyclic')
lasso_reg.fit(X, y)
lasso_reg.predict([[X_pred]])
from sklearn.linear_model import Lasso
lasso_reg = Lasso(alpha=0.1)
lasso_reg.fit(X, y)
lasso_reg.predict([[1.5]])
array([1.53788174])
lasso_reg.intercept_, lasso_reg.coef_
(array([1.14537356]), array([0.26167212]))

1.2.2 Lasso + SGD

利用隨機梯度下降來求解 Lasso 迴歸,當 θi=0(i=1,2, ,n)\theta_i=0(i=1,2,\cdots,n) ,Lasso 成本函數是不可微的。但是,當任意 θi=0\theta_i=0 時,可以使用次梯度向量 gg 作爲替代,依舊可以讓梯度下降正常運轉。

LassoLasso 迴歸次梯度向量:

(4)g(θ,J)=θMSE(θ)+α(sign(θ1)sign(θ2)sign(θn))sign(θ1)={1(θi<0)0(θi=0)+1(θi>0) g(\theta, J)=\nabla_{\theta} \operatorname{MSE}(\theta)+\alpha\left(\begin{array}{c}{\operatorname{sign}\left(\theta_{1}\right)} \\ {\operatorname{sign}\left(\theta_{2}\right)} \\ {\vdots} \\ {\operatorname{sign}\left(\theta_{n}\right)}\end{array}\right) 當sign(\theta_1)=\left\{ \begin{aligned} -1 \quad (\theta_i<0) \\ 0 \quad (\theta_i=0) \\ +1 \quad (\theta_i>0) \\ \end{aligned} \right.\tag{4}

1.2.2.1 Sklearn 實現

from sklearn.linear_model import SGDRegressor

lasso_sgd_reg = SGDRegressor(max_iter=50, tol=-np.infty, penalty="l1", random_state=42)
lasso_sgd_reg.fit(X, y.ravel())
lasso_sgd_reg.predict([[1.5]])
array([1.49903849])
lasso_sgd_reg.intercept_, lasso_sgd_reg.coef_
(array([0.63727982]), array([0.57450578]))

1.3 Elastic Net(L1&L2)

彈性網絡是嶺迴歸與 Lasso 迴歸之間的中間地帶。其正則項就是嶺迴歸和 Lasso 迴歸的正則項的混合混合比例通過 rr (L1_ratio)來控制。當 r=0r=0 時,彈性網絡即等同於嶺迴歸,而當 r=1r=1 時,即相當於 Lasso 迴歸。

彈性網絡成本函數:

(5)J(θ)=MSE(θ)+rαi=1nθi+1r2αi=1nθinJ(\theta)=MSE(\theta)+r\alpha \sum_{i=1}^n|\theta_i|+\frac{1-r}{2}\alpha\sum_{i=1}^n \theta_i^n \tag{5}

1.3.1 Sklearn 實現

sklearn.linear_model.ElasticNet:

from sklearn.linear_model import ElasticNet

elastic_net = ElasticNet(alpha=1.0, l1_ratio=0.5, fit_intercept=True, normalize=False, precompute=False, max_iter=1000, copy_X=True, tol=0.0001, warm_start=False, positive=False, random_state=None, selection='cyclic')[source]

elastic_net.fit(X, y)
elastic_net.predict([[X_pred]])
from sklearn.linear_model import ElasticNet
elastic_net = ElasticNet(alpha=0.1, l1_ratio=0.5, random_state=42)
elastic_net.fit(X, y)
elastic_net.predict([[1.5]])
array([1.54333232])
elastic_net.intercept_, elastic_net.coef_
(array([1.08639303]), array([0.30462619]))

1.4 正則線性模型選擇

應該如何選擇線性、嶺迴歸、Lasso 迴歸和彈性網絡呢?通常來說,有正則化——哪怕是很小,總是比沒有更可取一些。所以大多數情況下,應該避免使用純線性迴歸。

嶺迴歸是個不錯的默認選擇,但是如果覺得實際用到的特徵只有少數幾個,那就應該更傾向於 Lasso 迴歸或是彈性網絡,因爲它們會將無用特徵的權重降爲零。

一般而言,彈性網絡優於 Lasso 迴歸,因爲當特徵數量超過訓練實例數量,又或者是幾個特徵強相關時,Lasso 迴歸的表現可能非常不穩定。[1]

參考資料

[1] Aurelien Geron, 王靜源, 賈瑋, 邊蕤, 邱俊濤. 機器學習實戰:基於 Scikit-Learn 和 TensorFlow[M]. 北京: 機械工業出版社, 2018: 121-127.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章