【機器學習】用於分類的線性模型:Logistic迴歸與線性支援向量機

線性模型用於分類,分類的原理還要從公式說起。
線性模型的公司的結果 y
是一個連續的輸出結果,如果將 y
的值與 0
作一個界限上的區分,那 y
的值將被分成兩個區域。公式的表達如下:
也就是說,如果該公式(函式)預測的結果值小於0,就歸類為-1,如果結果值大於0,就歸類為1.
需要重點理解的地方在於:
- 對於用於迴歸的線性模型來說,輸出
y
是特徵的線性函式,是直線、平面或超平面(對於更高維的資料集)。 - 對於用於分類的線性模型, 決策邊界 是輸入的線性函式。
不同線性模型演算法之間的區別在於:
- 係數和截距的特定組合對訓練集資料擬合好壞的度量方法;
- 是否使用正則化,以及使用哪種正則化方法。
最覺的兩種線性分類演算法是 Logistic迴歸 和 線性支援向量機 。前者在 linear_model.LogisticRegression
中實現,後者在 svm.LinearSVC
(SVC代表支援再是分類器)中實現 。
接下來對這兩個模型做一個初步認識吧!
# 在學習之前,先匯入這些常用的模組 import numpy as np import pandas as pd import matplotlib.pyplot as plt import mglearn
Logistic 與 LinearSVC 模型
下面,將這兩個模型用在二分類資料 forge
資料集上,並顯示模型得出的決策邊界。
先展示下二分類的展示圖:
# 匯入二分類資料 X, y = mglearn.datasets.make_forge() mglearn.discrete_scatter(X[:, 0], X[:, 1], y) plt.show()
C:\Users\Administrator\Anaconda3\lib\site-packages\sklearn\utils\deprecation.py:77: DeprecationWarning: Function make_blobs is deprecated; Please import make_blobs directly from scikit-learn warnings.warn(msg, category=DeprecationWarning)

# 匯入Logistic from sklearn.linear_model import LogisticRegression # 匯入LinearSVC 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=.5, ax=ax, alpha=.7) # 繪製二分類的訓練資料 mglearn.discrete_scatter(X[:, 0], X[:, 1], y, ax=ax) # 設定標題為模型名稱 ax.set_title('{}'.format(clf.__class__.__name__)) # 設定x座標軸標籤名稱 ax.set_xlabel('Feature 0') # 設定y座標軸標籤名稱 ax.set_ylabel('Feature 1') # 在第一個繪圖區上顯示圖例 axes[0].legend() plt.show()

說明:
- forge資料集有兩個特徵,分別對應X軸與Y軸。
- LinearSVC與LogisticRegression得到的決策邊界,都是直線,將資料分為了上下兩個區域。
- 兩個模型預設使用了L2正則化。
繼續探討:
- 對於LinearSVC與LogisticRegression而言,決定正則化強度的權衡引數叫做
C
。C
值越大,對就的正則化 越弱 。 - 也就是說,越大的
C
將擁有越上的約束力,即係數的大小更自由,模型對於資料的貼合度將變得更復雜。 - 如果
C
越小,則對係數的約束越大,甚至趨向於0,使模型更能貼合大多數資料,模型也更簡單。
下面直接展示一下 LinearSVC 模型的 C
分別取 0.01
、 1
、 100
時模型的決策邊界效果:
mglearn.plots.plot_linear_svc_regularization()

對上圖的總結:
- 最左側的圖,C值很小,所以對應強正則化。要求模型更貼合於大多數資料,因此對於圖中兩個錯誤的點進行了忽略。
- 中間的圖,C值稍大,由於對模型的約束變小,模型對於資料的反應則變得更加第三一些,決策線向著兩個錯誤的點進行偏移,希望更好的貼合訓練資料。
- 右側圖C值很大,因為對模型的約束很小,導致模型的決策邊界要求對所有資料都貼合,造成了過擬合現象。
再來看看使用乳腺癌資料集對LogisticRegression模型做出分析:
# 匯入乳腺癌資料 from sklearn.datasets import load_breast_cancer cancer = load_breast_cancer() # 將資料分為訓練集測試集 from sklearn.model_selection import train_test_split 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('訓練集評估分數:', logreg.score(X_train, y_train)) print('測試集評估分數:', logreg.score(X_test, y_test))
訓練集評估分數: 0.9553990610328639 測試集評估分數: 0.958041958041958
這裡模型置信的 C
值是1.如果訓練集的評分與測試集的評分差不多,那可能存在欠擬合的現象。
現在給模型增大 C
值,再看看評估結果:
logreg100 = LogisticRegression(C=100).fit(X_train, y_train) print('訓練集評估分數:', logreg100.score(X_train, y_train)) print('測試集評估分數:', logreg100.score(X_test, y_test))
訓練集評估分數: 0.971830985915493 測試集評估分數: 0.965034965034965
通過增大模型的 C
值,發現模型的精度變高了。
現在再減小 C
值看看模型的評估分數:
logreg001 = LogisticRegression(C=0.01).fit(X_train, y_train) print('訓練集評估分數:', logreg001.score(X_train, y_train)) print('測試集評估分數:', logreg001.score(X_test, y_test))
訓練集評估分數: 0.9342723004694836 測試集評估分數: 0.9300699300699301
可以看出,模型的精度變小了,並且存在欠擬合的可能。
按照老辦法,我們當不同 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('Codefficient index') plt.ylabel('Coefficient magnitude') plt.legend() plt.show()

從這個圖例可以看出, C
值越小,模型的係數就越趨向於0.
另外,該模型預設使用 L2 正則,也可以將其改成 L1 正則,以減少模型使用的特徵:
# 評估 for C, marker in zip([0.001, 1, 100], ['o', '^', 'v']): lr_l1 = LogisticRegression(C=C, penalty='l1').fit(X_train, y_train) print('訓練集,C={0},評估分數={1}'.format(C, lr_l1.score(X_train, y_train))) print('測試集,C={0},評估分數={1}'.format(C, lr_l1.score(X_test, y_test))) # 繪圖 plt.plot(lr_l1.coef_.T, marker, label='C={}'.format(C)) 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('Codefficient index') plt.ylabel('Coefficient magnitude') plt.legend(loc=3) plt.show()
訓練集,C=0.001,評估分數=0.9131455399061033 測試集,C=0.001,評估分數=0.9230769230769231 訓練集,C=1,評估分數=0.960093896713615 測試集,C=1,評估分數=0.958041958041958 訓練集,C=100,評估分數=0.9859154929577465 測試集,C=100,評估分數=0.9790209790209791

Ok,上圖對於不同 C
值所對應的 L
正則下的係數分佈有了直觀的瞭解,也就明白了對應的約束力。
這裡主要需要明白設定 L1 或 L2 需要通過引數 penalty
來設定。
用於多分類的線性模型
多分類其實也是一處二分類的模式,它是 一對其餘 的方法。
這裡展示一個三類的gf資料:
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', 'Class 2']) plt.show()

然後使用該資料對 LinearSVC
分類器進行訓練:
linear_svm = LinearSVC().fit(X, y) print('模型斜率集:', linear_svm.coef_.shape) print('模型截距集:', linear_svm.intercept_.shape)
模型斜率集: (3, 2) 模型截距集: (3,)
通過形狀可以明白:斜率集有3行,每行代表類別之一的一個係數向量;有2列,每列包含某個特徵對應的係數值。而截距是個一維資料,包含每個類別的截距值。
現在將分類器給出的直線進行視覺化:
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'], loc=(1.01, 0.3)) plt.show()

在這裡,線條的顏色與各點的顏色是一致的。從圖中可以很直觀的看到這三個點是如何被分成三類的。
但是,這三條線交叉的地方,有一個空白的三角區,那這個區域屬於哪個類別呢?
答案是分類方程結果最大的那個類別,即最接近的那條結對應的類別!
下面將展示整個二維空間是如何被分類的:
mglearn.plots.plot_2d_classification(linear_svm, X, 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'], loc=(1.01, 0.3)) plt.show()

通過上圖很明白的就看出中間的三角區是如何被分類的了!
好吧,到現在,機器學習的基礎模型的探討就告一段落了。不過,這些模型並不常用,在接下來,將著重學習樸素貝葉期斯分類器、決策樹、核支援向量機、神經網路等經典模型!
