svm+python实现(更新)

一.svm概述

svm是一种二分类模型,学习策略是通过间隔最大化来实现分类的目的,最终转化为了凸二次规划求解,对于svm,处理的问题有三种情况,即:

1.线性可分问题:

为了高效简化计算参数w,b,将问题转化为:

2.线性不可分问题:(不可分是由于特异点outlier的存在引起的,故引入松弛变量)

C称为惩罚参数,C增大对误分类的惩罚就增大,转换为对偶问题有:

3.非线性问题:

二,求解参数

的确我们可以单纯的通过求解凸二次规划问题来获得答案,但是当训练样本量很大时,这些算法就会变的低效,从上面的公式就可以直观看出,有多少样例就有多少乘子,如何高效求解拉格朗日乘子成为了关键——smo。

浏览了很多博文总结一下具体的求解过程(smo):

1.寻找违背KKT条件的,即:

其中:

2.寻找第二个乘子,通过:max|E1-E2|

3.求解约束前的,公式为:

其中,,Ei=f(xi)-yi

 4.对进行约束:

5.通过求解

6.对b的更新

7.启发式迭代具体方法:看了很多博文,感觉讲的太抽象,自己尝试很久发现并没那么复杂,先遍历一遍全部样例,标注好违反kkt条件的样例,第二个alpha在这些违反kkt样例中找即可。

二.python实现

# -*- coding:utf-8 -*-
#svm.py

import numpy as np
import matplotlib.pyplot as plt
import random
def getdata(num):  # 生成间隔大些的数据,需要输入数据量
    xdata = []
    for i in range(num):
        idata = [random.randint(0, 20), random.randint(0, 20)]
        if sum(idata) >= 20:
            idata = [i + 5 for i in idata]
        if not idata in xdata:
            xdata.append(idata)
    ydata = [1 if sum(i) >= 20 else -1 for i in xdata]
    return xdata, ydata
class Svc(object):
    def __int__(self,c=1000000,w=[0,0],b=0,xdata,ydata,alpha):#初始化函数
        self.c=c
        self.w=w
        self.b=b
        self.xdata=xdata
        self.ydata=ydata
        self.alpha=alpha
    def kernels(self,x1,x2):#核函数,这里是线性可分因此就是普通的内积运算
        a=x1[0]*x2[0]+x1[1]*x2[1]
        return a
    def kernelmat(self):#核矩阵
        a=np.eye(len(self.xdata),len(self.xdata))
        for i in range(len(self.xdata)):
            for j in range(len(self.xdata)):
                a[i][j]=self.kernels(self.xdata[i],self.xdata[j])
        return a
    def ui(self,i):  # 求ui
        a = 0
        for j in range(len(self.xdata)):
            a = a + self.alpha[j] * self.ydata[j] * (self.xdata[j][0] * self.xdata[i][0] + self.xdata[j][1] * self.xdata[i][1])
        a = a + self.b
        return a
    def Ei(self,i):  # 求Ei=ui-yi
        a = self.ui(i) - self.ydata[i]
        return a
    def alpha2(self,i, tflist):  # 找第二个alpha2在alpha向量中的位置,通过max|Ei-Ej|
        ei = self.Ei(i)
        a = 0
        d = 0
        for j in range(len(self.xdata)):
            if tflist[j] == True:
                ej = self.Ei(j)
                bi = abs(ei - ej)
                if bi > a:
                    a = bi
                    d = j
        return d
    def eta(self, i, j):  # 求分母eta
        a = self.xdata[i][0] ** 2 + self.xdata[i][1] ** 2 + self.xdata[j][0] ** 2 + self.xdata[j][1] ** 2 - 2 * (
            self.xdata[i][0] * self.xdata[j][0] + self.xdata[i][1] * self.xdata[j][1])
        return a
    def alpha2new(self,i, j):  # 求alpha2new,这里直接做约束
        a = self.alpha[j] + self.ydata[j] * (self.Ei(i) - self.Ei(j)) / self.eta(i, j)
        if self.ydata[i] == self.ydata[j]:
            L = np.max([0, self.alpha[i] + self.alpha[j] - self.c])
            H = np.min([self.c, self.alpha[i] + self.alpha[j]])
            if a > H:
                return H
            elif a < L:
                return L
            else:
                return a
        else:
            L = np.max([0, self.alpha[j] - self.alpha[i]])
            H = np.min([self.c, self.c + self.alpha[j] - self.alpha[i]])
            if a > H:
                return H
            elif a < L:
                return L
            else:
                return a
    def alpha1new(self,i, j):  # 把alpha2new带进去求alpha1new
        a = self.alpha[i] + self.ydata[i] * self.ydata[j] * (self.alpha[j] - self.alpha2new(i,j))
        return a
    def bnew(self,i,j):  # 更新b
        ei = self.Ei(i)
        ej = self.Ei(j)
        yi = self.ydata[i]
        yj = self.ydata[j]
        alphai = self.alpha1new(i,j)
        alphaj = self.alpha2new(i,j)
        b1 = self.b - ei - yi * (alphai - self.alpha[i]) * (self.xdata[i][0] ** 2 + self.xdata[i][1] ** 2) - yj * (alphaj - self.alpha[j]) * (self.xdata[j][0] * self.xdata[i][0] + self.xdata[j][1] * self.xdata[i][1])
        b2 = self.b - ej - yi * (alphai - self.alpha[i]) * (self.xdata[i][0] * self.xdata[j][0] + self.xdata[i][1] * self.xdata[j][1]) - yj * (alphaj - self.alpha[j]) * (self.xdata[j][0] ** 2 + self.xdata[j][1] ** 2)
        if alphai > 0 and alphai < self.c:
            return b1
        elif alphaj > 0 and alphaj < self.c:
            return b2
        else:
            return (b1 + b2) / 2
    def sign(self,x):  # 符号函数
        if x > 0:
            return 1
        elif x < 0:
            return -1
        else:
            return 0
    def acc(self):  # 计算正确率,判断函数
        a = 0
        for i in range(len(self.xdata)):
            a = a + (self.sign(self.w[0] * self.xdata[i][0] + self.w[1] * self.xdata[i][1] + self.b) == self.ydata[i])
        return a / len(self.xdata)
    def wb(self):  # 训练函数输出w,b
        alphav = self.alpha.copy()
        while self.acc() < 0.99:
            tflist = []
            for i in range(len(self.alpha)):
                tflist.append((self.ydata[i] * self.ui(i) == 1 and self.alpha[i] == 0) or (self.ydata[i] * self.ui(i) > 1 and self.alpha[i] != 0) or (self.ydata[i] * self.ui(i) < 1))
            for i in range(len(self.alpha)):
                if tflist[i] == True:
                    j = self.alpha2(i,tflist)
                    t = self.alpha2new(i,j)
                    alphav[j] = t
                    alphav[i] = self.alpha1new(i,j)
                    self.b = self.bnew(i,j)
                    self.alpha = alphav
            self.w = [0, 0]
            for i in range(len(self.alpha)):
                self.w = self.w + self.alpha[i] * self.ydata[i] * np.array(self.xdata[i])
            self.w = list(self.w)
        return self.w,self.b
    def pic(self):#画图
        x=[1,25]
        xdata1 = [i[0] for i in self.xdata]
        xdata2 = [i[1] for i in self.xdata]
        plt.scatter(xdata1, xdata2, c=["r" if i == 1 else "b" for i in self.ydata], s=5)
        y = [((-1) * self.b - self.w[0] * x[0]) / self.w[1], ((-1) * self.b - self.w[0] * x[1]) / self.w[1]]  # 计算y
        plt.plot(x, y)
        plt.show()
    def test(self,point):#测试函数
        a=self.sign(self.w[0]*point[0]+self.w[1]*point[1]+self.b)
        return a
def main():
    s=Svc()
    s.xdata,s.ydata=getdata(100)
    s.alpha=np.ones(len(s.xdata))#初始化alpha
    s.w,s.b=s.wb()
    s.pic()
  for i in range(10):
    print(s.test(s.xdata[i])==s.ydata[i])
if __name__=="__main__": main()

  

  

 

效果如图所示:

 

posted @ 2017-09-03 00:32  澹宁  阅读(931)  评论(1)    收藏  举报