机器学习中,支持向量机(SVM)是一种经典的分类算法,它的优势在于高效的性能与良好的泛化能力。简而言之,SVM就像一个能精准“分割”不同类别的高手,它通过找到一个最佳分割线(在高维空间中是超平面),来区分数据点。
接下来,我们从头开始,一步一步揭开SVM的神秘面纱。准备好了吗?让我们开始吧!
想象一下,你的任务是通过一条直线(或在高维空间中的超平面)将两种不同的物体分开。SVM的核心目标就是找出一条“最大间隔线”,使得这条线距离两类数据点的边界最远。最大间隔的意义是,越远离两类数据点的分类线,模型的泛化能力就越强,也就是分类的新数据误差更小。
具体来说,SVM会寻找一个“分割超平面”,这个超平面将数据集分成两类,同时使得到这个超平面的距离(也叫间隔)最大。这个距离是指支持向量(离超平面最近的点)到超平面的距离。 假设我们的数据集是二维的,分布在坐标平面上,如下图所示:
+------------------+------------------+
| | |
| 类别1 | 类别2 |
| | |
+------------------+------------------+
目标就是找到一条直线(二维中是直线,三维及以上是超平面),把两个类别的点分开,而且要求这条直线与离它最近的数据点之间的间隔最大。
假设我们有两个类别的数据点,分别用 ( +1 ) 和 ( -1 ) 表示。对于线性可分数据,SVM的目标是找到一个超平面:
其中:
是超平面的法向量(决定超平面的方向),
是偏置项(决定超平面的位置),
是输入数据。
为了最大化间隔,我们要求支持向量的距离最远。几何上,离超平面最近的点到超平面的距离是:
而我们希望这个距离最大化。所以,SVM的优化问题变成了一个求解最优
和
的问题:
约束条件是每个数据点的分类都正确,即:
这里,
是每个样本的标签,取值为
或
。
通过求解这个优化问题,我们可以得到最优的
和
,从而得到一个“最大间隔超平面”。
如下图所示:
问题来了:并不是所有数据集都能用直线(或者平面)完美分开,尤其是在高维数据或复杂数据的情况下。那么如何处理呢?这时核函数就登场了。
核函数的核心思想是,通过将数据映射到更高维的空间,使得数据变得线性可分。换句话说,核函数让我们不需要显式地计算高维空间中的映射,而是直接通过某些函数的计算来实现。
高斯核能够让SVM在复杂的、非线性的数据集上取得更好的效果。
选择合适的核函数非常关键,通常可以通过交叉验证来选择。
在实际问题中,我们不一定能得到完全线性可分的数据。在这种情况下,硬间隔(完全不允许错误分类)就不太适用了,SVM需要引入一个软间隔的概念。
软间隔允许某些点落在错误的侧面,但要求这些点离分隔面不太远。为了平衡分类误差和间隔的大小,SVM引入了一个惩罚参数 C,来控制这个平衡。
SVM的目标变成了同时最小化以下目标函数:
其中,
是每个数据点的松弛变量,用于衡量点是否被正确分类。
时,数据点被正确分类。
时,数据点分类错误,且该值越大,错误越严重。
这个公式确保了SVM能够在保证最大间隔的同时,允许一定的分类错误,从而处理现实中的非完美数据。
接下来,我们通过一个具体的建模实例来简单地理解SVM的使用。我们这次还是先使用一下经典的Iris鸢尾花数据集进行分类建模,在利用kaggle平台的数据集Wine dataset来加深一下理解。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import classification_report, accuracy_score
from sklearn.datasets import load_iris
# 加载Iris数据集
iris = load_iris()
X = iris.data
y = iris.target
# 数据集划分:80%训练集,20%测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 使用高斯RBF核
model = SVC(kernel='rbf', C=1, gamma='scale')
model.fit(X_train, y_train)
# 预测测试集结果
y_pred = model.predict(X_test)
# 打印分类报告与准确率
print(classification_report(y_test, y_pred))
print(f'Accuracy: {accuracy_score(y_test, y_pred)}')
# 可视化决策边界(仅适用于2D数据)
plt.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap='coolwarm', s=50, edgecolors='k')
plt.title('SVM Decision Boundary')
plt.show()
从上面可以看到SVM的分类工作做得很准确,这是因为lris数据集经过处理,特征很容易分辩的缘故,应用到其他数据集上SVM的效果不一定好,例如接下来的Wine数据集,没有经过特征处理它的效果很多模型都可以做到,但是同样的如果特征处理的方式得当,它的效果也是很多模型比不上的,这里我们先进行建模的演示,对于模型优化和特征处理这一块我们后续内容会逐步涉及到。
接下来,我们换一个不同的数据集来进行演示,来展示支持向量机(SVM)在实际中的应用。这里我们使用 Kaggle 上的经典 Wine 数据集,这是一个多分类问题的数据集,用来预测不同类型的葡萄酒。这个数据集具有不同的特征,适合展示 SVM 分类的能力。
首先,我们导入所需的 Python 库:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import classification_report, accuracy_score
Wine 数据集是一个包含 13 个化学成分特征的多分类数据集,用于分类 3 种不同类型的葡萄酒。
# 加载Wine数据集
wine = load_wine()
X = wine.data # 特征变量
y = wine.target # 标签(目标变量)
# 查看数据集的基本信息
print(f"Wine dataset features: {wine.feature_names}")
print(f"Wine dataset target labels: {wine.target_names}")
# 数据集划分:80% 训练集,20% 测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(f"Training set size: {X_train.shape[0]} samples")
print(f"Test set size: {X_test.shape[0]} samples")
我们使用高斯 RBF 核函数(径向基核函数),它在许多实际问题中表现非常好,尤其是当数据具有非线性关系时。
# 创建一个 SVM 模型,使用 RBF 核函数
model = SVC(kernel='rbf', C=1, gamma='scale')
# 训练模型
model.fit(X_train, y_train)
训练完模型后,我们使用测试集进行预测,并评估模型的表现。我们将使用准确率和分类报告来衡量模型效果。
# 使用模型对测试集进行预测
y_pred = model.predict(X_test)
# 输出分类报告
print(classification_report(y_test, y_pred, target_names=wine.target_names))
# 输出准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.4f}")
对于多维数据集(如 Wine 数据集),直接可视化所有特征的决策边界比较困难。我们可以通过降维(例如 PCA)将数据降到 2D,进而绘制决策边界。
这里我们先使用 PCA(主成分分析)将数据降到二维,再进行可视化。
from sklearn.decomposition import PCA
# 使用PCA将数据降至二维(仅用于可视化)
pca = PCA(n_components=2)
X_train_pca = pca.fit_transform(X_train)
X_test_pca = pca.transform(X_test)
# 创建并训练SVM模型(基于降维后的数据)
model_pca = SVC(kernel='rbf', C=1, gamma='scale')
model_pca.fit(X_train_pca, y_train)
# 预测并可视化
y_pred_pca = model_pca.predict(X_test_pca)
# 绘制数据点
plt.figure(figsize=(8, 6))
plt.scatter(X_test_pca[:, 0], X_test_pca[:, 1], c=y_test, cmap='coolwarm', s=50, edgecolors='k', marker='o', label='True labels')
# 绘制决策边界
xx, yy = np.meshgrid(np.linspace(X_test_pca[:, 0].min(), X_test_pca[:, 0].max(), 100),
np.linspace(X_test_pca[:, 1].min(), X_test_pca[:, 1].max(), 100))
Z = model_pca.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3, cmap='coolwarm')
plt.title('SVM Decision Boundary (PCA Reduced Wine Data)', fontsize=14)
plt.xlabel('PCA Component 1')
plt.ylabel('PCA Component 2')
plt.show()
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import classification_report, accuracy_score
from sklearn.datasets import load_wine
from sklearn.decomposition import PCA
# 加载Wine数据集
wine = load_wine()
X = wine.data # 特征变量
y = wine.target # 标签(目标变量)
# 数据集划分:80% 训练集,20% 测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建SVM模型,使用RBF核
model = SVC(kernel='rbf', C=1, gamma='scale')
model.fit(X_train, y_train)
# 使用模型对测试集进行预测
y_pred = model.predict(X_test)
# 输出分类报告与准确率
print(classification_report(y_test, y_pred, target_names=wine.target_names))
print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}")
# 可视化(降维到二维后)
pca = PCA(n_components=2)
X_train_pca = pca.fit_transform(X_train)
X_test_pca = pca.transform(X_test)
# 创建并训练SVM模型(基于降维后的数据)
model_pca = SVC(kernel='rbf', C=1, gamma='scale')
model_pca.fit(X_train_pca, y_train)
# 预测并可视化
y_pred_pca = model_pca.predict(X_test_pca)
# 绘制数据点
plt.figure(figsize=(8, 6))
plt.scatter(X_test_pca[:, 0], X_test_pca[:, 1], c=y_test, cmap='coolwarm', s=50, edgecolors='k', marker='o', label='True labels')
# 绘制决策边界
xx, yy = np.meshgrid(np.linspace(X_test_pca[:, 0].min(), X_test_pca[:, 0].max(), 100),
np.linspace(X_test_pca[:, 1].min(), X_test_pca[:, 1].max(), 100))
Z = model_pca.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3, cmap='coolwarm')
plt.title('SVM Decision Boundary (PCA Reduced Wine Data)', fontsize=14)
plt.xlabel('PCA Component 1')
plt.ylabel('PCA Component 2')
plt.show()
通过这个示例,我们使用了 Wine 数据集 来展示如何使用支持向量机(SVM)进行多分类任务。这个例子包括了数据预处理、模型训练、评估和降维可视化等常见步骤。SVM 在处理高维数据时,特别是在有非线性分布的数据上,表现出了强大的分类能力。
通过调整 C 和 gamma 等超参数,我们可以进一步优化模型的表现,提升准确率。此外,核函数的选择也会直接影响分类效果,例如线性核对于线性可分问题表现较好,而 RBF 核适合处理复杂的非线性问题。
这里我上传了一个wine数据集,和本文示例不同的是,该数据集是有八个葡萄酒分类,特征为quality列,所以使用时要仔细查看数据集中的数据。希望大家可以下载下来练习一遍,加深印象,如果有什么问题,也欢迎在评论区留言探讨。
你也可以将该代码示例应用到其他类似的数据集上,进一步探索 SVM 的强大能力。
这就是今天的内容。希望对你有帮助!如果你觉得内容有用,别忘了继续关注接下来的代码细节与更多机器算法相关,到这里各位到道友就快要不如金丹巅峰了,希望各位道友再接再厉。
Wine Quality dataset地址:https://www.kaggle.com/datasets/adarshde/wine-quality-dataset