支援向量機(Support Vector Machines,SVM)是機器學習中最優雅的演算法之一。在開始探討之前,我們需要理解超平面(hyperplane)這個核心概念。形式上,超平面是 n 維空間中的 n-1 維子網路。這聽起來複雜,但實際上相當直觀:
- 在二維空間中,超平面就是一條線(一維)
- 在三維空間中,超平面就是一個平面(二維)
- 在更高維度,超平面則是這個概念的推廣
SVM 的核心思想是尋找一個能最大化類別間邊界(margin)的超平面。想像一下,在二維空間中有兩個類別的資料點,SVM 會尋找一條具有最寬「邊界帶」的直線,完美地將這兩個類別分開。
訓練線性分類別
在實際應用中,當我們需要訓練一個能夠有效分類別測值的模型時,支援向量分類別(SVC)是一個強大的選擇。讓我們看如何使用 SVM 來訓練一個線性分類別:
# 載入必要的函式庫
from sklearn.svm import LinearSVC
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
import numpy as np
# 載入只有兩個類別和兩個特徵的資料
iris = datasets.load_iris()
features = iris.data[:100,:2]
target = iris.target[:100]
# 標準化特徵
scaler = StandardScaler()
features_standardized = scaler.fit_transform(features)
# 建立支援向量分類別
svc = LinearSVC(C=1.0)
# 訓練模型
model = svc.fit(features_standardized, target)
這段程式碼示範瞭如何使用 scikit-learn 的 LinearSVC 實作一個簡單的支援向量分類別。我們從 iris 資料集中只選擇前 100 筆資料(包含兩個類別)和前兩個特徵,這樣可以在二維空間中視覺化模型。在訓練前,我們先對特徵進行標準化處理,這對 SVM 的效能至關重要,因為 SVM 對特徵尺度敏感。引數 C=1.0 是正則化引數,控制錯誤分類別懲罰強度。
為了更好地理解 SVM 的運作原理,讓我們視覺化資料和決策邊界:
# 載入視覺化函式庫
from matplotlib import pyplot as plt
# 根據類別繪製資料點並著色
color = ["black" if c == 0 else "lightgrey" for c in target]
plt.scatter(features_standardized[:,0], features_standardized[:,1], c=color)
# 建立超平面
w = svc.coef_[0]
a = -w[0] / w[1]
xx = np.linspace(-2.5, 2.5)
yy = a * xx - (svc.intercept_[0]) / w[1]
# 繪製超平面
plt.plot(xx, yy)
plt.axis("off")
plt.show()
這段程式碼視覺化了我們的二維資料點和 SVM 找到的決策邊界(超平面)。在二維空間中,超平面就是一條直線。黑色點代表類別 0,淺灰色點代表類別 1。程式碼中,我們從模型中提取權重(coefficients)和截距(intercept)來繪製這條直線。
這個視覺化展示了 SVM 的核心思想:尋找一條能最大化兩個類別間邊界的直線。任何位於線上方的新觀測值會被歸類別 0,而線下方的則歸類別 1。我們可以透過預測一個位於左上角的新觀測值來驗證這一點:
# 建立新的觀測值
new_observation = [[-2, 3]]
# 預測新觀測值的類別
print(svc.predict(new_observation)) # 輸出: [0]
SVM 的進階應用與挑戰
使用 SVM 時有幾個重要的考量點。首先,雖然我們的例子只有兩個類別(二元分類別,但 SVM 也能很好地應用於多類別問題。其次,如上述視覺化所示,基本的 SVM 超平面是線性的(非曲線)。在我們的例子中,這沒有問題因為資料是線性可分的,意味著存在一條直線能完美分隔兩個類別。
然而,現實世界中的資料很少如此理想。通常情況下,我們無法完美分隔各個類別。在這種情況下,SVM 需要在最大化邊界和最小化錯誤分類別間取得平衡。這種平衡由引數 C 控制,它決定了對錯誤分類別懲罰程度:
- 當 C 較小時,分類別容許更多錯誤分類別高偏差但低方差)
- 當 C 較大時,分類別嚴厲懲罰錯誤分類別因此會盡力避免任何錯誤(低偏差但高方差)
在 scikit-learn 中,C 預設為 1.0。我們應該將 C 視為學習演算法的超引數,可以透過模型選擇技術進行調整。
使用核函式處理線性不可分的類別
現實中的資料經常是線性不可分的,也就是說沒有一條直線能夠完美分隔不同類別。在這種情況下,我們可以使用核函式(kernel functions)來擴充套件 SVM,建立非線性決策邊界:
# 載入必要的函式庫
from sklearn.svm import SVC
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
import numpy as np
# 設定隨機種子
np.random.seed(0)
# 生成兩個特徵
features = np.random.randn(200, 2)
# 使用 XOR 閘產生線性不可分的類別
target_xor = np.logical_xor(features[:, 0] > 0, features[:, 1] > 0)
target = np.where(target_xor, 0, 1)
# 建立使用徑向基函式(RBF)核函式的支援向量機
svc = SVC(kernel="rbf", random_state=0, gamma=1, C=1)
# 訓練分類別
model = svc.fit(features, target)
這段程式碼示範瞭如何處理線性不可分的資料。我們生成了一個特殊的資料集,其中類別是透過 XOR(異或)邏輯產生的,這種資料集在二維空間中是無法用直線分隔的。為瞭解決這個問題,我們使用了徑向基函式(RBF)核函式的 SVM,它可以建立非線性決策邊界。
核函式的本質是將資料轉換到更高維度的空間,使得原本線性不可分的資料變成線性可分的。從數學角度看,支援向量分類別可以表示為:
f(x) = β₀ + ∑(i∈S) αᵢK(xᵢ, x’ᵢ)
其中:
- β₀ 是偏差(bias)
- S 是所有支援向量觀測值的集合
- α 是要學習的模型引數
- (xᵢ, x’ᵢ) 是兩個支援向量觀測值的配對
- K 是核函式,用於比較 xᵢ 和 x’ᵢ 的相似度
核函式 K 決定了用於分隔類別的超平面類別。透過使用不同的核函式,我們可以建立不同形狀的決策邊界。例如:
線性核函式: K(xᵢ, x’ᵢ) = ∑ⱼ₌₁ᵖ xᵢⱼx’ᵢⱼ
多項式核函式: K(xᵢ, x’ᵢ) = (1 + ∑ⱼ₌₁ᵖ xᵢⱼx’ᵢⱼ)^d
徑向基函式(RBF)核函式: K(xᵢ, x’ᵢ) = e^(-γ∑ⱼ₌₁ᵖ (xᵢⱼ-x’ᵢⱼ)²)
讓我們視覺化一下線性核函式和 RBF 核函式在處理線性不可分資料時的表現差異:
# 視覺化函式定義
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt
def plot_decision_regions(X, y, classifier):
cmap = ListedColormap(("red", "blue"))
xx1, xx2 = np.meshgrid(np.arange(-3, 3, 0.02), np.arange(-3, 3, 0.02))
Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
plt.contourf(xx1, xx2, Z, alpha=0.1, cmap=cmap)
for idx, cl in enumerate(np.unique(y)):
plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
alpha=0.8, c=cmap(idx),
marker="+", label=cl)
# 建立線性核函式的支援向量分類別
svc_linear = SVC(kernel="linear", random_state=0, C=1)
svc_linear.fit(features, target)
# 視覺化線性核函式的結果
plot_decision_regions(features, target, classifier=svc_linear)
plt.axis("off")
plt.show()
# 建立RBF核函式的支援向量分類別
svc_rbf = SVC(kernel="rbf", random_state=0, gamma=1, C=1)
svc_rbf.fit(features, target)
# 視覺化RBF核函式的結果
plot_decision_regions(features, target, classifier=svc_rbf)
plt.axis("off")
plt.show()
這段程式碼比較了線性核函式和 RBF 核函式在處理同一個線性不可分資料集時的表現差異。從視覺化結果可以明顯看出,線性核函式無法有效分隔這個 XOR 資料集,因為沒有一條直線能夠同時將兩個類別分開。而 RBF 核函式則能夠建立一個非線性的決策邊界,成功地將兩個類別分開。
RBF 核函式的優勢在於它能夠將資料對映到無限維的空間中,從而找到一個能夠分隔不同類別的超平面。引數 gamma 控制了決策邊界的形狀:
- 較大的 gamma 值會產生更複雜(更彎曲)的決策邊界
- 較小的 gamma 值則產生更平滑的決策邊界
處理不平衡資料集的策略
在實際應用中,不平衡資料集(某些類別的樣本數遠多於其他類別)是一個常見的挑戰。當使用 SVM 處理不平衡資料時,模型可能會偏向多數類別,導致少數類別的預測效果不佳。針對這個問題,有幾種有效的策略:
調整類別權重
SVM 允許我們為不同類別分配不同的權重,增加少數類別的重要性:
# 使用類別權重處理不平衡資料
from sklearn.svm import SVC
from sklearn.datasets import make_classification
# 生成不平衡資料集(90% 類別 0,10% 類別 1)
X, y = make_classification(n_samples=1000, weights=[0.9, 0.1], random_state=42)
# 使用平衡類別權重的SVM
svm_balanced = SVC(kernel='rbf', class_weight='balanced', random_state=42)
svm_balanced.fit(X, y)
# 或手動設定權重
class_weights = {0: 1, 1: 9} # 類別 1 的權重是類別 0 的 9 倍
svm_custom = SVC(kernel='rbf', class_weight=class_weights, random_state=42)
svm_custom.fit(X, y)
這段程式碼展示了兩種設定類別權重的方式:
class_weight='balanced'
:scikit-learn 自動根據類別頻率計算權重- 手動指定每個類別
支援向量機與貝葉斯理論:機器學習中的兩大強力工具
在機器學習領域中,支援向量機(SVM)與貝葉斯分類別是兩種具有不同理論基礎但同樣強大的分類別具。這兩種方法各有其獨特優勢與適用場景,掌握它們的進階技巧對於資料科學家而言至關重要。本文將探討SVM的核心技術與貝葉斯理論在實際應用中的關鍵技巧。
核函式選擇與最佳化SVM的靈魂所在
在使用scikit-learn實作SVM時,核函式(kernel)的選擇是影響模型效能的關鍵因素。核函式決定了如何將資料對映到高維空間,從而使線性不可分的資料變得可分。
我在處理各種機器學習問題時發現,核函式選擇不僅是一門科學,更是一門藝術。以下是關於核函式選擇的幾點關鍵考量:
- 線性核函式(Linear Kernel):當資料近似線性可分時的最佳選擇
- 多項式核函式(Polynomial Kernel):需調整degree引數,適合處理非線性但結構相對簡單的資料
- 徑向基函式(RBF):最常用的核函式,需調整gamma引數,適合處理複雜的非線性關係
在scikit-learn中,我們可以透過kernel引數指定核函式類別,並設定相應的引數:
- 對於多項式核函式,需設定degree引數
- 對於RBF核函式,需設定gamma引數
- 對於所有核函式,都需設定懲罰引數C
在實踐中,這些引數應該被視為超引數,透過模型選擇技術(如交叉驗證)來尋找最佳組合。我經常使用GridSearchCV或RandomizedSearchCV來自動化這個過程,確保找到最佳的參陣列合。
取得SVM的預測機率:從決策邊界到機率估計
如何從SVM獲得類別預測機率
SVM在本質上並非根據機率模型,而是根據決策邊界的幾何模型。然而,在許多應用場景中,我們不僅需要知道預測的類別,還需要了解預測的確信度。scikit-learn提供了一種方法來從SVM取得預測機率。
# 載入必要的函式庫
from sklearn.svm import SVC
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
import numpy as np
# 載入資料
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 標準化特徵
scaler = StandardScaler()
features_standardized = scaler.fit_transform(features)
# 建立支援向量分類別物件,設定probability=True
svc = SVC(kernel="linear", probability=True, random_state=0)
# 訓練分類別
model = svc.fit(features_standardized, target)
# 建立新的觀測值
new_observation = [[.4, .4, .4, .4]]
# 檢視預測機率
model.predict_proba(new_observation)
# 輸出結果:array([[ 0.00588822, 0.96874828, 0.0253635 ]])
上面的程式碼示範瞭如何從SVM取得類別預測機率。關鍵在於建立SVC物件時設定probability=True
引數。這段程式碼首先載入鳶尾花資料集,然後標準化特徵(這對SVM尤其重要),接著訓練一個線性核函式的SVM模型。最後,對一個新的觀測值進行機率預測。
結果顯示這個新觀測值有約96.87%的機率屬於第二個類別(索引為1),而屬於第一個和第三個類別的機率分別只有0.59%和2.54%。
SVM機率估計的工作原理與限制
SVM生成預測機率的方式與其他監督學習演算法(如k近鄰)有本質不同。SVM使用超平面建立決策區域,本身不直接輸出機率估計。然而,我們可以透過一些技術來取得校準後的類別機率:
對於二元分類別題,SVM使用Platt scaling技術,這實際上是先訓練SVM,然後訓練一個額外的交叉驗證邏輯迴歸,將SVM的輸出對映為機率。
機率計算公式:P(y=1|x) = 1/(1 + e^(A*f(x)+B))
其中A和B是引數向量,f(x)是觀測值到超平面的有符號距離。
對於多類別問題,則使用Platt scaling的擴充套件版本。
實際使用中,取得預測機率存在兩個主要問題:
- 計算成本高:因為需要訓練第二個模型並使用交叉驗證,生成預測機率會顯著增加模型訓練時間
- 預測不一致:由於預測機率是透過交叉驗證建立的,它們可能與預測類別不完全比對。例如,一個觀測值可能被預測為類別1,但其屬於類別1的預測機率可能小於0.5
在scikit-learn中,預測機率必須在模型訓練時透過設定probability=True
來啟用。訓練後,我們可以使用predict_proba
方法輸出每個類別的估計機率。
識別SVM的支援向量:決策邊界背後的關鍵觀測值
為何支援向量如此重要?
支援向量是SVM中極為重要的概念,它們是決定超平面位置的關鍵觀測值。直覺上,可以將超平面視為由這些支援向量"支撐"的,這也是支援向量機名稱的由來。
識別支援向量對於理解模型至關重要,因為:
- 支援向量決定了決策邊界的位置
- 移除非支援向量的觀測值不會改變模型
- 移除支援向量會導致超平面移動,失去最大間隔
# 載入必要的函式庫
from sklearn.svm import SVC
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
import numpy as np
# 載入只有兩個類別的資料
iris = datasets.load_iris()
features = iris.data[:100,:]
target = iris.target[:100]
# 標準化特徵
scaler = StandardScaler()
features_standardized = scaler.fit_transform(features)
# 建立支援向量分類別物件
svc = SVC(kernel="linear", random_state=0)
# 訓練分類別
model = svc.fit(features_standardized, target)
# 檢視支援向量
support_vectors = model.support_vectors_
這段程式碼示範瞭如何識別SVM模型中的支援向量。它首先載入鳶尾花資料集的前100個樣本(只包含兩個類別),然後標準化特徵,接著訓練一個線性SVM模型。
訓練後,我們可以透過support_vectors_
屬性檢視支援向量的特徵值。在本例中,模型識別出4個支援向量,這些向量決定了分類別界的位置。
除了直接檢視支援向量的特徵值外,scikit-learn還提供其他方式來瞭解支援向量:
使用
support_
屬性檢視支援向量的索引:model.support_ # 輸出:array([23, 41, 57, 98], dtype=int32)
使用
n_support_
檢視每個類別的支援向量數量:model.n_support_ # 輸出:array([2, 2], dtype=int32)
這表明在我們的模型中,每個類別各有2個支援向量,總共4個支援向量決定了決策邊界。
處理不平衡類別問題:SVM的權重調整策略
不平衡類別問題是機器學習中常見的挑戰,當某些類別的樣本數量遠多於其他類別時,模型往往會偏向多數類別,導致對少數類別的識別率下降。
在SVM中,處理不平衡類別的一個有效方法是透過權重調整懲罰引數C。基本思想是增加對少數類別誤分類別懲罰,防止它們被多數類別"淹沒"。
# 載入必要的函式庫
from sklearn.svm import SVC
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
import numpy as np
# 載入只有兩個類別的資料
iris = datasets.load_iris()
features = iris.data[:100,:]
target = iris.target[:100]
# 透過移除前40個觀測值使類別高度不平衡
features = features[40:,:]
target = target[40:]
# 建立目標向量,指示是否為類別0,否則為1
target = np.where((target == 0), 0, 1)
# 標準化特徵
scaler = StandardScaler()
features_standardized = scaler.fit_transform(features)
# 建立支援向量分類別,設定class_weight="balanced"
svc = SVC(kernel="linear", class_weight="balanced", C=1.0, random_state=0)
# 訓練分類別
model = svc.fit(features_standardized, target)
這段程式碼示範瞭如何處理SVM中的不平衡類別問題。首先建立一個不平衡的資料集,然後透過設定class_weight="balanced"
引數來自動調整各類別的權重。
在SVM中,C是控制誤分類別罰的超引數。處理不平衡類別的方法是按類別加權C,使得:
C_k = C * w_j
其中C是誤分類別懲罰,w_j是與類別j頻率成反比的權重,C_j是類別j的C值。
在scikit-learn中,設定class_weight='balanced'
會自動計算權重:
w_j = n/(k*n_j)
其中w_j是類別j的權重,n是觀測值總數,n_j是類別j的觀測值數量,k是總類別數。
這種方法有效地增加了對少數類別誤分類別懲罰,使模型在預測時更加"公平",不會過度偏向多數類別。在實際應用中,這是處理不平衡資料集的重要技術,特別是當我們關注少數類別的識別率時(如詐欺檢測)。
樸素貝葉斯分類別:機率分類別簡潔之美
貝葉斯理論與機器學習
貝葉斯理論是理解事件機率的首要方法,它讓我們能根據新訊息和先驗信念更新對事件機率的理解:
P(A|B) = (P(B|A) * P(A)) / P(B)
在機器學習中,貝葉斯理論的一個重要應用是樸素貝葉斯分類別。這種分類別結合了多種在實際機器學習中非常理想的特質:
- 直觀的方法論
- 能夠有效處理小資料集
- 訓練和預測的計算成本低
樸素貝葉斯之所以"樸素",是因為它假設特徵之間相互獨立,這雖然在現實中很少成立,但這種簡化使得模型計算變得非常高效,而與在許多情況下仍能提供出色的結果。
在處理文字分類別情感分析和垃圾郵件過濾等任務時,樸素貝葉斯常是首選演算法,因為它能有效處理高維稀疏資料,與訓練速度快、記憶體求低。
我在實際專案中發現,即使在特徵明顯相關的情況下,樸素貝葉斯也能表現得出奇地好。這種"不合理的有效性"使它成為快速建立基線模型或處理資源受限環境中的理想選擇。
樸素貝葉斯分類別有三種主要變體:
- 高斯樸素貝葉斯:假設特徵遵循正態分佈,適合處理連續資料
- 多項式樸素貝葉斯:適合處理離散資料,如文字中的詞頻
- 伯努利樸素貝葉斯:特徵為二進位值,只考慮特徵是否出現
在scikit-learn中,這三種變體
貝氏分類別的數學魔法:簡單而強大的分類別術
在機器學習的眾多演算法中,貝氏分類別以其簡潔的數學原理與驚人的實用性脫穎而出。當我第一次接觸這個演算法時,便被其簡單而優雅的設計所吸引。在處理文字分類別垃圾郵件過濾等任務時,貝氏分類別往往能在極低的計算成本下提供令人滿意的結果。
貝氏分類別的核心是貝氏定理,這個看似簡單的公式卻蘊含著深刻的統計學原理。讓我們先來理解這個演算法的基礎公式:
$$P(y|x_1, \cdots, x_j) = \frac{P(x_1, \cdots, x_j|y)P(y)}{P(x_1, \cdots, x_j)}$$
在這個公式中:
- $P(y|x_1, \cdots, x_j)$ 是後驗機率,表示在觀察到特徵 $x_1, \cdots, x_j$ 的情況下,樣本屬於類別 $y$ 的機率
- $P(x_1, \cdots, x_j|y)$ 是可能性,表示當樣本屬於類別 $y$ 時,觀察到特徵值 $x_1, \cdots, x_j$ 的可能性
- $P(y)$ 是先驗機率,表示在看到任何資料前,我們對類別 $y$ 出現機率的預設信念
- $P(x_1, \cdots, x_j)$ 是邊際機率,在所有類別比較中保持不變的常數
在實際應用中,分類別會比較每個可能類別的後驗機率分子(因為分母在所有類別中相同)。對每個觀察值,後驗機率分子最大的類別將成為預測類別 $\hat{y}$。
貝氏分類別有個「天真」之處,它假設所有特徵之間是相互獨立的。這個假設在現實中往往不成立,但有趣的是,即使這個假設被違反,貝氏分類別仍然能夠產生相當不錯的結果。這就是為什麼它被稱為「天真」或「單純」貝氏分類別。
另一個關鍵點是,我們需要為每個特徵的可能性 $P(x_j|y)$ 假設一個統計分佈。常見的分佈包括正態分佈(高斯)、多項式分佈和伯努利分佈。選擇哪種分佈通常取決於特徵的性質(連續、二元等)。