【機器學習】支援向量機(個人筆記)

漫舞八月(Mount256)發表於2024-06-12

目錄
  • SVM 分類器的誤差函式
    • 分類誤差函式
    • 距離誤差函式
    • C 引數
  • 非線性邊界的 SVM 分類器(核心方法)
    • 多項式核心
    • 徑向基函式(RBF)核心

原始碼檔案請點選此處

SVM 分類器的誤差函式

SVM 使用兩條平行線,使用中心線作為參考系 \(L: \ w_1x_1 + w_2x_2 + b = 0\)。我們構造兩條線,一條在上面,一條在下面,分別為:

\[L+: \ w_1x_1 + w_2x_2 + b = 1 \\ L-: \ w_1x_1 + w_2x_2 + b = -1 \]

分類器由 \(L+\)\(L-\) 組成。為訓練 SVM,我們需要為由兩條線組成的分類器構建一個誤差函式,期望達成的目標有兩個:

  • 兩條線中的每一條都應儘可能對點進行分類。
  • 兩條線應儘可能彼此遠離。

誤差函式表示如下:

\[誤差 = 分類誤差 + 距離誤差 \]

分類誤差函式

\((x_1, x_2)\) 的預測函式為

\[\hat{y} = step(w_1x_1 + w_2x_2 + b) \]

顯然這是一個離散感知器,其中:

\[y = step(x) = \begin{cases} 0, x \leq 0 \\ 1, x > 0 \end{cases} \]

定義分類誤差函式如下:

\[\begin{cases} 0, 錯誤分類 \\ |w_1x_1 + w_2x_2 + b|, 正確分類 \end{cases} \]

例如,考慮標籤為 \(0\) 的點 \((4,3)\),兩個感知器給出的預測為:

\[L+: \hat{y} = step(2x_1 + 3x_2 - 7) = 1 \\ L-: \hat{y} = step(2x_1 + 3x_2 - 5) = 1 \]

可以看到兩個感知器均預測錯誤,此時分類誤差為:

\[|2x_1 + 3x_2 - 7| + |2x_1 + 3x_2 - 5| = 22 \]

距離誤差函式

若兩個線性方程如下:

\[L+: \ w_1x_1 + w_2x_2 + b = 1 \\ L-: \ w_1x_1 + w_2x_2 + b = -1 \]

根據兩條平行直線間的距離公式:

\[d = \frac{|C_1 - C_2|}{\sqrt{A^2 + B^2}} \]

則這兩條平行線的垂直距離為:

\[d = \frac{2}{\sqrt{w_1^2 + w_2^2}} \]

此為距離誤差。注意到,當 \(w_1^2 + w_2^2\) 很大時,\(d\) 很小;當 \(w_1^2 + w_2^2\) 很小時,\(d\) 很大。因此 \(w_1^2 + w_2^2\) 是一個很好的誤差函式。

C 引數

很多時候我們希望 SVM 分類器能側重於分類誤差或距離誤差其中一個方面,那麼我們可以使用 C 引數:

\[誤差 = C \cdot 分類誤差 + 距離誤差 \]

C 引數如何控制兩者的呢?

  • C 很大:誤差公式以分類誤差為主,SVM 分類器更側重於對點進行正確分類;
  • C 很小:誤差公式以距離誤差為主,SVM 分類器更側重於保持線之間的距離。

下面是一個例子:

svm_c_001 = SVC(kernel='linear', C=0.01)
svm_c_001.fit(features, labels)
 
svm_c_100 = SVC(kernel='linear', C=100)
svm_c_100.fit(features, labels)

上圖為 C=0.01 的情況,下圖為 C=100 的情況:

image

image

非線性邊界的 SVM 分類器(核心方法)

多項式核心

  • 在變數 \(x_1, x_2\) 使用 2 階多項式核心,就需要計算這些單項式:\(x_1, x_2, x_1^2, x_1x_2, x_2^2\),然後嘗試把它們線性組合起來,比如透過檢查發現這是一個有效的分類器公式:\(x_1^2 + x_2^2 = 1\)
  • 這相當於將二維平面對映到一個五維平面,即點 \((x_1, x_2)\) 到點 \((x_1, x_2, x_1^2, x_1x_2, x_2^2)\) 的對映
  • 類似地,在變數 \(x_1, x_2\) 使用 3 階多項式核心,就需要計算這些單項式:\(x_1, x_2, x_1^2, x_1x_2, x_2^2, x_1^3, x_1^2x_2, x_1x_2^2, x_2^3\),然後嘗試把它們線性組合起來,透過檢查發現一個有效的分類器公式

程式碼如下:

svm_degree_2 = SVC(kernel='poly', degree=2)
svm_degree_2.fit(features, labels)
print("[Degree=2] Accuracy=", svm_degree_2.score(features, labels))

svm_degree_4 = SVC(kernel='poly', degree=4)
svm_degree_4.fit(features, labels)
print("[Degree=4] Accuracy=", svm_degree_4.score(features, labels))

當分類器為 2 階多項式的執行結果:

image

當分類器為 4 階多項式的執行結果:

image

徑向基函式(RBF)核心

徑向基函式:

  • 當變數只有一個時,最簡單的徑向基函式為 \(y = e^{-x^2}\),此函式看起來像標準正態分佈,函式凸起處為 \(x=0\)
  • 當變數有 2 個時,最簡單的徑向基函式為 \(z = e^{-(x^2 + y^2)}\),此函式看起來像標準正態分佈,函式凸起處為 \((0,0)\)
  • 當變數有 \(n\) 個時,基本徑向基函式為 \(y = e^{-(x_1^2 + ... + x_n^2)}\)\(n\) 維凸點以 0 為中心
  • 若希望以點 \((p_1, ..., p_n)\) 為中心凸起,則基本徑向基函式為 \(y = e^{-[(x_1-p_1)^2 + ... + (x_n-p_n)^2]}\)
  • 新增 \(\gamma\) 引數:\(y = e^{-\gamma[(x_1-p_1)^2 + ... + (x_n-p_n)^2]}\),用於控制擬合程度(形象理解,即調整凸起程度
    • \(\gamma\) 值非常小時,模型會欠擬合
    • \(\gamma\) 值非常大時,模型會嚴重過擬合,合適的 \(\gamma\) 值非常重要

相似度公式:

  • 對於點 \(p\) 和點 \(q\)\(相似度(p,q) = e^{-距離(p,q)^2}\)
  • 一維資料集中,點 \(x_1\) 和點 \(x_2\) 的相似度為 \(e^{-(x_1-x_2)^2}\)
  • 二維資料集中,點 \(A(x_1, y_1)\) 和點 \(B(x_2, y_2)\) 的相似度為 \(e^{-[(x_1-x_2)^2 + (y_1-y_2)^2]}\)
  • 若該資料集有 \(n\) 個資料點,則應計算 \(n^2\) 個相似度;每個點到自身的相似度一定為 1;距離越近,相似度越高

有了相似度公式,就可以定義分類器了。假設資料集有 \(n\) 個資料點 \(X_i\),每個點對應標籤 \(L_i\)(取值為 0 或 1),則對於點 \(X\) 的分類預測如下:

\[\hat{y} = step[\sum^n_{i=1} (-1)^{L_i - 1} \cdot e^{-距離(X, X_i)^2}] \]

形象理解:這相當於在一個二維平面上,為標記為 0 的點新增了一個“山谷”,為標記為 1 的點新增了一個“山峰”。對每個點都如此操作,最後使用閾值 0 畫出一個“海岸線”,這就是最後的分類邊界(boundary)。

程式碼如下:

svm_gamma_01 = SVC(kernel='rbf', gamma=0.1)
svm_gamma_01.fit(features, labels)
print("[Gamma=0.1] Accuracy=", svm_gamma_01.score(features, labels))

svm_gamma_1 = SVC(kernel='rbf', gamma=1)
svm_gamma_1.fit(features, labels)
print("[Gamma=1] Accuracy=", svm_gamma_1.score(features, labels))


svm_gamma_10 = SVC(kernel='rbf', gamma=10)
svm_gamma_10.fit(features, labels)
print("[Gamma=10] Accuracy=", svm_gamma_10.score(features, labels))


svm_gamma_100 = SVC(kernel='rbf', gamma=100)
svm_gamma_100.fit(features, labels)
print("[Gamma=100] Accuracy=", svm_gamma_100.score(features, labels))

\(\gamma=0.1\) 時的執行結果:

image

\(\gamma=1\) 時的執行結果:

image

\(\gamma=10\) 時的執行結果:

image

\(\gamma=100\) 時的執行結果:

image

相關文章