参考python机器学习实战和统计学习编写SVM(软间隔)
SVM分类器的实现:二分类方式 软间隔线性分类器:通过调整C的大小,来决定对数据差错的容忍度,C越高代表容忍差错的能力越低 使用二次规划的算法 SMO 求解: 更新方式:外层循环找到不符合KTT条件的变量,内层循环找到在第一个变量确定条件下,第二个变量改变步长最大 的变量进行更新,同时更新偏置量b 最重要的两层循环。
#SVM的实现,主要是二次规划
#首先读取数据
from numpy import *
def loadData(fileName):
retData=[]
retLabel=[]
fr=open(fileName)
for line in fr.readlines():
curLine=line.strip().split('\t')
retData.append([float(curLine[0]),float(curLine[1])])
retLabel.append(float(curLine[2]))
return mat(retData),mat(retLabel).T
#因为实际上是针对一个变量的优化 另一个变量随之变化,两者之间满足线性关系,
#所以所求值有一个
#产生新的下标值
#计算g(x)
class op:
def __init__(self,dataSet,label,C,totel):
self.X=dataSet
self.label=label
self.C=C
self.tol=totel
self.numRow=shape(dataSet)[0]
self.alpha=mat(zeros([self.numRow,1]))
self.b=0
self.eCache=mat(zeros([self.numRow,2]))
def calcEk(oS,k):
Ek=float(multiply(oS.alpha,oS.label).T*(oS.X*oS.X[k,:].T))-float(oS.label[k])+oS.b
return Ek
def selectJ(i,oS,Ei):
maxIndex=-1
matDelta=0
Ej=0
oS.eCache[i]=[1,Ei]
lenValid=nonzero(oS.eCache[:,0].A)[0]
if (len(lenValid))>1:
for j in lenValid:
if(i==j): continue
tempE=calcEk(oS,j)
miu=abs(Ei-tempE)
if miu>matDelta:
matDelta=miu
Ej=tempE
maxIndex=j
return maxIndex,Ej
else:
j=selectJrand(i,oS)
Ej=calcEk(oS,j)
return j,Ej
def selectJrand(i,oS):
j=i
while(j==i):
j=int(random.uniform(0,oS.numRow))
return j
def updateE(i,oS):
Ek=calcEk(oS,i)
oS.eCache[i]=[1,Ek]
def clipAlpha(alpha,L,H):
if alpha<L:
alpha=L
if alpha>H:
alpha=H
return alpha
def innerL(i,os):
Ei=calcEk(os,i)
if (os.label[i]*Ei<-os.tol and os.alpha[i]<os.C) or(os.label[i]*Ei>os.tol and os.alpha[i]>0):
j,Ej=selectJ(i,os,Ei)
alphaIold=os.alpha[i].copy()
alphaJold=os.alpha[j].copy()
if os.label[i]!=os.label[j]:
L=max(0,alphaJold-alphaIold)
H=min(os.C,os.C+alphaJold-alphaIold)
else:
L=max(0,alphaJold+alphaIold-os.C)
H=min(os.C,alphaJold+alphaIold)
if L==H: return 0
eta=2.0*(os.X[j,:]*os.X[j,:].T)-os.X[i,:]*os.X[i,:].T-os.X[i,:]*os.X[j,:].T
if eta>=0:return 0
os.alpha[j]-=os.label[j]*(Ei-Ej)/eta
os.alpha[j]=clipAlpha(os.alpha[j],L,H)
updateE(j,os)
if abs(alphaJold-os.alpha[j])<0.001:
return 0
os.alpha[i]+=os.label[i]*os.label[j]*(alphaJold-os.alpha[j])
updateE(i,os)
#更新b
b1=os.b-Ei-os.label[i]*(os.alpha[i]-alphaIold)*os.X[i,:]*os.X[i,:].T-os.label[j]*(os.alpha[j]-alphaJold)*os.X[j,:]*os.X[i,:].T
b2=os.b-Ej-os.label[i]*(os.alpha[i]-alphaIold)*os.X[j,:]*os.X[i,:].T-os.label[j]*(os.alpha[j]-alphaJold)*os.X[j,:]*os.X[j,:].T
if os.alpha[i]>0 and os.alpha[i]<os.C:
os.b=b1
elif os.alpha[j]>0 and os.alpha[j]<os.C:
os.b=b2
else:
os.b=(b1+b2)/2.0
return 1
else:
return 0
def smoP(fileName,C,totel,maxItr):
data,label=loadData(fileName)
os=op(data,label,C,totel)
itr=0
entier=True
p=0
while itr<maxItr and(p>0 or entier):
p=0
if entier:
for i in range(os.numRow):
p+=innerL(i,os)
else:
nonBoundIs=nonzero((os.alpha.A>0)*(os.alpha.A<C))[0]
for i in nonBoundIs:
p+=innerL(i,os)
itr+=1
print(itr)
if entier:entier=False
elif p==0:entier=True
return os.alpha,os.b
alpha,b=smoP('testSet.txt',100000,0.001,40)
SVM软间隔分类,主要在于调整C 的大小 one class SVM 主要是调整nu的大小 ,nu代表差错数据的比例,通过调整nu来控制超球面的大小,以及异常点的比例
#展示SVM结果
def calcWs(alphas,data,label):
m,n=shape(data)
w=zeros([n,1])
for i in range(m):
w+=multiply(alphas[i]*label[i],data[i,:].T)
return w
data,label=loadData('testSet.txt')
w=calcWs(alpha,data,label)
newLabel=[]
m=shape(data)[0]
numLabel=[]
for i in range(m):
r=data[i]*mat(w)+b
numLabel.append(r)
if abs(r-1)<0.01or abs(r+1)<0.01:
newLabel.append(0)
elif r>0 :
newLabel.append(1)
elif r<0:
newLabel.append(-1)
x=arange(0.0,10,0.5)
y=(-(w[0][0]*x+b))/w[1][0]
y=array(y)[0]
import matplotlib.pyplot as plt
col=['ro','g+']
Slabel=[-1,1]
plt.subplot(121)
for i in range(2):
index=[j for j in range(m) if newLabel[j]==Slabel[i]]
plt.plot(data[index,0],data[index,1],col[i])
index=index=[j for j in range(m) if newLabel[j]==0]
plt.plot(data[index,0],data[index,1],'b*')
plt.plot(x,y,'b-')
plt.show()
plt.subplot(122)
for i in range(2):
index=[j for j in range(m) if label[j]==Slabel[i]]
plt.plot(data[index,0],data[index,1],col[i])
plt.plot(x,y,'b-')
plt.show()