第4章:支持向量机
导入必要的库
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
import time
代码解释
import numpy as np
这行代码导入了numpy库,别名为np。numpy是一个强大的数学计算库,就像是我们手中的计算器,帮助我们进行各种数值运算。import matplotlib.pyplot as plt
matplotlib是一个用于绘制图表和数据可视化的库,pyplot是matplotlib的一个模块,通常用于绘制各种类型的图表。这就像是我们手中的画笔,帮助我们画出漂亮的图形。from sklearn import svm
从sklearn库中导入svm模块,svm是Support Vector Machine(支持向量机)的缩写。这是一个强大的分类算法,就像是一个聪明的分类器,能够找到最佳的分类边界。from sklearn.datasets import make_blobs
从sklearn库的datasets模块导入make_blobs函数,这个函数可以帮助我们生成用于分类的模拟数据。这就像是我们自己创造一些数据来测试我们的模型。from sklearn.preprocessing import StandardScaler
从sklearn库的preprocessing模块导入StandardScaler类,这个类用于数据的标准化处理。这就像是我们把不同尺度的数据统一到一个标准尺度,让模型更容易学习。from sklearn.model_selection import train_test_split
从sklearn库的model_selection模块导入train_test_split函数,用于将数据集划分为训练集和测试集。这样我们可以评估模型在未见过的数据上的表现。from sklearn.metrics import classification_report, confusion_matrix
从sklearn库的metrics模块导入classification_report和confusion_matrix函数,用于评估模型的性能。classification_report提供了精确率、召回率等指标,confusion_matrix则显示了预测结果的混淆矩阵。import seaborn as sns
导入seaborn库,这是一个基于matplotlib的高级可视化库,可以帮助我们创建更美观的统计图表,特别适合绘制混淆矩阵。import time
导入time模块,用于记录模型训练的时间,帮助我们了解模型的训练效率。
为什么需要数据标准化?
在机器学习中,数据标准化是一个重要的预处理步骤:
- 消除不同特征之间的量纲差异
- 使得所有特征都在相似的尺度上
- 加快模型的收敛速度
- 提高模型的数值稳定性
生成数据
def generate_data(n_samples=100, centers=2, random_state=42):
"""
生成随机数据
参数:
n_samples: 样本数量
centers: 类别数量
random_state: 随机种子
返回:
X: 特征矩阵
y: 标签数组
"""
try:
print(f"生成{centers}类{n_samples}个样本的随机数据...")
X, y = make_blobs(n_samples=n_samples, centers=centers, random_state=random_state)
return X, y
except Exception as e:
print(f"生成数据时出错: {str(e)}")
return None, None
代码解释
我们定义了一个generate_data
函数来生成随机数据。这个函数有三个参数:
n_samples
:要生成的样本数量,默认为100centers
:数据类别的数量,默认为2random_state
:随机种子,设置为42以确保每次运行代码时生成的数据都是一样的
函数使用try-except
结构来处理可能出现的错误,这样可以让程序更加健壮。在函数内部,我们使用make_blobs
函数生成随机数据,并返回特征矩阵X和标签数组y。如果出现错误,函数会打印错误信息并返回None。
数据标准化
def preprocess_data(X):
"""
数据预处理:标准化
参数:
X: 特征矩阵
返回:
标准化后的特征矩阵
"""
try:
print("对数据进行标准化处理...")
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
return X_scaled
except Exception as e:
print(f"数据预处理时出错: {str(e)}")
return None
代码解释
我们定义了一个preprocess_data
函数来对数据进行标准化处理。这个函数接收特征矩阵X作为输入,返回标准化后的特征矩阵。
函数内部使用StandardScaler
类来进行标准化处理:
- 创建
StandardScaler
对象 - 使用
fit_transform
方法计算数据的均值和标准差,并将数据转换为标准正态分布(均值为0,标准差为1)
同样,我们使用了try-except
结构来处理可能出现的错误,使程序更加健壮。如果出现错误,函数会打印错误信息并返回None。
训练和评估模型
def train_and_evaluate_model(X, y, kernel='linear'):
"""
训练和评估SVM模型
参数:
X: 特征矩阵
y: 标签数组
kernel: 核函数类型
返回:
model: 训练好的模型
metrics: 评估指标
"""
try:
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 训练模型
print(f"\n开始训练SVM模型 (kernel={kernel})...")
start_time = time.time()
model = svm.SVC(kernel=kernel)
model.fit(X_train, y_train)
training_time = time.time() - start_time
print(f"模型训练完成,用时: {training_time:.2f}秒")
# 评估模型
train_score = model.score(X_train, y_train)
test_score = model.score(X_test, y_test)
# 预测
y_pred = model.predict(X_test)
# 计算评估指标
metrics = {
'train_score': train_score,
'test_score': test_score,
'training_time': training_time,
'classification_report': classification_report(y_test, y_pred),
'confusion_matrix': confusion_matrix(y_test, y_pred)
}
return model, metrics, X_test, y_test
except Exception as e:
print(f"训练模型时出错: {str(e)}")
return None, None, None, None
代码解释
我们定义了一个train_and_evaluate_model
函数来训练和评估SVM模型。这个函数有三个参数:
X
:特征矩阵y
:标签数组kernel
:核函数类型,默认为'linear'(线性核函数)
函数的主要步骤包括:
- 使用
train_test_split
函数将数据集划分为训练集(80%)和测试集(20%) - 创建并训练SVM模型,同时记录训练时间
- 评估模型性能,包括:
- 计算训练集和测试集的准确率
- 使用模型进行预测
- 生成分类报告(包含精确率、召回率等指标)
- 计算混淆矩阵
同样使用了try-except
结构来处理可能出现的错误。
支持向量
SVM 通过找到一个最优的超平面来实现分类:
- 最大化分类边界(margin)
- 只关注支持向量(最靠近分类边界的点)
- 可以通过核技巧处理非线性可分的数据
这就像是在选择两类点之间画一条线,使得:
- 线两边的点尽可能分开
- 线到最近的点的距离尽可能大
可视化结果
def plot_decision_boundary(model, X, y):
"""
绘制决策边界
参数:
model: 训练好的SVM模型
X: 特征矩阵
y: 标签数组
"""
try:
print("\n绘制决策边界...")
# 创建网格点
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
np.arange(y_min, y_max, 0.02))
# 预测网格点的类别
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# 绘制结果
plt.figure(figsize=(10, 8))
plt.contourf(xx, yy, Z, alpha=0.4, cmap='coolwarm')
plt.scatter(X[:, 0], X[:, 1], c=y, alpha=0.8, cmap='coolwarm')
plt.title('SVM分类结果')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.colorbar(label='类别')
plt.show()
except Exception as e:
print(f"绘制决策边界时出错: {str(e)}")
def plot_confusion_matrix(cm):
"""
绘制混淆矩阵
参数:
cm: 混淆矩阵
"""
try:
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.title('混淆矩阵')
plt.xlabel('预测标签')
plt.ylabel('真实标签')
plt.show()
except Exception as e:
print(f"绘制混淆矩阵时出错: {str(e)}")
代码解释
我们定义了两个可视化函数:
plot_decision_boundary
函数用于绘制决策边界:- 首先计算数据的范围,并稍微扩大以显示完整的分类边界
- 使用
np.meshgrid
创建一个网格,网格点将用于绘制分类边界 - 使用训练好的模型预测网格中每个点的类别
- 使用
plt.contourf
绘制分类边界,使用plt.scatter
绘制数据点 - 添加标题、坐标轴标签和颜色条
plot_confusion_matrix
函数用于绘制混淆矩阵:- 使用
seaborn
库的heatmap
函数绘制混淆矩阵 - 设置合适的图形大小和颜色方案
- 添加标题和坐标轴标签
- 使用
两个函数都使用了try-except
结构来处理可能出现的错误。
主函数
def main():
# 生成数据
X, y = generate_data(n_samples=200, centers=2)
if X is None or y is None:
return
# 数据预处理
X_scaled = preprocess_data(X)
if X_scaled is None:
return
# 训练和评估模型
model, metrics, X_test, y_test = train_and_evaluate_model(X_scaled, y)
if model is None or metrics is None:
return
# 打印评估结果
print("\n模型评估结果:")
print(f"训练集准确率: {metrics['train_score']:.4f}")
print(f"测试集准确率: {metrics['test_score']:.4f}")
print(f"训练用时: {metrics['training_time']:.2f}秒")
print("\n分类报告:")
print(metrics['classification_report'])
# 绘制混淆矩阵
plot_confusion_matrix(metrics['confusion_matrix'])
# 绘制决策边界
plot_decision_boundary(model, X_scaled, y)
if __name__ == "__main__":
main()
代码解释
主函数main()
按照以下步骤执行:
- 生成200个样本的随机数据,分为2类
- 对数据进行标准化处理
- 训练SVM模型并进行评估
- 打印模型的评估结果,包括:
- 训练集和测试集的准确率
- 模型训练时间
- 详细的分类报告
- 可视化结果:
- 绘制混淆矩阵
- 绘制决策边界
每个步骤都有错误检查,如果前面的步骤出错,程序会提前退出。
总结
支持向量机(SVM)是一个强大的分类算法,它通过找到一个最优的超平面来分隔不同类别的数据。在这个例子中,我们实现了一个完整的SVM分类器,包括:
- 数据准备:生成随机数据并进行标准化
- 模型训练:使用线性核函数训练SVM模型
- 模型评估:计算准确率、生成分类报告和混淆矩阵
- 结果可视化:绘制决策边界和混淆矩阵
SVM的一个重要特点是它只关注支持向量(即最靠近分类边界的点),这使得它对噪声数据具有较强的鲁棒性。在实际应用中,我们还可以使用其他核函数(如RBF核)来处理更复杂的非线性分类问题。
代码中使用了异常处理和函数模块化的设计,使得程序更加健壮和易于维护。同时,通过详细的评估指标和可视化结果,我们可以更好地理解模型的性能。