*这是灰灰的第一篇博文,主要是为大家了解SVM做一个抛砖引玉的工作,在写作的过程中,借鉴和学习了很多大神的工作,自己再加以学习和整理,形成了下面的这篇文章。
在这里先鸣谢 v_JULY_v 博主,他的《支持向量机通俗导论(理解SVM的三层境界)》给了我很大的帮助,可谓是站在巨人的肩膀上。*
话不多说,本次博客的目的是为了让大家初步了解什么是支持向量机。目录如下:
1 什么是支持向量机
2 初识SVM-线性SVM算法的数学建模
3 SVM应用
4 总结
从以下四个方面来认识:
什么是机器学习中的分类?
一般我们会以为凡是分类就是把一些东西或样例按照类别给区分开来,实际上,分类方法是一个机器学习的方法,分类也称为模式识别,或者在概率统计中称为判别分析问题。
正儿八经的解释:分类作为数据挖掘领域中一项非常重要的任务,目前在商业上应用最多(比如分析型CRM里面的客户分类模型,客户流失模型,客户盈利等等,其本质上都属于分类问题)。而分类的目的则是学会一个分类函数或分类模型(或者叫做分类器),该模型能把数据库中的数据项映射到给定类别中的某一个,从而可以用于预测未知类别。
你甚至可以想当然的认为,分类就是恰如一个商场进了一批新的货物,你现在要根据这些货物的特征分门别类的摆放在相关的架子上,这一过程便可以理解为分类,只是它由训练有素的计算机程序来完成。
举个例子:
以上就是分类的内容,这部分引用自 v_JULY_v 博主,他的《支持向量机通俗导论(理解SVM的三层境界)》,再次再次感谢。
接下来,是:什么是支持向量? 关于这个问题,在讲述之前需要简单科普三个储备知识:
对于维度来说,零维是一个点;两个点连成一条线,就是一维;两条线交叉形成一个面,是二维;三维从二维的空间延伸出去一条线,使得物体不光有了长度宽度,还有高度,是一个立体的物体。三维及以上的维度描述,可以看这个链接:
从第一维度旅行到第十一维度
有了这三个储备知识之后,就很好理解后面的支持向量机这五个字了!请看
支持向量就这么说完了,我们来了解下什么是机
至此,支持向量机就说完了,那么,支持向量机是做什么的呢?
看到这里,我们的第一个内容:什么是支持向量机就讲完了。接下来是带领大家初步认识SVM,这里将会运用数学进行建模,前方大量公式高能预警!!!
在这里有个值得注意的小细节,题目里我特地说明是线性,为什么呢?
这是因为,SVM不光包括线性的,也有非线性的,但是在这篇博文里我主要是带领大家初步认识SVM,因此不会涉及到太难的部分。而线性的部分比较好理解,因此我用线性建模来给大家讲解和实现。
本章节有引用这位大神的内容,在此向原作者表示谢意和敬意。零基础学SVM
接下来看看我们如果要建模的话,需要哪些内容呢?
一个最优化问题通常有两个最基本的因素:
1)目标函数,也就是你希望什么东西的什么指标达到最好;
2)优化对象,你期望通过改变哪些因素来使你的目标函数达到最优。
在线性SVM算法中,目标函数显然就是那个“分类间隔”,而优化对象则是决策面。所以要对SVM问题进行数学建模,首先要对上述两个对象(“分类间隔”和“决策面”)进行数学描述。按照一般的思维习惯,我们先描述决策面。
(请注意,以下的描述对于线性代数及格的同学可能显得比较啰嗦,但请你们照顾一下用高数课治疗失眠的同学们。)
请你暂时不要纠结于n维空间中的n-1维超平面这种超出正常人想象力的情景。我们就老老实实地看看二维空间中的一根直线,我们从初中就开始学习的直线方程形式很简单。
公式(2.3)的向量形式可以写成
看到变量 ω,x 略显粗壮的身体了吗?他们是黑体,表示变量是个向量, ω=[ω1,ω2]T , x=[x1,x2]T 。一般我们提到向量的时候,都默认他们是个列向量,所以我在方括号[ ]后面加上了上标T,表示转置(我知道我真的很啰嗦,但是关于“零基础”三个字,我是认真的。),它可以帮忙把行向量竖过来变成列向量,所以在公式(2.5)里面 ω 后面的转置符号T,会把列向量又转回到行向量。这样一个行向量 ωT 和一个列向量 x 就可快快乐乐的按照矩阵乘法的方式结合,变成一个标量,然后好跟后面的标量 γ 相加后相互抵消变成0。
就着公式(2.5),我们再稍稍尝试深入一点。那就是探寻一下向量 ω=[ω1,ω2]T 和标量 γ 的几何意义是什么。让我们回到公式(2.4),对比公式(2.5),可以发现此时的 ω=[a,−1]T 。然后再去看公式(2.2),还记得那条我们熟悉的直线方程中的a的几何意义吗?对的,那是直线的斜率。如果我们构造一个向量 ϕ=[1,a]T ,它应该跟我们的公式(2.2)描述的直线平行。然后我们求一下两个向量的点积 ωTϕ ,你会惊喜地发现结果是0。我们管这种现象叫作“两个向量相互正交”。通俗点说就是两个向量相互垂直。当然,你也可以在草稿纸上自己画出这两个向量,比如让 a=3√ ,你会发现 ϕ=[1,a]T 在第一象限,与横轴夹角为60°,而 ω=[a,−1]T 在第四象限与横轴夹角为30°,所以很显然他们两者的夹角为90°。
你现在是不是已经忘了我们讨论正交或者垂直的目的是什么了?那么请把你的思维从坐标系上抽出来,回到决策面方程上来。我是想告诉你向量 ω=[ω1,ω2]T 跟直线 ωTx+γ=0 是相互垂直的,也就是说 ω=[ω1,ω2]T 控制了直线的方向。另外,还记得小时候我们学过的那个叫做截距的名词吗?对了, γ 就是截距,它控制了直线的位置。
然后,在本小节的末尾,我冒昧地提示一下,在n维空间中n-1维的超平面的方程形式也是公式(2.5)的样子,只不过向量 ω,x 的维度从原来的2维变成了n维。如果你还是想不出来超平面的样子,也很正常。那么就请你始终记住平面上它们的样子也足够了。
到这里,我们花了很多篇幅描述一个很简单的超平面方程(其实只是个直线方程),这里真正有价值的是这个控制方向的参数 ω 。接下来,你会有很长一段时间要思考它到底是个什么东西,对于SVM产生了怎样的影响。
决策面到此也就描述完了,接下来描述分类间隔
我们在开始得文章里介绍过分类间隔的定义及其直观的几何意义。间隔的大小实际上就是支持向量对应的样本点到决策面的距离的二倍,如图所示。
所以分类间隔计算似乎相当简单,无非就是点到直线的距离公式。如果你想要回忆高中老师在黑板上推导的过程,可以随便在百度文库里搜索关键词“点到直线距离推导公式”,你会得到至少6、7种推导方法。但这里,请原谅我给出一个简单的公式如下:
这里 ||ω|| 是向量 ω 的模,表示在空间中向量的长度, x=[x1,x2]T 就是支持向量样本点的坐标。 ω , γ 就是决策面方程的参数。而追求W的最大化也就是寻找d的最大化。看起来我们已经找到了目标函数的数学形式。
但问题当然不会这么简单,我们还需要面对一连串令人头疼的麻烦。
接着上面的结尾,我们讨论一下究竟还有哪些麻烦没有解决:
1)并不是所有的方向都存在能够实现100%正确分类的决策面,我们如何判断一条直线是否能够将所有的样本点都正确分类?
2)即便找到了正确的决策面方向,还要注意决策面的位置应该在间隔区域的中轴线上,所以用来确定决策面位置的截距 γ 也不能自由的优化,而是受到决策面方向和样本点分布的约束。
3)即便取到了合适的方向和截距,公式(2.6)里面的 x 不是随随便便的一个样本点,而是支持向量对应的样本点。对于一个给定的决策面,我们该如何找到对应的支持向量?
以上三条麻烦的本质是“约束条件”,也就是说我们要优化的变量的取值范围受到了限制和约束。事实上约束条件一直是最优化问题里最让人头疼的东西。但既然我们已经论证了这些约束条件确实存在,就不得不用数学语言对他们进行描述。尽管上面看起来是3条约束,但SVM算法通过一些巧妙的小技巧,将这三条约束条件融合在了一个不等式里面。
我们首先考虑一个决策面是否能够将所有的样本都正确分类的约束。上图中的样本点分成两类(红色和蓝色),我们为每个样本点 xi 加上一个类别标签 yi :
如果我们的决策面方程能够完全正确地对图2中的样本点进行分类,就会满足下面的公式
如果我们要求再高一点,假设决策面正好处于间隔区域的中轴线上,并且相应的支持向量对应的样本点到决策面的距离为d,那么公式(2.8)就可以进一步写成:
符号 ∀ 是“对于所有满足条件的” 的缩写。我们对公式(2.9)中的两个不等式的左右两边除上d,就可得到:
其中
把 ωd 和 γd 就当成一条直线的方向矢量和截距。你会发现事情没有发生任何变化,因为直线 ωTdx+γd=0 和直线 ωTx+γ=0 其实是一条直线。现在,现在让我忘记原来的直线方程参数 ω 和 γ ,我们可以把参数 ωd 和 γd 重新起个名字,就叫它们 ω 和 γ 。我们可以直接说:“对于存在分类间隔的两类样本点,我们一定可以找到一些决策面,使其对于所有的样本点均满足下面的条件:”
公式(2.11)可以认为是SVM优化问题的约束条件的基本描述。
至此,支持向量机的数学建模初步完成,大家可以歇口气!
接下来是支持向量机的应用,关于应用,可以看看这篇神文章!再次向作者表达我的敬意!
权力的游戏死亡预测-SVM应用
这里插入我们的代码
import numpy as np
import matplotlib.pyplot
from sklearn import svm
1
2
3
np.random.seed(8) # 保证随机的唯一性
1
# 线性可分:
array = np.random.randn(20,2)
X = np.r_[array-[3,3],array+[3,3]]
y = [0]*20+[1]*20
print X[0]
print X[20]
print y
1
2
3
4
5
6
7
[-2.90879528 -1.90871727]
[ 3.09120472 4.09128273]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
1
2
3
4
# 建立svm模型
clf = svm.SVC(kernel='linear')
clf.fit(X,y)
1
2
3
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='linear',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
1
2
3
4
5
x1_min, x1_max = X[:,0].min(), X[:,0].max(),
x2_min, x2_max = X[:,1].min(), X[:,1].max(),
xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max), np.linspace(x2_min, x2_max))
# 得到向量w : w_0x_1+w_1x_2+b=0
w = clf.coef_[0]
f = w[0]*xx1 + w[1]*xx2 + clf.intercept_[0]+1 # 加1后才可绘制 -1 的等高线 [-1,0,1] + 1 = [0,1,2]
plt.contour(xx1, xx2, f, [0,1,2], colors = 'r') # 绘制分隔超平面、H1、H2
plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.Paired)
plt.scatter(clf.support_vectors_[:,0],clf.support_vectors_[:,1],color='k') # 绘制支持向量点
plt.show()
1
2
3
4
5
6
7
8
9
10
# 非线性可分:
from sklearn import datasets
1
2
3
# 加载数据
iris = datasets.load_iris()
X = iris.data
y = iris.target
print iris.target_names
1
2
3
4
5
['setosa' 'versicolor' 'virginica']
1
2
from sklearn.model_selection import train_test_split
1
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/3.) # 分割训练集和测试集
1
from sklearn.preprocessing import StandardScaler # 标准化
scaler = StandardScaler()
X_train_std = scaler.fit_transform(X_train)
X_test_std = scaler.transform(X_test)
1
2
3
4
5
from sklearn.grid_search import GridSearchCV
1
# 交叉验证,调整参数
param_grid = {'C':[1e1,1e2,1e3, 5e3,1e4,5e4],
'gamma':[0.0001,0.0008,0.0005,0.008,0.005,]}
clf = GridSearchCV(svm.SVC(kernel='rbf',class_weight='balanced'),param_grid,cv=10)
clf = clf.fit(X_train_std,y_train)
print clf.best_estimator_
1
2
3
4
5
6
7
SVC(C=10.0, cache_size=200, class_weight='balanced', coef0=0.0,
decision_function_shape=None, degree=3, gamma=0.005, kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
1
2
3
4
5
clf.score(X_test_std,y_test)
1
1.0
1
2
y_pred = clf.predict(X_test_std)
1
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
1
2
print(classification_report(y_test,y_pred,target_names=iris.target_names))
print(confusion_matrix(y_test,y_pred,labels=range(iris.target_names.shape[0])))
1
2
precision recall f1-score support
setosa 1.00 1.00 1.00 18
versicolor 1.00 1.00 1.00 17
virginica 1.00 1.00 1.00 15
avg / total 1.00 1.00 1.00 50
# recall表示召回率 = #(True positive) / (#(True positive)+ #(False negative)),表示样本中的正例有多少被预测正确。
# precision表示精确率 = #(True positive) / (#(True positive)+ #(False negative)),表示预测为正的样本中有多少是真正的正样本。
# f1-score(F1指标)表示召回率和精确率两个指标的调和平均数,召回率和精确率越接近,F1指标越高。F1 = 2 / (1/recall + 1/precision)。召回率和精确率差距过大的学习模型,往往没有足够的实用价值。
[[18 0 0]
[ 0 17 0]
[ 0 0 15]]
纵坐标表示预测的是谁,横坐标表示标准的是谁。对角线的值越大,预测能力越好。
到这一步,大家也就初步的认识了支持向量机啦,再次对给予我帮助的大神们致以崇高的敬意!同时也欢迎大家有什么意见或者看法可以指出来!互相学习进步!最后把文章的总结放在这里。