線性模型

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import mglearn
from sklearn.model_selection import train_test_split

1.用於回歸的線性模型

對於回歸問題,線性模型預測的一般公式如下:

y = w[0]x[0]+w[1]x[1]+…+w[p]*x[p]+b

這裡x[0]到x[p]表示單個數據點的特徵(本例中特徵個數為p+1),w和b是學習模型的參數,yᨈ是模型的預測結果。對於單一特徵的數據集,公式如下:

y = w[0]*x[0]+b

這就是高中數學裡的直線方程。這裡w[0]是斜率,b是y軸偏移。對於有更多特徵的數據集,w包含沿沿每個特徵坐標軸的斜率。也可以將預測的響應值看作輸入特徵的加權求和,權重由w的元素給出(可以取負值)。

下列程式碼可以在一維wave數據集上學習參數w[0]和b

mglearn.plots.plot_linear_regression_wave()
w[0]: 0.393906  b: -0.031804

用於回歸的線性模型可以表示為這樣的回歸模型:對單一特徵的預測結果是一條直線,兩個特徵時是一個平面,或者在更高維度(即更多特徵)時是一個超平面

如果將直線的預測結果與KNeighborsRegressor 的預測結果相比較,會發現直線的預測能力非常受限。似乎數據的所有細節都丟失了。從某種意義上講,這種說法是正確的。假設目標y是特徵的線性組合,這是一個非常強(也有點不現實的)假設。但觀察一維數據得出的觀點有些片面。對於有多個特徵的數據集而言,線性模型可以非常強大。特別地,如何特徵數量大於訓練數據點的數量,任何目標y都可以在(訓練集上)用線性函數完美擬合。

2.線性回歸(普通最小二乘法)

線性回歸,或者普通最小二乘法(ordinary least squares,OLS),是回歸問題最簡單也最經典的線性方法。線性回歸尋找參數w和b,使得對訓練集的預測值與真實的目標值y之間的均方誤差最小。均方誤差(mean squared error)是預測值與真實值之差的平方和除以樣本數。線性回歸沒有參數,這是一個優點,但也因此無法控制模型的複雜度。

下列程式碼構建一個線性模型

from sklearn.linear_model import LinearRegression
X, y = mglearn.datasets.make_wave(n_samples=60)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

lr = LinearRegression().fit(X_train, y_train)

「斜率」參數(w,也叫作權重或係數)被保存在coef_屬性中,而偏移或截距(b)被保存在intercept_屬性中:

print("lr_coef_: {}".format(lr.coef_))
print("lr_intercept_: {}".format(lr.intercept_))
lr_coef_: [0.39390555]
lr_intercept_: -0.031804343026759746

intercept_屬性是一個浮點數,而coef_屬性是一個NumPy數組,每個元素對應一個輸入特徵。由於wave數據集中只有一個輸入特徵,所以lr.coef_中只有一個元素

檢測一下訓練集和測試集的性能:

print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lr.score(X_test, y_test)))
Training set score: 0.67
Test set score: 0.66

R^2約為0.66,這個結果不是很好,但我們注意到,訓練集和測試集上的分數非常接近。這說明可能存在欠擬合,而不是過擬合。對於一個一維數據集來說,過擬合的風險很小,因為模型非常簡單(或受限)。然而,對於更高維的數據集(即有大量特徵的數據集),線性模型將變得更加強大,過擬合的可能性也會變大。我們來看一下LinearRegression在更複雜的數據集上的表現,比如波士頓房價數據集。這個數據集有506個樣本和105個導出特徵。

X, y = mglearn.datasets.load_extended_boston()

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
lr = LinearRegression().fit(X_train, y_train)

比較一下訓練集和測試集的分數可以發現,在訓練集上的預測結果非常準確,但測試集上的R^2要低很多:

print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lr.score(X_test, y_test)))
Training set score: 0.95
Test set score: 0.61

訓練集和測試集之間的性能差異是過擬合的明顯標誌,因此我們應該試圖找到一個可以控制複雜度的模型。標準線性回歸最常用的替代方法之一就是嶺回歸(ridge regression)

3.嶺回歸

嶺回歸也是一種用於回歸的線性模型,因此它的預測公式與普通最小二乘法相同。但在嶺回歸中,對係數(w)的選擇不僅要在訓練數據上得到好的預測結果,而且還要擬合附加約束。我們還希望係數盡量小,換句話說,w的所有元素都應該接近於0。直觀上來看,這意味著每個特徵對輸出的影響儘可能小(即斜率很小),同時仍給出很好的預測結果,這種約束是所謂正則化(regularization)的一個例子。正則化是指對模型做顯式約束,以避免過擬合。嶺回歸用到的這種被稱為L2正則化

從數學的觀點來看,Ridge懲罰了係數的L2範數或w的歐式長度。

嶺回歸在linear_model.Ridge中實現。

from sklearn.linear_model import Ridge

ridge = Ridge().fit(X_train, y_train)
print("Training set score: {:.2f}".format(ridge.score(X_train, y_train)))
print("Test set score: {:.2f}".format(ridge.score(X_test, y_test)))
Training set score: 0.89
Test set score: 0.75

可以看出,Ridge在訓練集上的分數要低於LinearRegression,但在測試集上的分數 更高 。這和我們的預期一致。線性回歸對數據存在過擬合。Ridge是一種約束更強的模型,所以更不容易過擬合。複雜度更小的模型意味著在訓練集上的性能更差,但泛化性能更好。由於我們只對泛化性能感興趣,所以應該選擇Ridge模型而不是LinearRegression模型。

Ridge模型在模型的簡單性(係數都接近於0)與訓練集性能之間做出權衡。簡單性和訓練集性能二者對於模型的重要程度可以通過設置alpha參數來指定。在前面的例子中,我們用的是默認參數alpha=1.0,但沒有理由認為這會給出最佳權衡。alpha的最佳設定值取決於具體數據集。增大alpha會使得係數更加趨向於0,從而降低訓練集性能,但可能會提高泛化性能。例如:

ridge10 = Ridge(alpha=10).fit(X_train, y_train)
print("Training set score: {:.2f}".format(ridge10.score(X_train, y_train)))
print("Test set score: {:.2f}".format(ridge10.score(X_test, y_test)))
Training set score: 0.79
Test set score: 0.64

減小alpha可以讓係數受到的限制更小,對於非常小的alpha值,係數幾乎沒有受到限制,我們得到一個與LinearRegression類似的模型:

ridge01 = Ridge(alpha=0.1).fit(X_train, y_train)
print("Training set score: {:.2f}".format(ridge01.score(X_train, y_train)))
print("Test set score: {:.2f}".format(ridge01.score(X_test, y_test)))
Training set score: 0.93
Test set score: 0.77

可以查看alpha取不同值時模型的coef_屬性,從而更加定性的理解alpha參數是如何改變模型的。更大的alpha表示約束更強的模型,所以我預計大alpha對應的coef_元素比小alpha對應的coef_元素要小。

plt.plot(ridge.coef_, 's', label='Ridge alpha=1')
plt.plot(ridge10.coef_, '^', label='Ridge alpha=10')
plt.plot(ridge01.coef_, 'v', label='Ridge alpha=0.1')

plt.plot(lr.coef_, 'o', label='LinearRegression')
plt.xlabel('Coefficient index')
plt.ylabel('Coefficient magnitude')
plt.hlines(0, 0, len(lr.coef_))
plt.ylim(-25, 25)
plt.legend()

x軸對應coef_的元素:x=0對應第一個特徵的係數,x=1對應第二個特徵的係數,以此類推,一直到x=100。y軸表示該係數的具體數值。對於alpha=10,係數大多在-3到3之間。對於alpha=1的ridge模型,係數稍大一些。對於alpha=0.1,點的範圍更大。對於沒有做正則化的線性回歸(即alpha=0),點的範圍更大,許多點超出了影像的範圍。

還有一種方法可以用來理解正則化的影響,就是固定alpha值,但改變訓練數據量。對波士頓房價數據集做二次抽樣,並在數據量逐漸增加的數據集上分別對LinearRegression和Ridge(alpha=1)兩個模型進行評估(將模型大小作為數據集大小的函數進行繪圖,這樣的影像叫作學習曲線):

mglearn.plots.plot_ridge_n_samples()

如上圖所示,無論是嶺回歸還是線性回歸,所有數據集大小對應的訓練分數都要高於測試分數。由於嶺回歸是正則化的,因此它的訓練分數要整體低於線性回歸的訓練分數。但嶺回歸的測試分數要更高,特別是對較小的子數據集。如果少於400個數據點,線性模型學不到任何內容。隨著模型可用的數據越來越多,兩個模型的測試集性能開始提升,最終線性模型的性能追上了嶺回歸。這裡要注意的是,如果有足夠多的訓練數據,正則化變得不那麼重要,並且嶺回歸和線性回歸具有相同的測試集性能。從圖中還可以看出線性回歸的訓練性能在下降。如果添加更多數據,模型將更加難以過擬合或記住所有的數據。

4. lasso

除了Ridge,還有一種正則化的線性回歸是Lasso。與嶺回歸相同,使用Lasso也是約束係數使其接近於0,但用到的方法不同,叫作L1正則化。L1正則化的結果是,使用Lasso時某些係數剛好為0。這說明某些特徵被模型完全忽略。這可以看作是一種自動化的特徵選擇。某些係數剛好為0,這樣模型更容易解釋,也可以呈現模型最重要的特徵。

Lasso懲罰係數向量的L1範數,換句話說,係數的絕對值之和

將Lasso應用在拓展的波士頓房價數據集上:

from sklearn.linear_model import Lasso

lasso = Lasso().fit(X_train, y_train)
print("Training set score: {:.2f}".format(lasso.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lasso.score(X_test, y_test)))
print("Numbor of feayures used: {}".format(np.count_nonzero(lasso.coef_)))
Training set score: 0.29
Test set score: 0.21
Numbor of feayures used: 4

可以看出,Lasso在訓練集與測試集上的表現都很差。這表示存在欠擬合,我們發現模型只用到了105個特徵中的4個。與Ridge類似,Lasso也有一個正則化參數alpha,可以控制係數趨向於0的強度。Lasso()類中默認值alpha=1。為了降低欠擬合,我們嘗試減小alpha。這麼做的同時,我們還需要增加max_iter的值(運行迭代的最大次數):

# 我們增大max_iter的值,否則模型會警告我們,說應該增大max_iter
lasso001 = Lasso(alpha=0.01, max_iter=100000).fit(X_train, y_train)

print("Training set score: {:.2f}".format(lasso001.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lasso001.score(X_test, y_test)))
print("Numbor of feayures used: {}".format(np.count_nonzero(lasso001.coef_)))
Training set score: 0.90
Test set score: 0.77
Numbor of feayures used: 33

alpha值變小,我們可以擬合一個更複雜的模型,在訓練集和測試集上的表現也更好。模型性能比使用Ridge時略好一點,而且我們只用到了105個特徵中的33個。

但如果把alpha設得太小,就會消除正則化的效果,並出現過擬合,得到與LinearRegression類似的結果:

lasso00001 = Lasso(alpha=0.0001, max_iter=100000).fit(X_train, y_train)

print("Training set score: {:.2f}".format(lasso00001.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lasso00001.score(X_test, y_test)))
print("Numbor of feayures used: {}".format(np.count_nonzero(lasso00001.coef_)))
Training set score: 0.95
Test set score: 0.64
Numbor of feayures used: 94

對不同係數的模型進行作圖

plt.plot(lasso.coef_, 's', label='Lasso alpha=1')
plt.plot(lasso001.coef_, '^', label='Lasso alpha=0.01')
plt.plot(lasso00001.coef_, 'v', label='Lasso alpha=0.0001')

plt.plot(ridge01.coef_, 'o', label='Ridge alpha=0.1')
plt.legend(ncol=2, loc=(0, 1.05))
plt.ylim(-25, 25)
plt.xlabel('Coefficient index')
plt.ylabel('Coefficient magnitude')
Text(0,0.5,'Coefficient magnitude')

在alpha=1時,Lasso回歸不僅大部分係數為0,而且其他係數也都很小。將alpha減小至0.01,我們得到圖中向上的三角形,大部分特徵等於0,alpha=0.0001時,我們得到正則化很弱的模型,大部分係數都不為0,並且還很大。為了便於比較,圖中用圓形表示Ridge的最佳結果。alpha=0.1的Ridge模型的預測性能與alpha=0.01的Lasso模型類似,但Ridge模型的所有係數都不為0.

在實踐中,兩個正則化模型首選嶺回歸。但如果特徵很多,你認為只有其中幾個是重要的,那麼選擇Lasso可能更好。同樣,如果你想要一個容易解釋的模型,Lasso可以給出更容易理解的模型,因為它只選擇了一部分輸入特徵。scikit-learn還提供了ElasticNet類,結合了Lasso和Ridge的懲罰項。在實踐中,這種結合的效果最好,不過代價是要調節兩個參數,一個用於L1正則化,一個用於L2正則化。

5. 用於分類的線性模型

線性模型也廣泛用於分類問題。我們首先來看二分類。這時可以利用下面的公式進行預測:

y = w[0] * x[0] + w[1] * x[1] + … + w[p] * x[p] + b > 0

看起來與線性回歸的公式非常相似,但我們沒有返回特徵的加權求和,而是為預測設置了閾值(0)。如果函數值小於0,我們就預測類別-1,如果函數值大於0,我們就預測類別+1。對於所有用於分類的線性模型,這個預測規則都是通用的。同樣,有很多種不同的方法來找出係數(w)和截距(b)。

對於用於回歸的線性模型,輸出y是特徵的線性函數,是直線、平面或超平面。對於用於分類的線性模型,決策邊界是輸入的線性函數。換句話說,(二元)線性分類器是利用直線、平面或超平面來分開兩個類別的分類器。

學習線性模型有很多種演算法。這些演算法的區別在於以下兩點:

  • 係數和截距的特定組合對訓練數據擬合好壞的度量方法;
  • 是否使用正則化,以及使用哪種正則化方法。

不同的演算法使用不同的方法來度量「對訓練集擬合好壞」。由於數學上的技術原因,不可能調節w和b使得演算法產生的誤分類最少。對於我們的目的,以及許多應用而言,上面第一點(稱為損失函數)的選擇並不重要。

最常見的兩種線性分類演算法是Logistic 回歸(logistic regression)和線性支援向量機(linear support vector machine,簡稱SVM),前者在linear_model.LogisticRegression中實現,後者在svm.LinearSVC(SVC代表支援向量分類器)中實現。

下列程式碼將LogisticRegression和LinearSVC模型應用到forge數據集上,並將線性模型找到的決策邊界可視化:

from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC

X, y = mglearn.datasets.make_forge()

fig, axes = plt.subplots(1, 2, figsize=(10, 3))

for model, ax in zip([LinearSVC(), LogisticRegression()], axes):
    clf = model.fit(X, y)
    mglearn.plots.plot_2d_separator(clf, X, fill=False, eps=0.5, ax=ax, alpha=.7)
    mglearn.discrete_scatter(X[:, 0], X[:, 1], y, ax=ax)
    ax.set_title("{}".format(clf.__class__.__name__))
    ax.set_xlabel("Feature 0")
    ax.set_ylabel("Feature 1")
axes[0].legend()

在上圖中,forge數據集的第一個特徵位於x軸,第二個特徵位於y軸,圖中分別展示了LinearSVC和LogisticRegression得到的決策邊界,都是直線,將頂部歸為類別1的區域與底部歸為類別0的區域分開了。

兩個模型得到了相似的決策邊界。兩個模型中都有兩個點是分類錯誤的,默認使用L2正則化。

對於LogisticRegression和LinearSVC,決定正則化強度的權衡參數叫作C。C值越大,對應的正則化越弱。
參數C的還有一個作用:較小的C值可以讓演算法盡量適應「大多數」數據點,而較大的C值更強調每個數據點都分類正確的準確性。下面使用LinearSVC的圖示:

mglearn.plots.plot_linear_svc_regularization()

在左側的圖中,C值很小,對應強正則化。大部分屬於類別0的點位於底部,大部分屬於類別1的點位於頂部。強正則化項的模型會選擇一條相對水平的線,有兩個點分類錯誤。中間圖C值稍大,模型更關注兩個分類錯誤的樣本,使決策邊界的斜率的絕對值變大。最後,在右側的圖中,模型的C值非常大,使得決策邊界斜率的絕對值也很大,對類別0的所有點都分類正確。類別1仍有一個點分類錯誤,這是因為對整個數據集來說,不可能用一條直線將所有點正確分類。右側圖中的模型儘可能使所有點的分類都正確,但可能無法學習到類別的整體分布。(很可能過擬合)

與回歸的情況類似,用於分類的線性模型在低維空間看起來非常受限,決策邊界只能是直線或平面。同樣,在高維空間中,用於分類的線性模型變得非常強大,當考慮更多特徵時,避免過擬合變得越來越重要。

下面程式碼使用乳腺癌數據集詳細分析LogisticRegression:

from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=42)
logreg = LogisticRegression().fit(X_train, y_train)
print("Training set socre: {:.3f}".format(logreg.score(X_train, y_train)))
print("Test set socre: {:.3f}".format(logreg.score(X_test, y_test)))
Training set socre: 0.955
Test set socre: 0.958

C=1時的默認值給出了相當好的性能,在訓練接和測試集都達到了近96%的精度。但由於訓練接和測試集的性能非常接近,所以模型很可能是欠擬合的。我們嘗試增大C來擬合一個更複雜的模型:

logreg100 = LogisticRegression(C=100).fit(X_train, y_train)
print("Training set socre: {:.3f}".format(logreg100.score(X_train, y_train)))
print("Test set socre: {:.3f}".format(logreg100.score(X_test, y_test)))
Training set socre: 0.972
Test set socre: 0.965

使用C=100可以得到更高的訓練集精度,也得到了稍高的測試集精度,這也證實了我們的直覺,即更複雜的模型應該性能更好。

我們還可以研究使用正則化更強的模型時會發生什麼。設置C=0.01:

logreg001 = LogisticRegression(C=0.01).fit(X_train, y_train)
print("Training set socre: {:.3f}".format(logreg001.score(X_train, y_train)))
print("Test set socre: {:.3f}".format(logreg001.score(X_test, y_test)))
Training set socre: 0.934
Test set socre: 0.930

我們可以發現將默認已經欠擬合的模型更加欠擬合,訓練接和測試集精度比採用默認參數時更小。

看一下正則化參數C取三個不同值時模型學到的係數:

plt.plot(logreg.coef_.T, 'o', label="C=1")
plt.plot(logreg100.coef_.T, '^', label="C=100")
plt.plot(logreg001.coef_.T, 'v', label="C=0.01")
plt.xticks(range(cancer.data.shape[1]), cancer.feature_names, rotation=90)
plt.hlines(0, 0, cancer.data.shape[1])
plt.ylim(-5, 5)
plt.xlabel('Coefficient index')
plt.ylabel('coefficient magnitude')
plt.legend()

LogisticRegression默認使用L2正則化。更強的正則化使得係數更趨向於0,但係數永遠不會正好等於0.進一步觀察影像,還可以在第三個係數那裡發現有趣之處,這個係數是「平均周長」(mean perimeter)。C=100和C=1時,這個係數為負,而C=0.01時這個係數為正,係數可以告訴我們某個特徵與哪個類別有關。例如,人們可能會認為高「紋理錯誤」(texture error)特徵與「惡性」樣本有關。但「平均周長」係數的正負號發生變化,說明較大的「平均周長」可以被當作「良性」或「惡性」的指標,具體取決於我們考慮的是哪個模型。這樣說明,對線性模型的解釋應該持保留態度。

如果想要一個可解釋性強的模型,使用L1正則化可能更好,因為它約束模型只使用少數幾個特徵。下面是使用L1正則化的係數影像和分類精度:

for C, marker in zip([0.01, 1, 100], ['o', '^', 'v']):
    logreg_l1 = LogisticRegression(C=C, penalty="l1").fit(X_train, y_train)
    print("Training accuracy of l1 logreg with C={:.3f}: {:.2f}".format(C, logreg_l1.score(X_train, y_train)))
    print("Test accuracy of l1 logreg with C={:.3f}: {:.2f}".format(C, logreg_l1.score(X_test, y_test)))

    plt.plot(logreg_l1.coef_.T, marker, label="C={:.3f}".format(C))
plt.xticks(range(cancer.data.shape[1]), cancer.feature_names, rotation=90)
plt.hlines(0, 0, cancer.data.shape[1])
plt.xlabel("Coefficient index")
plt.ylabel("Coefficient magnitude")
plt.ylim(-5, 5)
plt.legend(loc=3)
Training accuracy of l1 logreg with C=0.010: 0.92
Test accuracy of l1 logreg with C=0.010: 0.93
Training accuracy of l1 logreg with C=1.000: 0.96
Test accuracy of l1 logreg with C=1.000: 0.96
Training accuracy of l1 logreg with C=100.000: 0.99
Test accuracy of l1 logreg with C=100.000: 0.98

如上圖所示,用於分類的線性模型與用於回歸的線性模型有許多相似之處。與用於回歸的線性模型一樣,模型的主要差別在於penalty參數,這個參數會影響正則化,也會影響模型時使用所有特徵還是只選擇特徵的一個子集。

6.用於多分類的線性模型

許多線性分類模型只適用於二分類問題,不能輕易的推廣到多分類問題(除了Logistic回歸)。將二分類方法推廣到多分類的一種常見方法是「一對其餘」(one-vs-rest)方法。在「一對其餘」方法中,對每個類別都學習一個二分類模型,將這個類別與其他類別盡量分開,這樣就生成了與類別個數一樣多的二分類模型。在測試點上運行所有二分類分類器來進行預測。在在對應類別上分數最高的分類器「勝出」,將這個類別返回作為預測結果。

每個類別都對應一個二類分類器,這樣每個類別也都有一個係數(w)向量和一個截距(b)。下面是分類置信方程,其結果中最大值對應的類別即為預測的類比標籤:

w[0] * x[0] + w[1] * x[1] + … + w[p] * x[p] + b

多分類Logistic回歸背後的數學與「一對其餘」方法稍有不同,但它也是對每個類別都有一個係數向量和一個截距,也使用了相同的預測方法。

我們將「一對其餘」方法應用在一個簡單的三分類數據集上。我們用到了一個二維數據集,每個類別的數據都是從一個高斯分布中取樣得出的:

from sklearn.datasets import make_blobs

X, y = make_blobs(random_state=42)
mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
plt.legend(["class 0", "class 1", "class2"])

在這個數據集上訓練一個LinearSVC分類器:

linear_svm = LinearSVC().fit(X, y)
print("Training set score: {:.2f}".format(linear_svm.score(X, y)))
print("Coefficient shape:", linear_svm.coef_.shape)
print("Intercept shape:", linear_svm.intercept_.shape)
Training set score: 1.00
Coefficient shape: (3, 2)
Intercept shape: (3,)

將這三個二分類器給出的直線可視化:

mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
line = np.linspace(-15, 15)
for coef, intercept, color in zip(linear_svm.coef_, linear_svm.intercept_, ['b', 'r', 'g']):
    plt.plot(line, -(line * coef[0] + intercept) / coef[1], c=color)
plt.ylim(-10, 15)
plt.xlim(-10, 8)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
plt.legend(['Class 0', 'Class 1', 'Class 2', 'Line Class 0', 'Line Class 1', 'Line Class 2'], loc=[1.01, 0.3])

可以看到,訓練集中所有屬於類別0的點都在於類別0對應的直線上方,這說明它們位於這個二類分類器屬於「類別0」的那一側。屬於類別0的點位於與類別2對應直線的上方,這說明類別0的點被類別2的二類分類器劃為「其餘」。屬於類別0的點位於與類別1對應的直線左側,這說明類別1的二類分類器將類別0也劃為「其餘」。

影像中間的三角形區域和同時屬於兩個分類的區域屬於哪一個類別呢,3個二類分類器都將中間區域的點劃為「其餘」,將公有的區域兩個二類分類器劃為「本類」,剩下一個二類分類器劃為「其餘」。這些區域的點應該划到哪一個類別呢?答案是分類方程結果最大的那個類別,即最接近的那條線對應的類別。

下面的例子給出了二維空間中所有區域的預測結果:

mglearn.plots.plot_2d_classification(linear_svm, X, fill=True, alpha=.7)
mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
line = np.linspace(-15, 15)
for coef, intercept, color in zip(linear_svm.coef_, linear_svm.intercept_, ['b', 'r', 'g']):
    plt.plot(line, -(line * coef[0] + intercept) / coef[1], c=color)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
plt.legend(['Class 0', 'Class 1', 'Class 2', 'Line Class 0', 'Line Class 1', 'Line Class 2'], loc=[1.01, 0.3])

7. 線性模型的優點、缺點和參數

線性模型的主要參數是正則化參數,在回歸模型中叫作alpha,在LogisticRegression和LiearSVC中叫作C。alpha值越大或C值越小,對應的正則化越強,說明模型越簡單。通常在對數尺度上對C和alpha進行搜索。還需要確定是使用L1正則化還是使用L2正則化。如果假定只有幾個特徵時真正重要的,那麼應該使用L1正則化。否則應默認使用L2正則化。如果模型的可解釋性很重要的話,使用L1正則化也會有幫助。由於L1隻用到幾個特徵,所以相對更容易解釋那些特徵對模型是重要的,以及這些特徵的作用。

線性模型的訓練速度非常快,預測速度也很快。這種模型可以推廣到非常大的數據集,對稀疏數據也很有效。如果你的數據包含數十萬甚至上百萬個樣本,你可能需要研究如何使用LogisticRegression和Ridge模型的slover=’sag’選項,在處理大型數據時,這一選項比默認值要更快。其他選項還有SGDClassifier類和SGDRegression類,它們對本節介紹的線性模型實現了可拓展性更強的版本。

線性模型的另一個優點在於,利用我們之前見過的用於回歸和分類的公式,理解如何進行預測是相對比較容易的。但是往往並不完全清楚係數為什麼是這樣的。如果數據中包含高度相關的特徵,這一問題尤為突出。在這種情況下,可能很難對係數做出解釋。

如果特徵數量大於樣本數量,線性模型的表現通常很好。它也常用於非常大的數據集,只是因為訓練其他模型並不可行。但在更低維的空間中,模型的泛化性能可能更好。