题目要求:
在sonar和iris数据集中分别验证SVM算法,可选择不同的核函数,观察其分类结果。并讨论不同训练样本条件下,SVM算法的性能变化。
SVM原理
基本原理
假设在给定的样本集
D
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
⋯
,
(
x
m
,
y
m
)
}
,
y
i
∈
{
−
1
,
+
1
}
D=\left\{ \left( x_1,y_1 \right) ,\left( x_2,y_2 \right) ,\cdots ,\left( x_m,y_m \right) \right\} ,y_i\in \left\{ -1,+1 \right\}
D={(x1,y1),(x2,y2),⋯,(xm,ym)},yi∈{−1,+1}中,如图1所示:
SVM的目标是,如何选出最鲁棒的划分超平面(图中加粗的那个超平面)。
也就是在图2中找到最大间隔
γ
\gamma
γ 。
也就是:
max w , b 2 ∥ w ∥ s.t. y i ( w T x i + b ) ⩾ 1 , i = 1 , 2 , … , m . \begin{aligned} \max _{\boldsymbol{w}, b} & \frac{2}{\|\boldsymbol{w}\|} \\ \text { s.t. } & y_i\left(\boldsymbol{w}^{\mathrm{T}} \boldsymbol{x}_i+b\right) \geqslant 1, \quad i=1,2, \ldots, m . \end{aligned} w,bmax s.t. ∥w∥2yi(wTxi+b)⩾1,i=1,2,…,m.
又可以写为:
min w , b 1 2 ∥ w ∥ 2 s.t. y i ( w T x i + b ) ⩾ 1 , i = 1 , 2 , … , m . \begin{aligned} \min _{\boldsymbol{w}, b} & \frac{1}{2}\|\boldsymbol{w}\|^2 \\ \text { s.t. } & y_i\left(\boldsymbol{w}^{\mathrm{T}} \boldsymbol{x}_i+b\right) \geqslant 1, \quad i=1,2, \ldots, m . \end{aligned} w,bmin s.t. 21∥w∥2yi(wTxi+b)⩾1,i=1,2,…,m.
核函数
对于线性不可分样本,可将样本从原始空间映射到一个更高维的特征空间, 使得样本在这个特征空间内线性可分. 如图 3 :
模型可以类似的表示为
min
w
,
b
1
2
∥
w
∥
2
s.t.
y
i
(
w
T
ϕ
(
x
i
)
+
b
)
⩾
1
,
i
=
1
,
2
,
…
,
m
.
\begin{aligned} \min _{\boldsymbol{w}, b} & \frac{1}{2}\|\boldsymbol{w}\|^2 \\ \text { s.t. } & y_i\left(\boldsymbol{w}^{\mathrm{T}} \phi\left(\boldsymbol{x}_i\right)+b\right) \geqslant 1, \quad i=1,2, \ldots, m . \end{aligned}
w,bmin s.t. 21∥w∥2yi(wTϕ(xi)+b)⩾1,i=1,2,…,m.
其中常用的核函数有:
- 线性核: κ ( x i , x j ) = x i T x j \kappa \left( \boldsymbol{x}_{\mathrm{i}},\boldsymbol{x}_{\mathrm{j}} \right) =\boldsymbol{x}_{\mathrm{i}}^{\mathrm{T}}\boldsymbol{x}_{\mathrm{j}} κ(xi,xj)=xiTxj,
- 多项式核: κ ( x i , x j ) = ( x i T x j ) d \kappa \left( \boldsymbol{x}_{\mathrm{i}},\boldsymbol{x}_{\mathrm{j}} \right) =\left( \boldsymbol{x}_{\mathrm{i}}^{\mathrm{T}}\boldsymbol{x}_{\mathrm{j}} \right) ^d κ(xi,xj)=(xiTxj)d, d ⩾ 1 d \geqslant 1 d⩾1为多项式的次数
- 高斯核: κ ( x i , x j ) = exp ( − ∥ x i − x j ∥ 2 2 σ 2 ) \kappa \left( \boldsymbol{x}_{\mathrm{i}},\boldsymbol{x}_{\mathrm{j}} \right) =\exp \left( -\frac{\left\| \boldsymbol{x}_{\mathrm{i}}-\boldsymbol{x}_{\mathrm{j}} \right\| ^2}{2\sigma ^2} \right) κ(xi,xj)=exp(−2σ2∥xi−xj∥2), σ > 0 \sigma>0 σ>0 为高斯核的带宽(width)
- 拉普拉斯核: κ ( x i , x j ) = exp ( − ∥ x i − x j ∥ σ ) \kappa \left( \boldsymbol{x}_{\mathrm{i}},\boldsymbol{x}_{\mathrm{j}} \right) =\exp \left( -\frac{\left\| \boldsymbol{x}_{\mathrm{i}}-\boldsymbol{x}_{\mathrm{j}} \right\|}{\sigma} \right) κ(xi,xj)=exp(−σ∥xi−xj∥), σ > 0 \sigma>0 σ>0
- Sigmoid核: κ ( x i , x j ) = tanh ( β x i T x j + θ ) \kappa \left( \boldsymbol{x}_{\mathrm{i}},\boldsymbol{x}_{\mathrm{j}} \right) =\tanh \left( \beta \boldsymbol{x}_{\mathrm{i}}^{\mathrm{T}}\boldsymbol{x}_{\mathrm{j}}+\theta \right) κ(xi,xj)=tanh(βxiTxj+θ), tanh \tanh tanh 为双曲正切函数, β > 0 , θ < 0 \beta>0, \theta<0 β>0,θ<0
SVM代码实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
# 加载Sonar数据集
sonar_data = datasets.fetch_openml(name='sonar', version=1)
X_sonar, y_sonar = sonar_data.data, sonar_data.target
# 加载Iris数据集
iris_data = datasets.load_iris()
X_iris, y_iris = iris_data.data, iris_data.target
def train_and_evaluate(X, y, kernel, train_size=0.8):
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1-train_size, random_state=42)
# 特征标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# 训练SVM模型
svm_model = SVC(kernel=kernel)
svm_model.fit(X_train, y_train)
# 预测
y_pred = svm_model.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy with {kernel} kernel: {accuracy}")
return accuracy
sonar_acc = np.array([])
iris_acc = np.array([])
# 验证不同核函数下的性能(Sonar数据集)
print("Sonar dataset:")
kernels = ['linear', 'poly', 'rbf', 'sigmoid']
for kernel in kernels:
acc = train_and_evaluate(X_sonar, y_sonar, kernel)
sonar_acc = np.append(sonar_acc, acc)
# 验证不同核函数下的性能(Iris数据集)
print("\nIris dataset:")
for kernel in kernels:
acc = train_and_evaluate(X_iris, y_iris, kernel)
iris_acc = np.append(iris_acc, acc)
通过sklearn中的SVC函数,可以很方便的实现SVM算法。在这个函数中,可以替换很多不同的核函数,如linear——线性核函数,ploy——多项式核函数,rbf——高斯核函数,sigmoid核函数等等。在上述代码中,实现了对sonar,以及iris数据集的SVM分类,并分别使用了上述四种核函数进行对比。
结果分析
对于输出的结果做了可视化如下:
可见不论在哪个数据集中,核函数对最终正确率的影响都不小。而且核函数对正确率的影响会随数据集的特性变化而变化。因此,根据数据集选择合适的核函数是重要的。而SVM算法强大之处也在于核函数。
可视化代码:
import numpy as np
import matplotlib.pyplot as plt
# 生成柱状图
labels = ['linear', 'poly', 'rbf', 'sigmoid']
width = 0.35 # 柱状图的宽度
fig, ax = plt.subplots()
bar1 = ax.bar(np.arange(len(labels)), sonar_acc, width, edgecolor='k',
fc=(130 / 255, 176 / 255, 210 / 255),label='Sonar Accuracy')
bar2 = ax.bar(np.arange(len(labels)) + width, iris_acc, width, edgecolor='k',
fc=(250 / 255, 127 / 255, 111 / 255), label='Iris Accuracy')
# 添加标签和标题
ax.set_ylim(0.0, 1.25)
ax.set_xlabel('Kernel')
ax.set_ylabel('Accuracy')
ax.set_title('Sonar and Iris Accuracy Comparison')
ax.set_xticks(np.arange(len(labels)) + width / 2)
ax.set_xticklabels(labels)
ax.legend()
# 显示柱状图
plt.show()