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

線性模型用於分類,分類的原理還要從公式說起。

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

線性模型的公司的結果y是一個連續的輸出結果,如果將y的值與0作一個界限上的區分,那y的值將被分成兩個區域。公式的表達如下:

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

也就是說,如果該公式(函數)預測的結果值小於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而言,決定正則化強度的權衡參數叫做CC值越大,對就的正則化越弱
  • 也就是說,越大的C將擁有越上的約束力,即係數的大小更自由,模型對於數據的貼合度將變得更復雜。
  • 如果C越小,則對係數的約束越大,甚至趨向於0,使模型更能貼合大多數數據,模型也更簡單。

下面直接展示一下LinearSVC模型的C分別取0.011100時模型的決策邊界效果:

mglearn.plots.plot_linear_svc_regularization()

對上圖的總結:

  1. 最左側的圖,C值很小,所以對應強正則化。要求模型更貼合於大多數數據,因此對於圖中兩個錯誤的點進行了忽略。
  2. 中間的圖,C值稍大,由於對模型的約束變小,模型對於數據的反應則變得更加第三一些,決策線向着兩個錯誤的點進行偏移,希望更好的貼合訓練數據。
  3. 右側圖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正則下的係數分佈有了直觀的瞭解,也就明白了對應的約束力。

這裏主要需要明白設置L1L2需要通過參數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()

通過上圖很明白的就看出中間的三角區是如何被分類的了!

好吧,到現在,機器學習的基礎模型的探討就告一段落了。不過,這些模型並不常用,在接下來,將着重學習樸素貝葉期斯分類器、決策樹、核支持向量機、神經網絡等經典模型!

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