问题:如何对对下图的线性可分数据集和线性不可分数据集进行分类?
python
思路:编程
下面将带着这两个问题对支持向量机相关问题进行总结数据结构
通常地,当训练数据集线性可分时,存在无穷个分离超平面可将两类数据正确分开,好比感知机求得的分离超平面就有无穷多个,为了求得惟一的最优分离超平面,就须要使用间隔最大化的支持向量机框架
上图中,有A,B,C三个点,表示三个示例,均在分离超平面的正类一侧,点A距分离超平面较远,若预测点为正类,就比较确信预测是正确的;点C距离超平面较近,若预测该点为正类,就不那么确信;点B介于点A与C之间,预测其为正类的确信度也在A与C之间dom
经过上面的描述,当训练集中的全部数据点都距离分隔平面足够远时,确信度就越大。在超平面\(w^T X + b = 0\)肯定的状况下,能够经过函数间隔和几何间隔来肯定数据点离分割超平面的距离机器学习
对于给定的训练数据集T和超平面(w,b),定义超平面(w,b)关于样本\((x_i,y_i)\)的函数间隔为:\[\overline{\gamma{_i}} = y_i(w\bullet{x_i} + b)\]ide
定义超平面(w,b)关于训练数据集T的函数间隔为超平面(w,b)关于T中全部样本点\((x_i,y_i)\)的函数间隔之最小值:\[\overline{\gamma} = \min\limits_{i=1,...,N}\overline{\gamma{_i}}\]函数
函数间隔能够表示分类预测的正确性及确信度,可是选择分离超平面时,只有函数间隔倒是不够的学习
对于给定的训练数据集T和超平面(w,b),定义超平面(w,b)关于样本点\((x_i,y_i)\)的几何间隔为:\[\gamma{_i} = \frac{y_i(w\bullet{x_i} + b)}{||w||}\]测试
定义超平面(w,b)关于训练数据集T的几何间隔为超平面(w,b)关于T中全部样本点\((x_i,y_i)\)的几何间隔之最小值:\[\gamma = \min\limits_{i=1,...,N}\gamma_i\]
从上面函数间隔和几何间隔的定义,能够获得函数间隔和几何间隔之间的关系:\[\gamma_i = \frac{\overline{\gamma_i}}{||w||}\]
\[\gamma = \frac{\overline{\gamma}}{||w||}\]
支持向量机学习的基本想法是找到可以正确划分训练数据集而且几何间隔最大的分离超平面,换句话说也就是不只将正负实例点分开,并且对最难分的实例点(离超平面最近的点)也有足够大的确信度将它们分开,硬间隔是与后面说明的软间隔相对应的
如何求得一个几何间隔最大化的分离超平面,能够表示为下面的约束优化问题:\[\max\limits_{w,b}\quad\gamma\]
\[s_.t.\quad\frac{y_i(w\bullet{x_i}+b)}{||w||}\geq\gamma,\quad{i=1,2,...,N}\]
根据上面函数间隔和几何间隔之间的关系,转换成下面的同等约束问题:\[\max\limits_{w,b}\quad\frac{\overline{\gamma}}{||w||}\]
\[s_.t.\quad\ y_i(w\bullet{x_i}+b)\geq\overline{\gamma},\quad{i=1,2,...,N}\]
因为当w,b按比例变换的的时候函数间隔\(\overline\gamma\)也会呈比例变化,先取\(\overline\gamma= 1\),再因为\(\frac{1}{||w||}\)最大化和最小化\(\frac{1}{2}{||w||}^2\)是等价的,因而获得:\[\min\limits_{w,b}\quad\frac{1}{2}{||w||^2}\]
\[s_.t.\quad\ y_i(w\bullet{x_i}+b)\geq 1,\quad{i=1,2,...,N}\]
由此获得分离超平面:\[w^{*} \bullet x + b^{*} = 0\]
分类决策函数:\[f(x) = sign(w^{*} \bullet x + b^{*})\]
求解拉格朗日对偶函数:\[L(w,b,a) = \frac{1}{2}{||w||}^2 - \sum_{i=1}^na_i[(y_i(x_iw+b)-1)]----(1)\]
对w求偏导:\[\frac{\partial L}{\partial w} = w - \sum_{i=1}^na_iy_ix_i = 0-----(2)\]
对b求偏导:\[\frac{\partial L}{\partial b} = \sum_{i=1}^na_iy_i = 0-------(3)\]
将(2)(3)带入(1)获得:\[maxL(a) = -\frac{1}{2}\sum_{i=1}^n\sum_{j=1}^na_ia_jy_iy_jx_ix_j + \sum_{i=1}^na_i\]
\[s.t. \quad \sum_{i=1}^na_iy_i = 0\]
\[a_i >= 0\]
对于线性可分的数据集能够直接使用硬间隔最大化超平面进行划分,但对于线性不可分的某些样本点不能知足函数间隔大于等于1的约束条件,为了解决这个问题,能够对每一个样本点\((x_i,y_i)\)引进一个松弛变量\(\xi >= 0\),使函数间隔加上松弛变量大于等于1,这样约束条件变为:\[yi(w\bullet x_i + b) >= 1- \xi_{i}\]
同时,对每一个松弛变量\(\xi_{i}\)支付一个代价\(\xi_{i},目标函数由原来的\)\(\frac{1}{2}{||w||}^2\)\(变为\)\(\frac{1}{2}{||w||}^2 + C\sum_{i=1}^n{\xi_i}\)
C为惩罚系数,通常由应用问题决定,C值大时对误分类的惩罚增大,C值小时对误分类惩罚小
线性不可分的线性支持向量机的学习问题编程以下凸二次规划问题:\[\min\limits_{w,b,\xi}\quad\frac{1}{2}{||w||^2}+ C\sum_{i=1}^n{\xi_i}\]
\[s_.t.\quad\ y_i(w\bullet{x_i}+b)\geq 1 - \xi_{i},\quad{i=1,2,...,N}\]
\[\xi_{i} >= 0,\quad i = 1,2,...,N\]
由此获得分离超平面:\[w^{*} \bullet x + b^{*} = 0\]
分类决策函数:\[f(x) = sign(w^{*} \bullet x + b^{*})\]
拉格朗日对偶函数:
\[maxL(a) = -\frac{1}{2}\sum_{i=1}^n\sum_{j=1}^na_ia_jy_iy_jx_ix_j + \sum_{i=1}^na_i\]
\[s.t. \quad \sum_{i=1}^na_iy_i = 0\]
\[a_i >= 0\]
\[\mu_i >= 0\]
\[C-a_i-\mu_i = 0\]
在线性可分的状况下,训练数据集的样本点中与分离超平面距离最近的样本点的示例称为支持向量,支持向量是使约束条件成立的点,即\[\quad\ y_i(w\bullet{x_i}+b) - 1 = 0\]或\[yi(w\bullet x_i + b) - (1- \xi_{i}) = 0\],在\(y_i = +1\)的正例点,支持向量在超平面\[H_1:w^Tx + b = 1\]上,对\(y_i = -1\)的负例点,支持向量在超平面\[H_2:w^T x + b = -1\]上,此时\(H_1\)和\(H_2\)平行,而且没有实例点落在它们中间,在\(H_1\)和\(H_2\)之间造成一条长带,分离超平面与它们平行且位于它们中间,\(H_1和H_2\)之间的距离为间隔,间隔依赖于分割超平面的法向量\(w\),等于\(\frac{2}{|w|}\),\(H_1和H_2\)为间隔边界,以下图:
在决定分离超平面时只有支持向量起做用,而其余实例点并不起做用。若是移动支持向量将改变所求的解;可是若是在间隔边界之外移动其余实例点,甚至去掉这些点,则解是不会变的,因为支持向量在肯定分离超平面中起着决定性的做用,因此将这种分类称为支持向量机。支持向量的个数通常不多,因此支持向量机由不多的‘很重要的’训练样本肯定
(1) 数据集自己就是线性不可分隔的
(2) 数据集中存在噪声,或者人工对数据赋予分类标签出错等状况的缘由致使数据集线性不可分
将线性不可分数据集转换为线性可分数据集经常使用方法:
对于缘由(2)
对于缘由(1)
注意到在线性支持向量机的对偶问题中,不管是目标函数仍是决策函数都只涉及输入实例与实例之间的内积,在对偶问题的目标函数中的内积\(x_ix_j\)能够用核函数\[K(x_i,x_j) = \phi (x_i)\bullet \phi(x_j)\]代替,此时对偶问题的目标函数成为\[maxL(a) = -\frac{1}{2}\sum_{i=1}^n\sum_{j=1}^na_ia_jy_iy_jK(x_i,x_j) + \sum_{i=1}^na_i\]
一样,分类决策函数中的内积也能够用核函数代替\[f(x) = sign(\sum_{i=1}^na_i^*y_iK(x_i,x)+b^*)\]
函数max(0,1-t),当t>=1时,函数等于0,若是t<1,其导数为-1
def hinge(x): if x >=1 : return 0 else: return 1-x
import numpy as np import matplotlib.pyplot as plt x = np.linspace(-2,4,20) y = [hinge(i) for i in x ] ax = plt.subplot(111) plt.ylim([-1,2]) ax.plot(x,y,'r-') plt.text(0.5,1.5,r'f(t) = max(0,1-t)',fontsize=20) plt.show()
<Figure size 640x480 with 1 Axes>
from sklearn import datasets import pandas as pd
iris = datasets.load_iris() print(iris.keys()) print('labels:',iris['target_names']) features,labels = iris['data'],iris['target'] print(features.shape,labels.shape) # 分析数据集 print('-------feature_names:',iris['feature_names']) iris_df = pd.DataFrame(features) print('-------info:',iris_df.info()) print('--------descibe:',iris_df.describe())
dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names', 'filename']) labels: ['setosa' 'versicolor' 'virginica'] (150, 4) (150,) -------feature_names: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'] <class 'pandas.core.frame.DataFrame'> RangeIndex: 150 entries, 0 to 149 Data columns (total 4 columns): 0 150 non-null float64 1 150 non-null float64 2 150 non-null float64 3 150 non-null float64 dtypes: float64(4) memory usage: 4.8 KB -------info: None --------descibe: 0 1 2 3 count 150.000000 150.000000 150.000000 150.000000 mean 5.843333 3.057333 3.758000 1.199333 std 0.828066 0.435866 1.765298 0.762238 min 4.300000 2.000000 1.000000 0.100000 25% 5.100000 2.800000 1.600000 0.300000 50% 5.800000 3.000000 4.350000 1.300000 75% 6.400000 3.300000 5.100000 1.800000 max 7.900000 4.400000 6.900000 2.500000
# 数据进行预处理 from sklearn.preprocessing import StandardScaler,LabelEncoder from sklearn.model_selection import RandomizedSearchCV from sklearn.svm import LinearSVC from scipy.stats import uniform # 对数据进行标准化 scaler = StandardScaler() X = scaler.fit_transform(features) print(X.mean(axis=0)) print(X.std(axis=0)) # 对标签进行编码 encoder = LabelEncoder() Y = encoder.fit_transform(labels) # 调参 svc = LinearSVC(loss='hinge',dual=True) param_distributions = {'C':uniform(0,10)} rscv_clf =RandomizedSearchCV(estimator=svc, param_distributions=param_distributions,cv=3,n_iter=20,verbose=2) rscv_clf.fit(X,Y) print(rscv_clf.best_params_)
[-1.69031455e-15 -1.84297022e-15 -1.69864123e-15 -1.40924309e-15] [1. 1. 1. 1.] Fitting 3 folds for each of 20 candidates, totalling 60 fits [CV] C=8.266733168092582 ............................................. [CV] .............................. C=8.266733168092582, total= 0.0s [CV] C=8.266733168092582 ............................................. [CV] .............................. C=8.266733168092582, total= 0.0s [CV] C=8.266733168092582 ............................................. [CV] .............................. C=8.266733168092582, total= 0.0s [CV] C=8.140498369662586 ............................................. [CV] .............................. C=8.140498369662586, total= 0.0s ... ... ... [CV] .............................. C=9.445168322251103, total= 0.0s [CV] C=9.445168322251103 ............................................. [CV] .............................. C=9.445168322251103, total= 0.0s [CV] C=2.100443613273717 ............................................. [CV] .............................. C=2.100443613273717, total= 0.0s [CV] C=2.100443613273717 ............................................. [CV] .............................. C=2.100443613273717, total= 0.0s [CV] C=2.100443613273717 ............................................. [CV] .............................. C=2.100443613273717, total= 0.0s {'C': 3.2357870215300046}
# 模型评估 y_prab = rscv_clf.predict(X) result = np.equal(y_prab,Y).astype(np.float32) print('accuracy:',np.sum(result)/len(result))
accuracy: 0.9466666666666667
from sklearn.metrics import accuracy_score,precision_score,recall_score print('accracy_score:',accuracy_score(y_prab,Y)) print('precision_score:',precision_score(y_prab,Y,average='micro'))
accracy_score: 0.9466666666666667 precision_score: 0.9466666666666667
SVC类经过参数kernel的设置能够实现线性和非线性分类,具体参数说明和属性说明以下
有这么多核函数,该如何决定使用哪个呢?有一个经验法则是,永远先从线性核函数开始尝试(LinearSVC比SVC(kernel='linear')快的多),特别是训练集很是大或特征很是多的时候,若是训练集不太大,能够试试高斯RBF核,大多数状况下它都很是好用。若是有多余时间和精力,可使用交叉验证核网格搜索来尝试一些其余的核函数,特别是那些专门针对你数据集数据结构的和函数
参考资料: