大数据和机器学习 基础篇 分类 支持向量机SVM

分类算法是机器学习中的一个重点,也是人们常说的“有监督的学习”。这是一种利用一系列已知类别的样本来对模型进行训练调整分类器的参数,使其达到所要求性能的过程,也成为监督训练或有教师学习。

注:本文中用到的Python及其模块安装教程参见


支持向量机SVM

支持向量机SVM是一种比较抽象的算法概念,全称是Support Vector Machine,它可以用来做模式识别,分类或者回归的机器学习。

前面介绍过机器学习是为了解决样本的具体分类映射的问题,构造一个算法,把已知样本的特征和分类情况做一个逻辑映射关系,这样碰到样本时就能用这个算法把它进行分类了。

例如,大于零的实数叫正数,小于零的实数叫负数:

\(
属性=
\left\{
\begin{array}{c}
Positive(x>0)\\
\\
Negative(x<0) \end{array} \right.
\)

但这个过程其实并不是一个机器学习过程,都是人来告诉计算机判定的定义如何,然后计算机根据这个判定的定义来处理每一个待定的对象。这里面计算机确实没有学习的过程。

下面我们把上面的例子改变一下:


年龄和好坏

假设某公司有任务,给客户分类,看看什么样的用户质量比较高;假设客户信息只有年龄这一项,客户信息表如下:

  • 表1 客户信息表

[mdx_table header=”true”]
客户编号
客户年龄
客户质量
客户编号
客户年龄
客户质量
—–
XXXX
34

XXXX
30

—–
XXXX
33

XXXX
25
不好
—–
XXXX
32

XXXX
23
不好
—–
XXXX
31

XXXX
22
不好
—–
XXXX
30

XXXX
18
不好
[/mdx_table]

  • 客户信息的数轴表示:

从上图可以看出,年龄在30以上的客户质量都好,在25一下的都不好。那么就可以考虑在30和25中间切一刀,一边是好一边是不好。也就是从27.5分开。

  • 以27.5为分界:

例如,来了一个27岁的客户,那么他应该属于客户质量好的客户。但是如果没有办法“一刀切”怎么办?例如客户信息如下表:

  • 表2 客户信息表

[mdx_table header=”true”]
客户编号
客户年龄
客户质量
客户编号
客户年龄
客户质量
—–
XXXX
34

XXXX
30

—–
XXXX
33

XXXX
25
不好
—–
XXXX
32

XXXX
23

—–
XXXX
31
不好
XXXX
22
不好
—–
XXXX
30

XXXX
18
不好
[/mdx_table]

  • 客户信息的数轴表示:

这个比较麻烦,因为没法做到“一刀切”。那么现在有以下两种选择:

  • 把这两类全部标出来。
\(
属性=
\left\{
\begin{array}{c}
Good(x≥30,x≠31)\\
\\
Good(x=23)\\
\\
NotGood(x≤25,x≠23)\\
\\
NotGood(x=31)
\end{array}
\right.
\)

这是一个分段函数,虽然准确但是啰嗦。在实际情况中一般可能会有10000个甚至更多的客户,所以这个函数写起来会相当麻烦。所以这种标记方法很容易产生过拟的问题。

  • 一刀切。反正只要一刀切就会非常简洁,如果一刀切下去虽然两边的类都不纯或者一边的类不纯,但是只要不纯的程度在能容忍的范围内就可以。
\(
属性=
\left\{
\begin{array}{c}
Good(x≥27.5)\\
\\
NotGood(x<27.5)\\ \end{array} \right.
\)

这次还是从27.5切,大于等于27.5就算“好”,小于27.5就算“不好”。那么在这个分类中“好”类的不纯度为\(\frac{1}{6}\);“不好”类的不纯度为\(\frac{1}{4}\)。如果说在不做这种数据分析的情况下,发展10个客户,有6个是“好”客户,4个是“不好”的客户;现在改进后虽然有一定的误判率,约为16.7%——由于分类不纯的问题,但是直接过滤掉了一定的对象,发展10个客户,有8.3个是“好”客户,1.7个是“不好”的客户。从数值上看,方案策略的提升还是有改进的。

总结一下,有以下几个关键点:

  • 关键点1:切下去的点在SVM算法体系里叫“超平面”。这个“超平面”是一个抽象的面概念,在一维空间里就是一个点,用\(x+A=0\)的点来表示;二维空间里就是一条线,用\(Ax+By+C=0\)的直线来表示;三维空间里就是一个面,用\(Ax+By+Cz+D=0\)的平面来表示;四维空间了就用\(Ax+By+Cz+Dα+E=0\)来表示;以此类推……上述4个方程都可以变形为:
    \( x=-A\)
    \( y=-\frac{A}{B}x-\frac{C}{B}\)
    \( z=-\frac{A}{C}x-\frac{B}{C}y-\frac{D}{C}\)
    \( α=-\frac{A}{D}x-\frac{B}{D}y-\frac{C}{D}z-\frac{E}{D}\)
  • 关键点2:过拟问题。一般来说,设计分类器都是要尽量避免过拟的。过拟会给归纳过程带来很大的麻烦,而且在应用的过程中也非常不方便,只要精确度达到标准就足够了。
  • 关键点3:不纯度问题。不纯度和精确度是一对矛盾,精确度越高那么不纯度就越低,反之,不纯度越高精确度就越低。分类器的研究和调整的过程就是一个精度和成本平衡的过程,所以并不是不纯度越低越好,而是在实际生产中操作成本一样的情况下,不纯度越低越好。

定义距离

在一个平面直角坐标系中,有一些样本点作为训练点,一些被标记为类别\(X\),一些被标记为非类别\(X\)。如何想把两种类别的点区分开,最朴素的想法是,如果能找到一条直线\(Ax+By+C=0\)能够恰好把它们区分成两个部分就最好了。

如何求解恰当的\(A,B,C\),恰当的标准是让类别\(X\)中与该直线最近的样本点的距离和非类别\(X\)中的样本点与该直线的距离最大。

在平面直角坐标系中,如果有一条直线\(Ax+By+C=0\),那么点\((x_0,y_0)\)到该直线的距离如下:

\( d=\frac{|Ax_0+By_0+C|}{\sqrt{A^2+B^2}}\)

与数轴上类似:“\(x-27.5>0\)的都是分类为‘好’的样本,\(x-27.5<0\)的则都不是分类为‘好’的样本”。如果以\(Ax+By+C=0\)这样一个方程做分隔,可以发现,所有\(X\)类别中的样本点都满足\(Ax+By+C>0\),而所有非\(X\)类别中的样本点都满足\(Ax+By+C<0\),这就是最开始构造这条直线的目的。 推广到N维空间,这个超平面的公式可以简写为: \( g(v)=wv+b\) 这里w是系数,v是样本向量,b是常数。 而N维空间上的距离为: \( d=\frac{|g(v_0)|}{||w||}\)


升维

如果样本是线性不可分的,那么就需要升维来解决这个问题——这才是SVM算法最为吸引人的部分。

先来看一个一维数据的例子,来说明升维的概念。

假设在数轴上给出一些数据,其中[-2,2]区间内的被标记为分类1,其余的都是分类0,我们可以把分段函数写成如下的形式:

\(
f(x)=
\left\{
\begin{array}{c}
1(-x^2+4>0)\\
\\
0(-x^2+4≤0)
\end{array}
\right.
\)

或者可以认为:

\(
f(y)=
\left\{
\begin{array}{c}
1(y>0)\\
\\
0(y≤0)
\end{array}
\right.\)

\(\left\{
\begin{array}{c}
y=-x^2+4\\
\\
z=f(y)
\end{array}
\right.
\)

这实际上就是\(y=-x^2+4\)这个函数在\(y=0(x轴)\)这条直线上的投影把样本点分开。

  • \(y=-x^2+4\)的图形:

在二维空间中也有类似的方式。

例如,样本向量v距离原点(0,0)的距离为1以内分类被标记为0,其余都为1。同样是线性不可分的,但是可以构造一个这样的函数:

\(
f(x,y)=
\left\{
\begin{array}{c}
1(x^2+y^2≥1)\\
\\
0(x^2+y^2<1) \end{array} \right.
\)

或者可以这么认为:

\(
f(z)=
\left\{
\begin{array}{c}
1(z≥1)\\
\\
0(z<1) \end{array} \right.
\)

\(
\left\{
\begin{array}{c}
z=x^2+y^2\\
\\
α=f(z)
\end{array}
\right.
\)

可以看到,在一维空间上解决线性不可分问题是把函数映射到二维空间,使得一维空间上的分类边界是二维空间上的分类函数在以为空间上的投影;而在二维空间上解决线性不可分问题是把函数映射到三维空间,使得二维空间上的分类边界是三维空间上的分类函数在二维空间上的投影。那么所有的n维空间上的线性不可分问题都可以考虑映射到n+1维上去构造分类函数,使得它在n维空间上的投影能够将两个类别分开。

这个构造的过程在SVM里是使用核函数(Kernel)来进行的。核函数的目的很单纯,即只要在当前维度的样本是线性不可分的,就一律映射到更高的维度上去,在更高的维度上找到超平面,得到超平面方程。函数本身表示的只是一个变量代换关系。


示例

下面还是用客户信息的列表给出示例。

  • 表3 客户信息表

[mdx_table header=”true”]
客户编号
客户年龄
客户质量
客户编号
客户年龄
客户质量
—–
XXXX
34

XXXX
30

—–
XXXX
33
不好
XXXX
25
不好
—–
XXXX
32

XXXX
23

—–
XXXX
31
不好
XXXX
22
不好
—–
XXXX
30

XXXX
18
不好
[/mdx_table]

在这个例子中,客户年龄和客户质量之间明显是没办法做线性分隔了。这是可以用SVM来做分类。
在Python的Scikit-learn库中,用到的是一个叫做SVC的类,SVC是Support Vector Classification的缩写,即支持分类向量机。SVC支持的核函数包括linear(线性核函数),poly(多项式核函数),rbf(径向核函数),sigmoid(神经元激活核函数),precomputed(自定义核函数),默认使用rbf(径向核函数)。

示例代码如下:

#支持向量机SVM
from sklearn import svm

#年龄
X=[[34],[33],[32],[31],[30],[30],[25],[23],[22],[18]]
#质量
y=[1,0,1,0,1,1,0,1,0,1]

#把训练数据和对应的分类放入分类器中进行训练
#这里使用rbf(linear,poly,rbf,sigmoid,precomputed)
clf=svm.SVC(kernel='rbf').fit(X,y)

#预测年龄29的客户的质量
p=[[29]]
print(clf.predict(p))

预测年龄为29的客户的质量,输出为1,表示客户质量为“好”。

在这个例子中,使用的是rbf核函数,这也是最适合做非线性关系分类标准的首选核函数。如果这几种核函数实在不知道该用哪个,那就在实际场景中多做对比测试,看看哪一种的正确率最高即可。


#小结

SVM解决问题的方法有以下几步:

  1. 把所有的样本和其对应的分类标记交给算法进行训练。
  2. 如果发现线性可分,那就直接找出超平面。
  3. 如果发现线性不可分,那就映射到n+1维空间,找出超平面。
  4. 最后得到超平面的表达式,也就是分类函数。

想了解更多关于大数据和机器学习:

发表评论

CAPTCHAis initialing...