支持向量机属于有监督学习算法,可以用于解决分类、回归和异常值检测问题。
本文主要讨论支持向量机解决分类问题。
通常存在多个决策边界(超平面)可以对数据进行划分,选择最大边缘(margin)的决策边界!根据统计学习理论,具有更大的边缘的决策边界有更好的泛化性。
数据即一系列自变量以及对应的因变量(分类标签)。
支持向量是最靠近决策边界的数据。根据拉格朗日对偶问题可证明,在边缘上的数据决定了决策边界及其边缘,而在边缘外的数据无任何作用,因此被称为支持向量。
其中,x为一系列属性,n为属性个数,w为属性对应的系数,和分别为决策边界两侧的支持向量,和分别为决策边界两侧的边缘边界,margin为边缘宽度。
为了最大化边缘 ,目标函数等价表示为:
因为要使得数据在边缘外,所以约束条件为:
等价于:
其中,y为标签值。
目标函数表示为:
其中,为对偶系数,N为数据个数,为数据与数据的核函数(kernel function),取决于核(kernel),通常有线性核、多项式核和sigmoid核等。
核(kernel)将数据从低维映射到高维,使之具有非线性能力。
核函数(kernel function)直接计算数据映射到高维之后的内积。
1.线性核(linear kernel)
2.多项式核(polynomial kernel)
其中,和r是系数,d为多项式的维数。
3.sigmoid核(sigmoid kernel)
约束条件表示为:
SVM的损失函数采用铰链损失,并且将目标函数和约束条件结合:
其中,为目标函数的权重,亦可理解为正则项的惩罚系数。
SVM采用梯度下降(Gradient Descend)进行优化
以kaggle数据集"Students' Academic Performance Dataset"为例
直接下载并使用"Students' Academic Performance Dataset" 数据集,读取数据
import pandas as pd
dataset = pd.read_csv('./Edu_Data.csv') # 读取csv文件中的数据
删除包含缺失值的数据,消除缺失值影响
dataset.dropna(axis=0, how='any', inplace=True) # 删除数据中存在缺失值的行
数据预处理。对有数值关系的字符型属性进行序数编码,对无数值关系的字符型属性进行独热编码
import category_encoders as ce
encoder_Ordinal = ce.OrdinalEncoder(
cols=['StageID', 'GradeID', 'SectionID', 'Semester', 'ParentschoolSatisfaction', 'StudentAbsenceDays']).fit(
dataset) # 对有序类别特征进行序数编码
encoder_Onehot = ce.OneHotEncoder(
cols=['gender', 'NationalITy', 'PlaceofBirth', 'Topic', 'Relation', 'ParentAnsweringSurvey'],
use_cat_names=True).fit(dataset) # 对无序类别特征进行独热编码
encoded_dataset = encoder_Onehot.transform(encoder_Ordinal.transform(dataset)) # 对数据集进行两次编码
因为支持向量机不具有缩放不变性,因此最好规范化数据范围。本文采用标准化。
from sklearn.preprocessing import StandardScaler # 用于对数值特征进行标准化
X = encoded_dataset.drop(['Class'], axis=1) # 从数据集中分离出特征矩阵X
y = encoded_dataset['Class'] # 从数据集中分离出标签向量y
pre_standard = StandardScaler().fit(X) # 用于对特征矩阵进行标准化,使其均值为0,方差为1
standard_dataset = pre_standard.transform(X) # 对特征矩阵进行标准化
Hold-out,划分训练集和测试集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33,
random_state=26) # 将数据集按照33%的比例划分为训练集和测试集,并设置随机种子为26
分别训练不同惩罚系数C下的线性核支持向量机和多项式核支持向量机
from sklearn.svm import SVC
import numpy as np
C_num = 10 # 设置惩罚参数C的取值范围
step = 10 # 设置步长
# 创建四个数组对象,用于存储不同核函数和不同惩罚参数下的训练集和测试集的准确率
linear_train_score = np.zeros(C_num)
linear_test_score = np.zeros(C_num)
polynomial_train_score = np.zeros(C_num)
polynomial_test_score = np.zeros(C_num)
# 使用for循环遍历不同的惩罚参数C的取值
for i in range(C_num):
linear_svc = SVC(C=1 + i * step, kernel='linear',
decision_function_shape='ovr')
linear_svc.fit(X_train, y_train)
linear_train_score[i] = linear_svc.score(X_train, y_train) # 计算并保存训练集上的准确率
linear_test_score[i] = linear_svc.score(X_test, y_test) # 计算并保存测试集上的准确率
poly_svc = SVC(C=1 + i * step, kernel='poly', degree=2,
decision_function_shape='ovr')
poly_svc.fit(X_train, y_train)
polynomial_train_score[i] = poly_svc.score(X_train, y_train) # 计算并保存训练集上的准确率
polynomial_test_score[i] = poly_svc.score(X_test, y_test) # 计算并保存测试集上的准确率
可视化不同惩罚系数下两种支持向量机分别在训练集和测试集下的准确率
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 8))
C_value = np.arange(1, C_num * step, step)
# 绘制不同核函数和不同惩罚参数下的训练集和测试集的准确率曲线,并添加图例
plt.plot(C_value, linear_train_score, label='linear_train_score')
plt.plot(C_value, linear_test_score, label='linear_test_score')
plt.plot(C_value, polynomial_train_score, label='poly_train_score')
plt.plot(C_value, polynomial_test_score, label='poly_test_score')
plt.legend(loc='center right', bbox_to_anchor=(1, 0.7))
plt.xlabel("C value")
plt.ylabel("Score")
plt.show()
结果如下:
因此训练一个C=31的线性核支持向量机模型
linear_svc = SVC(C=31, kernel='linear', decision_function_shape='ovr') # 创建一个线性核函数的SVM分类器,并设置惩罚参数C为31,决策函数形式为一对多(ovr)
linear_svc.fit(X_train, y_train) # 使用训练集拟合分类器模型
分别评估模型在训练集和测试集上的准确率
print("Score of train-set using linear kernel : {:.4f}".format(linear_svc.score(X_train, y_train))) # 打印训练集上的准确率
print("Score of test-set using linear kernel : {:.4f}".format(linear_svc.score(X_test, y_test))) # 打印测试集上的准确率
结果如下:
Score of train-set using linear kernel : 0.8754
Score of test-set using linear kernel : 0.7358
使用混淆矩阵(confusion-matrix)评估模型。
y_predict = linear_svc.predict(X_test) # 对测试集进行预测
print(pd.crosstab(y_test, y_predict, rownames=['true value'],
colnames=['predict value'])) # 创建一个交叉表,显示真实标签和预测标签之间的对应关系
结果如下:
predict value |
H | L | M |
true value | |||
H | 38 | 0 | 16 |
L | 2 | 34 | 9 |
M | 11 | 4 | 45 |