目录
一、最大间隔与分类
最大间隔分类(Maximum Margin Classification)是支持向量机(Support Vector Machine,SVM)的基本概念之一。在介绍最大间隔分类之前,我们先来了解一下支持向量机。
支持向量机是一种常用的监督学习算法,用于分类和回彏问题。在分类问题中,支持向量机的目标是找到一个超平面,将不同类别的数据点有效地分开,并且使得间隔最大化。这里的“间隔”指的是超平面与最靠近它的数据点之间的距离,而支持向量就是距离超平面最近的那些数据点。
最大间隔分类的核心思想是要找到一个超平面,使得训练数据中每个类别的支持向量到超平面的距离尽可能远,同时确保所有数据点都被正确地分类。这样的超平面可以被认为是对数据的良好泛化能力的体现,因为它尽可能地远离每个类别的数据点,从而更有可能对新的数据进行准确分类。
在支持向量机的求解过程中,最大间隔分类使用了优化算法,例如拉格朗日乘子法,来求解一个凸优化问题,以找到最优的超平面来进行分类。
总的来说,最大间隔分类通过寻找一个具有最大间隔的超平面来进行数据分类,使得分类能力更强,对未知数据的泛化性能更好。
(一)最大间隔与分类
超平面方程:
二、对偶问题
在支持向量机(Support Vector Machine,SVM)中,对偶函数也扮演着重要的角色。通过引入拉格朗日乘子法,我们可以将原始的凸优化问题转化为对偶问题,并且求解对偶问题可以帮助我们得到支持向量机的最优解。
对于支持向量机的原始问题,我们希望找到一个超平面,使得训练数据点到该超平面的间隔最大化,同时满足分类的准确性要求。这个原始问题可以表示为以下形式:
minimize f(w, b) = (1/2) * ||w||^2 - Σ αi * [yi * (w·xi + b) - 1]
其中,w 是超平面的法向量,b 是超平面的截距,xi 是训练样本,yi 是样本的标签(1或-1),αi 是拉格朗日乘子。
通过求解这个原始问题的拉格朗日函数的对偶问题,我们可以得到支持向量机的最优解。对偶问题的目标是最大化对偶函数,可以表示为以下形式:
maximize g(α) = Σ αi - (1/2) * Σ Σ αi * αj * yi * yj * xi·xj
其中,α 是对偶变量,需要满足条件 0 ≤ αi ≤ C,C 是一个正常数。
在求解对偶问题时,我们通过最大化对偶函数 g(α) 来找到最优的对偶变量 α。然后,我们可以利用对偶变量 α 来计算超平面的参数 w 和 b,并得到最终的支持向量机分类器。
对偶函数在支持向量机中的作用主要体现在以下两个方面:
·对偶函数提供了一种求解支持向量机的方法。通过求解对偶问题,我们可以得到支持向量机的最优解,即最佳的超平面划分。
·对偶函数可以帮助我们理解支持向量机的性质。例如,对偶变量 α 可以用于确定支持向量,即距离超平面最近的训练样本点,它们对决策边界的位置和形状起着关键作用。
总结来说,对偶函数在支持向量机中是通过求解对偶问题来得到最优解的关键部分。它提供了一种求解支持向量机的方法,并且对支持向量机的性质有重要的解释作用。
(一)对偶问题:等式约束
一般联立方程组可以得到相应的解。
(二)对偶问题:不等式约束的KKT条件
将约束等式g(x)=0推广为不等式g(x)≤0。这个约束优化问题可改为:
同理,其拉格朗日函数为:
其约束范围为不等式,因此可等价转化成Karush-Kuhn-Tucker(KKT)条件:
在此基础上,通过优化方式(如二次规划或SMO)求解其最优解。
(三)对偶问题:KKT条件的几何解释
三、核函数
在支持向量机(SVM)中,核函数是一种能够将输入特征映射到高维特征空间的函数。通过使用核函数,SVM 在高维特征空间中进行非线性分类,即使在原始特征空间中无法线性分离的情况下也能够实现有效的分类。
核函数的作用是通过将输入数据映射到高维特征空间,在该空间中可以更容易地进行线性分类。通过这种方式,我们可以克服原始特征空间中线性不可分的问题。
常用的核函数包括线性核、多项式核、高斯径向基核(RBF核)等。这些核函数具有不同的特性,适用于不同类型的数据和问题。以下是几种常见的核函数及其表达式:
·线性核函数: K(x, y) = x·y
·多项式核函数: K(x, y) = (x·y + c)^d 其中,c 是偏置项,d 是多项式的次数。
·高斯径向基核(RBF核): K(x, y) = exp(-γ * ||x - y||^2) 其中,γ 是一个控制高斯核宽度的超参数。
通过使用这些核函数,SVM 可以在高维特征空间中对数据进行有效的划分,从而实现非线性分类任务。值得注意的是,选择合适的核函数和调节相应的参数是很重要的,这会直接影响到支持向量机的性能和泛化能力。
总之,核函数在支持向量机中扮演着至关重要的角色,通过将输入数据映射到高维特征空间,SVM 可以更好地进行非线性分类,提高了模型的表达能力和泛化能力。
(一)核函数:线性不可分—高维可分
(二)核函数:核支持向量机
(三)核函数
四、软间隔与正则化
软间隔与正则化是支持向量机(SVM)中常用的两种技术,用于提高模型的鲁棒性和泛化能力。
·软间隔: 硬间隔指的是当数据完全线性可分时,SVM会选择最大化分类边界与最近的样本点之间的间隔。但实际上,现实中很少有数据满足完全线性可分的条件。因此,为了使模型更加鲁棒,SVM引入了软间隔的概念。软间隔允许一些数据点处于分类边界的错误一侧,并使用松弛变量来量化这些错误。通过使用软间隔,SVM可以在一定程度上容忍噪声和异常数据,并且具有更好的泛化能力。
·正则化: 正则化是一种通过添加额外约束来防止模型过拟合的方法。在SVM中,正则化通常通过添加惩罚项来实现。这个惩罚项通常被称为L1或L2正则化,它们的目标是减小模型复杂度并在一定程度上防止过拟合。L1正则化通常会使得模型产生稀疏解,即许多特征的权重被压缩到0,因此可以用于特征选择。L2正则化则可以使得模型的权重更加平滑,避免过度依赖少数特征。
总之,软间隔和正则化是SVM中常用的两种技术,用于提高模型的鲁棒性和泛化能力。软间隔通过容忍一定程度的错误来适应不完全线性可分的数据,而正则化则通过对模型复杂度的惩罚来防止过拟合。
部分样本允许: 称为松弛变量
(一)软间隔与正则化:损失函数
基本思路:最大化间隔的同时,让不满足约束的样本应尽可能少
其中C>0为惩罚参数,l0/1是”0/1损失函数”
存在问题:0/1损失函数非凸、非连续,不易优化!
替代损失
替代损失函数数学性质较好,一般是0/1损失函数的上界
(二)软间隔与正则化:HingeLoss
支持向量机学习模型的更一般形式
(三)软间隔与正则化
五、支持向量回归
支持向量回归(Support Vector Regression,SVR)是一种利用支持向量机(SVM)进行回归任务的方法。与传统的线性回归方法不同,SVR可以应对非线性关系和异常值,并具有较好的泛化能力。
SVR的目标是找到一个函数,使得样本点尽可能地位于该函数所构成的“间隔带”内。这个“间隔带”由两条平行的边界线定义,称为“上界”和“下界”。在SVR中,我们希望让样本点尽可能地落在这个间隔带中,同时允许一定程度的误差。误差的大小由用户指定的参数ε来控制。
SVR模型的训练过程包括以下几个步骤:
·将原始的输入样本映射到高维特征空间(通过核函数实现)。
·在高维特征空间中,构建一个边界带,使得样本点尽可能地落在带内。带的宽度由参数ε控制。
·通过最小化目标函数,寻找在间隔带内的最佳回归函数。
·根据回归函数,对新样本进行预测。
SVR使用的损失函数是ε不敏感损失函数。其中,对于落在间隔带内的样本,损失为0;对于落在间隔带外的样本,损失与其距离ε成正比。通过最小化损失函数,SVR可以找到最佳的回归函数。
在实际应用中,SVR可以根据不同的核函数(如线性核、多项式核、径向基核等)来适应不同类型的数据和问题。同时,通过调节参数C和ε,可以控制模型的复杂度和容忍误差的程度。
总结起来,支持向量回归是一种利用支持向量机进行回归任务的方法。它通过构建边界带,允许一定程度的误差,并使用支持向量机的优化算法来寻找最佳的回归函数。SVR具有较好的泛化能力和对非线性关系的适应能力。
(一)支持向量回归:损失函数
(二)支持向量回归:形式化
六、支持向量机实战—乳腺癌检测
本文使用支持向量机算法解决乳腺癌检测问题。scikit-learn
中自带一个乳腺癌数据集,为了方便起见,我们直接使用
首先,我们加载数据,输出数据形状和特征。以查看数据:
__author__ = "fpZRobert"
"""
支持向量机实战-乳腺癌检测
"""
import warnings
warnings.filterwarnings("ignore", category=FutureWarning, module="sklearn", lineno=196)
from sklearn.datasets import load_breast_cancer
"""
加载数据
"""
cancer = load_breast_cancer()
X = cancer.data
y = cancer.target
print("Shape of X: {0}; positive example: {1}; negative: {2}".format(X.shape, y[y==1].shape[0], y[y==0].shape[0])) # 查看数据的形状和类别分布
Out:
Shape of X: (569, 30); positive example: 357; negative: 212
我们可以看到,数据集总共有569个样本,每个样本有30个特征,其中357个阳性(y=1)样本,212个阴性(y=0)样本。
把数据集划分为训练集和测试集(划分比例一般80%用于训练,20%用于测试):
"""
拆分数据集
"""
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
根据上述数据的介绍,我们的数据集很少,高斯核函数太复杂,容易造成过拟合,模型效果不会很好。为了验证我们的猜想,我们首先使用高斯核函数试着拟合数据,看下效果:
"""
训练模型
"""
from sklearn.svm import SVC
clf = SVC(C=1.0, kernel="rbf", gamma=0.1) # 使用高斯核函数
clf.fit(X_train, y_train)
train_score = clf.score(X_train, y_train)
test_score = clf.score(X_test, y_test)
print("train score: {0}; test score: {1}".format(train_score, test_score))
Out:
train score: 1.0; test score: 0.631578947368421
训练数据集评分接近满分,而交叉验证集评分很低,这是典型的过拟合现象。我们画出学习曲线,更加直观的看一下:
"""
绘制学习曲线
"""
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import ShuffleSplit
from sklearn.model_selection import learning_curve
# 绘制学习曲线
def plot_learning_curve(plt, estimator, title, X, y, ylim=None, cv=None,
n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5)):
plt.title(title)
if ylim is not None:
plt.ylim(*ylim)
plt.xlabel("Training examples")
plt.ylabel("Score")
train_sizes, train_scores, test_scores = learning_curve(
estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes)
train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)
plt.grid()
plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
train_scores_mean + train_scores_std, alpha=0.1,
color="r")
plt.fill_between(train_sizes, test_scores_mean - test_scores_std,
test_scores_mean + test_scores_std, alpha=0.1, color="g")
plt.plot(train_sizes, train_scores_mean, 'o--', color="r",
label="Training score")
plt.plot(train_sizes, test_scores_mean, 'o-', color="g",
label="Cross-validation score")
plt.legend(loc="best")
return plt
cv = ShuffleSplit(n_splits=10, test_size=0.2, random_state=0)
title = "Learning Curves for Gaussian Kernel"
plt.figure(figsize=(10, 4), dpi=144)
plot_learning_curve(plt, SVC(C=1.0, kernel="rbf", gamma=0.01), title, X, y, ylim=(0.5, 1.01), cv=cv)
plt.show()
代码中gamma
的参数选择为0.1,这个值相对已经很小了。通过上述参数介绍,我们知道gamma
是核函数的系数(gamma
值越小,支持向量越多)。我们试着利用之前讲过的GridSearchCV
来自动选择参数:
"""
模型调优
"""
from sklearn.model_selection import GridSearchCV
gammas = np.linspace(0, 0.0003, 30)
param_grid = {"gamma": gammas}
clf = GridSearchCV(SVC(), param_grid, cv=5)
clf.fit(X, y)
print(" best param: {0}\n best score: {1}".format(clf.best_params_, clf.best_score_))
Out:
best score: 0.9367311072056239
gamma是选择RBF函数作为kernel后,该函数自带的一个参数。隐含地决定了数据映射到新的特征空间后的分布,gamma越大,支持向量越少,gamma值越小,支持向量越多。支持向量的个数影响训练与预测的速度。通过GridSearchCV我们选择了最优gamma参数,交叉验证集的评分增加了不少,是不是此时的模型就是最好的呢?我们来换个模型,使用二阶多项式核函数来拟合模型,看看结果如何:
"""
训练模型: 二阶多项式核函数
"""
clf = SVC(C=1.0, kernel="poly", degree=2)
clf.fit(X_train, y_train)
train_score = clf.score(X_train, y_train)
test_score = clf.score(X_test, y_test)
print("train score: {0}; test score: {1}".format(train_score, test_score))
Out:
train score: 0.9824175824175824; test score: 0.956140350877193
从上述结果,可以看出效果比使用RBF
核函数效果要好。作为对比,我们画出一阶多项式核二阶多项式的学习曲线,观察数据的拟合情况:
"""
绘制学习曲线
"""
cv = ShuffleSplit(n_splits=5, test_size=0.2, random_state=0)
title = "Learning Curves with degree={0}"
degrees = [1, 2]
plt.figure(figsize=(12, 4), dpi=144)
for i in range(len(degrees)):
plt.subplot(1, len(degrees), i+1)
plot_learning_curve(plt, SVC(C=1.0, kernel="poly", degree=degrees[i]), title.format(degrees[i]), X, y, ylim=(0.8, 1.01), cv=cv)
plt.show()
从图中可以看书,二阶多项式核函数的拟合效果更好。平均交叉验证集评分高达0.950,最高时达到0.975。运行该段代码需要注意,二阶多项式核函数计算代价很高,可能需要运行很长时间,请耐心等待结果。
我们使用逻辑回归算法来进行乳腺癌的预测,使用二项多项式增加特征,同时使用L1范数作为正则项,其拟合效果不仅比支持向量机好,而且在运算效率和计算代价上,远远好于二阶多项式核函数的支持向量机。当然,这里的支持向量机算法并未经过严谨的参数调优过程,但结果还是比使用L2范数的逻辑回归算法好,这里,我想表达的是:模型选择和参数调优,在工程实践中具有非常重要的作用。我们不仅需要掌握参数调优的科学方法,而且还需要了解各算法的适用场景和问题,以便选择最合适的算法模型去解决实际问题。
全部代码:
# -*- coding: utf-8 -*-
# Time:2019/4/1 16:48
# versions:Python 3.6
__author__ = "fpZRobert"
"""
支持向量机实战-乳腺癌检测
"""
import warnings
warnings.filterwarnings("ignore", category=FutureWarning, module="sklearn", lineno=196)
from sklearn.svm import SVC
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import ShuffleSplit
from sklearn.model_selection import learning_curve
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
"""
加载数据
"""
cancer = load_breast_cancer()
X = cancer.data
y = cancer.target
print("Shape of X: {0}; positive example: {1}; negative: {2}".format(X.shape, y[y==1].shape[0], y[y==0].shape[0])) # 查看数据的形状和类别分布
"""
拆分数据集
"""
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
"""
训练模型: RBF核函数
"""
clf = SVC(C=1.0, kernel="rbf", gamma=0.1)
clf.fit(X_train, y_train)
train_score = clf.score(X_train, y_train)
test_score = clf.score(X_test, y_test)
print("train score: {0}; test score: {1}".format(train_score, test_score))
"""
绘制学习曲线
"""
# 绘制学习曲线
def plot_learning_curve(plt, estimator, title, X, y, ylim=None, cv=None,
n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5)):
plt.title(title)
if ylim is not None:
plt.ylim(*ylim)
plt.xlabel("Training examples")
plt.ylabel("Score")
train_sizes, train_scores, test_scores = learning_curve(
estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes)
train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)
plt.grid()
plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
train_scores_mean + train_scores_std, alpha=0.1,
color="r")
plt.fill_between(train_sizes, test_scores_mean - test_scores_std,
test_scores_mean + test_scores_std, alpha=0.1, color="g")
plt.plot(train_sizes, train_scores_mean, 'o--', color="r",
label="Training score")
plt.plot(train_sizes, test_scores_mean, 'o-', color="g",
label="Cross-validation score")
plt.legend(loc="best")
return plt
cv = ShuffleSplit(n_splits=10, test_size=0.2, random_state=0)
title = "Learning Curves for Gaussian Kernel"
plt.figure(figsize=(10, 4), dpi=144)
plot_learning_curve(plt, SVC(C=1.0, kernel="rbf", gamma=0.01), title, X, y, ylim=(0.5, 1.01), cv=cv)
plt.show()
"""
模型调优
"""
gammas = np.linspace(0, 0.0003, 30)
param_grid = {"gamma": gammas}
clf = GridSearchCV(SVC(), param_grid, cv=5)
clf.fit(X, y)
print("best param: {0}\n best score: {1}".format(clf.best_params_, clf.best_score_))
"""
训练模型: 二阶多项式核函数
"""
clf = SVC(C=1.0, kernel="poly", degree=2)
clf.fit(X_train, y_train)
train_score = clf.score(X_train, y_train)
test_score = clf.score(X_test, y_test)
print("train score: {0}; test score: {1}".format(train_score, test_score))
"""
绘制学习曲线
"""
cv = ShuffleSplit(n_splits=5, test_size=0.2, random_state=0)
title = "Learning Curves with degree={0}"
degrees = [1, 2]
plt.figure(figsize=(12, 4), dpi=144)
for i in range(len(degrees)):
plt.subplot(1, len(degrees), i+1)
plot_learning_curve(plt, SVC(C=1.0, kernel="poly", degree=degrees[i]), title.format(degrees[i]), X, y, ylim=(0.8, 1.01), cv=cv)
plt.show()
七、总结
支持向量机(Support Vector Machine,SVM)是一种常用的机器学习算法,可以用于分类和回归问题。下面是对支持向量机实验的一个总结:
·数据准备:首先,需要准备用于实验的数据集。数据集应包含带有标签的训练样本,以及可能的测试样本。确保数据集经过预处理和特征选择,以提高模型性能。
·特征工程:根据实际问题,进行特征工程以提取有效的特征。可以使用领域知识或特征选择算法来选择最相关的特征。合适的特征可以提高SVM的分类或回归性能。
·模型选择:根据问题类型,选择合适的SVM模型。对于二分类问题,可以使用线性SVM或非线性SVM(通过核函数进行映射)。对于多类分类问题,可以使用一对多(one-vs-rest)或一对一(one-vs-one)的策略。
·参数调优:SVM有一些重要的参数需要调优,如正则化参数C、核函数的参数等。通过交叉验证等技术,选择合适的参数组合以获得最佳的模型性能。
·模型训练:使用训练数据对SVM模型进行训练。在训练过程中,SVM通过最大化间隔或最小化误差来找到一个最佳的分类或回归超平面。
·模型评估:使用测试数据对训练好的模型进行评估。常见的评估指标包括准确率、精确率、召回率、F1分数等。这些指标可以帮助评估模型的性能和泛化能力。
·结果分析:分析模型的结果以获得洞见。可以进一步探索模型的错误分类样本,并考虑调整特征工程或参数选择策略。
在实验中,还可以尝试其他技术,如特征降维、集成学习等,以进一步提升SVM模型的性能。
总体而言,支持向量机是一种强大且灵活的机器学习算法,可以应用于各种分类和回归问题。通过合适的数据准备、特征工程、模型选择和参数调优,可以构建出高性能的支持向量机模型。