svm python实现_svm+python实现(更新)

一.svm概述

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

1.线性可分问题:

1220897-20170911212424297-1506575115.png

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

1220897-20170911212615547-1623492040.png

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

1220897-20170911212821188-2087374087.png

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

1220897-20170911212952172-1915540610.png

3.非线性问题:

1220897-20170903000519796-1612743957.png

二,求解参数

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

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

1.寻找违背KKT条件的

1220897-20170903000802749-931324211.png,即:

1220897-20170903001558452-1897996289.png

其中:

1220897-20170903002221187-208556040.png

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

3.求解约束前的

1220897-20170903001843874-2063257696.png,公式为:

1220897-20170903001918718-57165853.png其中,

1220897-20170903001945593-1567755176.png,Ei=f(xi)-yi

4.对

1220897-20170903001843874-2063257696.png进行约束:

1220897-20170903002342030-1854577046.png

1220897-20170903002353140-689510479.png

5.通过

1220897-20170903001843874-2063257696.png求解

1220897-20170903000802749-931324211.png

1220897-20170903002434499-1188130379.png

6.对b的更新

1220897-20170903002523858-1990063080.png

1220897-20170903002534733-1598605891.png

1220897-20170903002624077-1044613601.png

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()

效果如图所示:

1220897-20170911212052985-594901190.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值