面试米哈游,奔溃。。。

文摘   2024-11-04 17:16   北京  

哈喽,我是kk~

最近有一位新人同学面试米哈游,差点奔溃,原因是问的内容太细致,可能自己在后面过于专注项目,导致对一些原理的细节,有些不太熟悉了,不过最后的结果还好,拿到了心心念念的offer。

咱们今天就从其中一个问题入手,也给大家聊聊:核支持向量机~

核支持向量机是支持向量机(SVM)的一个扩展,通过核技巧(Kernel Trick)解决了线性不可分问题,使得支持向量机能够处理高维甚至无限维的特征空间。为了详细阐述核支持向量机的原理及公式推导,我们先从支持向量机(SVM)的基础原理开始,然后逐步引入核技巧。

1. 基础原理

支持向量机的目标是找到一个超平面,能够将两类样本尽可能地分开,且最大化两类样本之间的间隔(margin)。

线性可分的SVM

假设我们有一个二分类问题,样本点由  表示,其中  是第  个样本的特征向量, 是其对应的类别标签。支持向量机要找到一个超平面来将样本点正确分类。

超平面的方程为:

其中, 是超平面的法向量, 是偏置项。

为了正确分类所有样本,超平面需要满足以下不等式条件:

这意味着所有的正样本()和负样本()必须位于超平面的两侧,且与超平面的距离至少为1。

间隔与优化问题

支持向量机的目标是最大化两个类别之间的几何间隔(geometric margin),几何间隔定义为:

因此,SVM的目标可以转换为最小化 ,同时保证所有样本满足分类约束条件。最终问题可以表示为以下的凸优化问题:

这是一个典型的凸二次规划问题(Quadratic Programming, QP),可以通过拉格朗日对偶方法求解。

对偶问题

为了引入核技巧,我们需要将SVM的原始问题转化为其对偶形式。首先,构造拉格朗日函数:

其中, 是拉格朗日乘子。

通过对  和  求拉格朗日函数的极值,我们可以得到:

将这些条件代入原拉格朗日函数并消去  和 ,可以得到SVM的对偶问题:

在对偶问题中,训练数据点仅通过其内积  出现。

2. 核技巧的引入

非线性问题

在实际应用中,数据往往是线性不可分的,即无法通过线性超平面将样本点分开。为了解决这个问题,可以将原始的特征空间通过一个非线性映射  映射到一个更高维甚至无限维的空间,使得在这个空间中数据是线性可分的。

核技巧的基本思想是:通过计算高维空间中向量的内积,而不显式地进行映射。

核函数

假设我们有一个映射函数 ,将样本点  映射到高维空间 。那么在对偶问题中,内积 就变成了 。为了避免显式地计算 ,我们引入核函数 ,定义为:

常用的核函数包括:

  • 线性核
  • 多项式核
  • 高斯核(RBF核):
  • Sigmoid核

通过核函数,原始的对偶问题变为:

这样,我们就可以通过求解这个对偶问题,在非线性映射的高维空间中找到一个线性分类器,而不需要显式地计算高维特征向量。

预测函数

经过训练后,支持向量机的决策函数为:

其中, 的点称为支持向量,这些点决定了分类超平面的位置。

3. 软间隔与核支持向量机

现实中,数据通常不是完全线性可分的,因此需要引入软间隔的概念。软间隔SVM允许某些点违反分类条件,即可以在约束中加入松弛变量 

优化目标则变为:

其中, 是一个正的惩罚参数,用于控制误分类样本的惩罚。

通过类似的推导,可以得到软间隔SVM的对偶问题以及核支持向量机的对应形式。此时的对偶问题

为:

总结来说,核支持向量机通过使用核函数将数据映射到高维空间,并在该空间中寻找一个线性分类器来解决原始的非线性分类问题。其核心思想是利用核技巧,避免显式地计算高维特征,同时通过对偶问题求解实现有效的训练。

下面,给大家举例一个关于核支持向量机的案例,并且给出完整的代码。

1. 导入必要的库

我们首先导入必要的库来生成数据、训练SVM模型以及可视化结果。

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
from sklearn.preprocessing import StandardScaler
import seaborn as sns
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm

2. 生成虚拟数据集

我们使用make_circles函数生成一个非线性可分的二维数据集。该数据集由两类样本构成,其中样本以同心圆的方式排列,这样可以直观地展示核支持向量机的非线性分类能力。

# 生成虚拟数据集:一个具有非线性结构的环形数据
X, y = datasets.make_circles(n_samples=1000, factor=0.5, noise=0.1)

# 将数据划分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 特征标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

在上面的代码中,我们生成了一个具有噪声的环形数据集,并将其分为训练集和测试集。我们还对数据进行了标准化处理,这对于SVM模型训练非常重要,因为它可以加快收敛速度。

3. 训练核支持向量机模型

接下来,我们使用SVC类训练一个带有RBF(径向基函数)的核支持向量机模型。

# 使用RBF核训练支持向量机模型
model = SVC(kernel='rbf', C=1, gamma='auto')
model.fit(X_train, y_train)

# 对测试集进行预测
y_pred = model.predict(X_test)

# 输出准确率
print(f"Accuracy: {accuracy_score(y_test, y_pred):.2f}")

在这里,我们使用了径向基函数(RBF)核来处理非线性问题。C参数控制着分类的软间隔,gamma参数定义了高斯核的宽度。

4. 性能评估

我们通过计算模型在测试集上的准确率、混淆矩阵以及分类报告来评估SVM的性能。

# 计算混淆矩阵
conf_matrix = confusion_matrix(y_test, y_pred)

# 显示分类报告
print("Classification Report:\n", classification_report(y_test, y_pred))

# 可视化混淆矩阵
plt.figure(figsize=(86))
sns.heatmap(conf_matrix, annot=True, fmt="d", cmap="YlGnBu", cbar=False)
plt.title('Confusion Matrix')
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
plt.show()

5. 绘制决策边界

接下来,我们绘制SVM的决策边界,以展示模型是如何将两类数据分开的。对于二维数据集,我们可以通过在特征空间中划分区域的方式来直观地展示分类结果。

# 创建网格用于绘制决策边界
xx, yy = np.meshgrid(np.linspace(X[:, 0].min() - 1, X[:, 0].max() + 1500),
                     np.linspace(X[:, 1].min() - 1, X[:, 1].max() + 1500))

# 使用模型预测网格点的类别
Z = model.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

# 绘制数据点和决策边界
plt.figure(figsize=(108))
plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 07), cmap=plt.cm.PuBu)
plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='darkred')

# 绘制训练集的样本点
plt.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=plt.cm.Paired, edgecolors='k')
plt.title('SVM Decision Boundary with RBF Kernel')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()

在这段代码中,我们通过生成网格点并用SVM模型的决策函数预测每个网格点的类别,绘制出了SVM的决策边界。通过颜色的变化可以清楚地看出SVM在数据空间中的分类效果。

6. 绘制三维决策边界图

为了进一步展示核支持向量机在高维空间中的决策能力,我们可以绘制一个三维的决策边界图,直观地展示模型的工作方式。

# 将特征映射到高维空间 (使用径向基函数核)
Z_train = np.exp(-(X_train[:, 0] ** 2 + X_train[:, 1] ** 2))

# 绘制三维图形
fig = plt.figure(figsize=(128))
ax = fig.add_subplot(111, projection='3d')

# 绘制正负类的点
ax.scatter(X_train[y_train == 00], X_train[y_train == 01], Z_train[y_train == 0], color='r', label='Class 0')
ax.scatter(X_train[y_train == 10], X_train[y_train == 11], Z_train[y_train == 1], color='b', label='Class 1')

# 绘制决策边界
ax.set_title('3D Visualization of Decision Boundary and Data Points')
ax.set_xlabel('Feature 1')
ax.set_ylabel('Feature 2')
ax.set_zlabel('Transformed Feature')
plt.legend()
plt.show()

在这段代码中,我们通过将特征映射到高维空间(这里是通过径向基函数将二维特征映射到三维),绘制出了SVM在这个高维空间中的表现。该图可以展示SVM是如何在高维空间中找到一个平面来区分两个类别的。

7. 完整Python代码

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
from sklearn.preprocessing import StandardScaler
import seaborn as sns
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm

# 1. 生成虚拟数据集:一个具有非线性结构的环形数据
X, y = datasets.make_circles(n_samples=1000, factor=0.5, noise=0.1)

# 将数据划分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 特征标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# 2. 使用RBF核训练支持向量机模型
model = SVC(kernel='rbf', C=1, gamma='auto')
model.fit(X_train, y_train)

# 对测试集进行预测
y_pred = model.predict(X_test)

# 输出准确率
print(f"Accuracy: {accuracy_score(y_test, y_pred):.2f}")

# 3. 计算混淆矩阵并可视化
conf_matrix = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(86))
sns.heatmap(conf_matrix, annot=True, fmt="d", cmap="YlGnBu", cbar=False)
plt.title('Confusion Matrix')
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
plt.show()

# 4. 绘制SVM决策边界
xx, yy = np.meshgrid(np.linspace(X[:, 0].min() - 1, X[:, 0].max() + 1500),
                     np.linspace(X[:, 1].min() - 1, X[:, 1].max() + 1500))
Z = model.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

plt.figure(figsize=(108))
plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 07), cmap=plt.cm.PuBu)
plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='darkred')
plt.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=plt.cm.Paired, edgecolors='k')
plt.title('SVM Decision Boundary with RBF Kernel')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()

# 5. 绘制三维决策边界
Z_train = np.exp(-(X_train[:, 0] ** 2 + X_train[:, 1] ** 2))
fig = plt.figure(figsize=(128))
ax = fig.add_subplot(111, projection='3d')

ax.scatter(X_train[y_train == 00], X_train[y_train == 01], Z_train[y_train == 0], color='r', label='Class 0')
ax.scatter(X_train[y_train == 10], X_train[y_train == 11], Z_train[y_train == 1], color='b', label='Class 1')
ax.set_title('3D Visualization of Decision Boundary and Data Points')
ax.set_xlabel('Feature 1')
ax.set_ylabel('Feature 2')
ax.set_zlabel('Transformed Feature')
plt.legend()
plt.show()

最后

通过使用核支持向量机,我们成功地解决了一个非线性分类问题。通过使用核函数(RBF核),SVM能够将原本不可分的数据映射到高维空间,在高维空间中找到最优的超平面进行分类。我们还通过可视化展示了SVM的决策边界以及高维空间中的分类过程,这帮助大家更好地理解了核支持向量机的工作原理。


下面是我们最近在和大家一起学习的内容,有兴趣可以扫码一起加入进来~



kk机器学习算法
机器学习基础、计算机视觉…
 最新文章