支持向量机(SVM)广泛应用于模式分类和非线性回归领域。 SVM算法的原始形式由Vladimir N.Vapnik和Alexey Ya提出。自从那以后,SVM已经被巨大地改变以成功地用于许多现实世界问题。
1.什么是支持向量机(SVM)?
支持向量机是一种有监督的机器学习算法,可用于分类和回归问题。它遵循一种用核函数技巧来转换数据的技术,并且基于这些转换,它找到可能输出之间的最佳边界。简单来说,它做一些非常复杂的数据转换,以找出如何根据标签或输出定义的数据分离。本文我们将看到SVM分类算法如何通过python实现并可视化。
2.SVM的原理
寻找一个分离超平面,使得它到各分类的平均距离是最大的。
什么是分离超平面?
把数据划分为多个类别的一个图形,如线、面、超平面,我们统称为超平面。一个最简单的示例,即数据集位于2维平面中,一条线就可以把样本分成两类。但是支持向量机也可以用于一般的n维数据集,所以我们统称超平面。更正式地说,它是n维欧几里德空间的n-1维子空间。
所以一个
- 1维数据集,单点表示超平面。
- 2维数据集,线是超平面。
- 3维数据集,平面是超平面。
- 在更高的维度上,就被称为超平面。
SVM的目标是找到最佳分离超平面。那么什么时候分离超平面是最优的?让我们通过一组图来理解最佳超平面。有多个超平面,但其中哪一个是分离超平面? 可以很容易地看出,线B是比较好地分离这两个类的线,但我们如何计算出来最佳的超平面呢?
直观地,如果我们选择接近一个类的数据点的超平面,那么它可能不能很好地推广。因此,要选择尽可能远离每个类别的数据点的超平面。
在上图中,满足指定条件的最佳超平面为B。
因此,最大化每个类的最近点和超平面之间的距离就能找到最优分离超平面。这个距离称为边距,下图是边距的计算原理图。
SVM的目标是找到最佳超平面,因为它不仅分类现有数据集,而且有助于预测未知数据的类。最优超平面是边距最大的平面。
3、支持向量机的优缺点
每个分类算法都有自己的优点和缺点,它们根据正在分析的数据集发挥作用。
SVM的一些优点如下:
- 凸优化方法的本质是保证最优性。该解决方案保证是全局最小值,而不是局部最小值
- SVM是一种适用于线性和非线性可分离数据(使用核函数技巧)的算法。唯一要做的是找出正则化项C
- SVM在低维和高维数据空间上工作良好。它能有效地对高维数据集工作,因为SVM中的训练数据集的复杂度通常由支持向量的数量而不是维度来表征。即使删除所有其他训练示例并重复训练,我们将获得相同的最佳分离超平面。
- SVM可以在较小的训练数据集上工作,因为它们不依赖于整个数据。
SVM的缺点如下:
- 它们不适合较大的数据集,因为在较大的数据集上使用SVM的训练时间可能很高,并且计算量更大。
- 它们在具有重叠类的嘈杂数据集上效率较低。
4、Python实现
4.1 加载需要用到的模块
- import numpy as np
- from sklearn import datasets
- from sklearn.pipeline import Pipeline
- from sklearn.svm import SVC
- import seaborn as sns
- import pandas as pd
- from sklearn.model_selection import cross_val_score
- from sklearn.grid_search import GridSearchCV
- from sklearn.model_selection import train_test_split
- from sklearn.metrics import accuracy_score
- import matplotlib.pyplot as plt
4.2 初始化数据
从datasets数据集中加载iris数据,提取data中的两列作为特征值,提取target为分类值,并把特征值和分类值转换为pandas的DataFrame数据框,并合并到data中,重命名各特征为x1,x2和y。
找出x1和x2的最大值和最小值,生成满布坐标系的点,用于描绘超平面。
- iris = datasets.load_iris()
- X = iris['data'][:,[2,3]]
- y = iris['target']
- X = pd.DataFrame(X)
- y = pd.DataFrame(y)
- data = pd.merge(X,y,left_index=True,right_index=True,how='outer')
- data.columns=['x1','x2','y']
- h = 0.002
- x_min, x_max = data.x1.min() - 0.2, data.x1.max() + 0.2
- y_min, y_max = data.x2.min() - 0.2, data.x2.max() + 0.2
- xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
- np.arange(y_min, y_max, h))
- sns.scatterplot(data.x1, y=data.x2,hue=data.y)
- X = data[['x1','x2']]
- y = data.y
我们用seaborn的scatterplot把x1和x2用散点图描绘出来,如下图。
在这个图中我们看到有三个分类,接下来我们用SVM支持向量机为这些训练数据建立一个模型。
4.3 线性SVM模型
- X_train,X_val,y_train,y_val = train_test_split(X,y,test_size=0.2) #80%和20%划分X和y
- clf = SVC(C=0.1,kernel='linear')
- clf.fit(X_train,y_train)
- y_pre = clf.predict(X)
- Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
- Z = Z.reshape(xx.shape)
- sns.scatterplot(data.x1, y=data.x2,hue=y_pre)
- plt.contourf(xx, yy, Z, cmap=plt.cm.ocean, alpha=0.2)
- accuracy_score(data.y,y_pre)
用数据集合的80%作为训练集,建立一个C=0.1的线性SVM模型,并用data的所有x1和x2用这个SVM模型去预测y,预测的y和原来的y计算准确率。
- accuracy_score(data.y,y_pre)
结果0.95333333333333337,即约95.33%的准确率,可以和上面第一个图进行精细对比是哪个点分类错了。
4.4 寻找最好的模型
我们通过网格搜索,寻找一个最好的模型。GridSearchCV可以配置一个参数列表(超参数)、模型,在这个超参数中自动寻找最好的模型。GridSearchCV已经自动按照cv=5把样本分成5等分进行训练和验证的了。
- params = {'C':np.arange(0.1,1,0.1),'kernel':['linear', 'poly', 'rbf', 'sigmoid']}
- gsearch = GridSearchCV(estimator = SVC(kernel='linear'),
- param_grid = params, scoring='accuracy',iid=False, cv=5)
- gsearch.fit(X,data.y)
- gsearch.grid_scores_, gsearch.best_params_, gsearch.best_score_
结果如下:
自动寻找到上面的红色框的模型参数,准确率是96.67%。
从上表可以看出来核函数rbf的拟合比较好。那么我们再用GridSearchCV去变量rbf的degree看看能不能有进一步优化的空间。
- params = {'C':np.arange(0.1,1,0.1),'degree':np.arange(1,5,1)}
- gsearch = GridSearchCV(estimator = SVC(kernel='poly'),
- param_grid = params, scoring='accuracy',iid=False, cv=5)
- gsearch.fit(X,data.y)
- gsearch.grid_scores_, gsearch.best_params_, gsearch.best_score_
最好的结果是:
{‘C’: 0.10000000000000001, ‘degree’: 2},
0.9666666666666668)
没有得到进一步优化。
接下来我们就用rbf核函数c=0.1去重新建立模型并看看可视化的效果。
4.5 最优模型
我们直接用全集去拟合这个c=0.1,核函数rbf的SVM模型。我们看看可视化的结果。
clf = SVC(C=0.2,kernel='rbf')
clf.fit(X,y)
y_pre = clf.predict(X)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
ax = sns.scatterplot(data.x1, y=data.x2,hue=y_pre)
ax.legend(loc="lower right")
plt.contourf(xx, yy, Z, cmap=plt.cm.ocean, alpha=0.2)
- accuracy_score(data.y,y_pre)
准确率为0.96666666666666667,即96.67%
4.6 学习曲线
接下来我们就用这个模型看看样本的学习曲线
- scores = []
- for m in range(2,X_train.size):#循环2-79
- clf.fit(X_train[:m],y_train[:m])
- y_train_predict = clf.predict(X_train[:m])
- y_val_predict = clf.predict(X_val)
- scores.append(accuracy_score(y_train_predict,y_train[:m]))
- plt.plot(range(2,X_train.size),scores,c='green', alpha=0.6)
可以看出来,样本引入50个后,模型的准确率已经稳定下来了。