SVM三層理解鏈接1
原文鏈接2
代碼鏈接3
一週時間的SVM簡單版本的代碼讓人讀的心力交瘁,讓我這個編程小白太難受!!!
1、MySVM
# -*- coding:utf-8 -*-
import random
import numpy as np
import matplotlib.pyplot as plt
#輔助函數一: 創建一個樣本點返回來的隨機整數(0,m),即選擇alpha(i,j)
def seclectJrand(i,m):
j = i
while (j == i):
j = int(random.uniform(0,m)) #返回一個浮點數 N,取值範圍爲0,m
return j
# 輔助函數二:將aj規劃到[0,C]範圍
def ClipAlpha(aj,H,L):
if aj > H:
aj = H
if aj < L:
aj = L
return aj
# 最簡版本SMO算法
def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
dataMatrix = np.mat(dataMatIn)
labelMat = np.mat(classLabels).transpose()
b = 0
m,n = np.shape(dataMatrix)
alphas = np.mat(np.zeros((m,1)))
iter_num = 0
while(iter_num < maxIter):
alphaPairsChanged = 0
for i in range(m):
#注意一
fXi = float(np.multiply(alphas,labelMat).T * (dataMatrix * dataMatrix[i,:].T)) + b # 前面得到alpha*yi*xi的總和,再乘以x
Ei = fXi - float(labelMat[i])
# 啓發式選擇,即尋找那些誤差過大(正間隔和否間隔)且在(0,C)範圍內的alpha進行優化
if ((labelMat[i]*Ei < -toler) and (alphas[i] < C )or\
((labelMat[i])*Ei > toler) and (alphas[i] > 0)):#不滿足KKT
j = seclectJrand(i,m)
fXj = float(np.multiply(alphas,labelMat).T * (dataMatrix * dataMatrix[j,:].T)) + b
Ej = fXj - float(labelMat[j])
alphaIold = alphas[i].copy()
alphaJold = alphas[j].copy()
if (labelMat[i] != labelMat[j]):
L = max(0, alphas[j] - alphas[i])
H = min(C, C + alphas[j] - alphas[i])
else:
L = max(0, alphas[j] + alphas[i] - C)
H = min(C, alphas[j] + alphas[i])
if L==H:
print("L==H")
continue
#注意二
eta = dataMatrix[i,:] * dataMatrix[i,:].T + dataMatrix[j,:] * dataMatrix[j,:].T\
- 2.0 * dataMatrix[i,:]*dataMatrix[j,:].T
if eta <= 0:
print("eta<=0")
continue
alphas[j] += labelMat[j] * (Ei -Ej)/eta
alphas[j] = ClipAlpha(alphas[j],H,L)
if (abs(alphas[j] -alphaJold) < 0.0001):
print("alpha_j變化小,不需要更新")
continue
#注意三
alphas[i] += labelMat[j] * labelMat[i] * (alphaJold - alphas[j])
#注意四
b1 = b -Ei -labelMat[i] * (alphas[i]-alphaIold) * dataMatrix[i,:] * dataMatrix[i,:].T\
- labelMat[j] * (alphas[j]-alphaJold) * dataMatrix[i,:] * dataMatrix[j,:].T
b2 = b -Ej -labelMat[i] * (alphas[i]-alphaIold) * dataMatrix[i,:] * dataMatrix[j,:].T\
- labelMat[j] * (alphas[j]-alphaJold) * dataMatrix[j,:] * dataMatrix[j,:].T
if (0 < alphas[i]) and (C > alphas[i]): b = b1
elif(0 < alphas[j]) and (C > alphas[j]): b = b2
else: b = (b1 + b2)/2.0
alphaPairsChanged += 1
print("第%d次迭代 樣本: %d, alpha優化次數: %d"%(iter_num, i, alphaPairsChanged))
if(alphaPairsChanged == 0):
iter_num += 1 #沒必要優化
else:
iter_num = 0 #繼續優化
#注意五:返回的b是實數,alphas是一個[m,1]矩陣
print("迭代次數: %d" % iter_num)
return b, alphas
# 計算w
def calcWs(dataMat, labelMat, alphas):
alphas, dataMat, labelMat = np.array(alphas), np.array(dataMat), np.array(labelMat)
# np.tile:np.tile(a,(1,2))第一個參數爲Y軸擴大倍數,第二個爲X軸擴大倍數,即原矩陣列數*2
w = np.dot((np.tile(labelMat.reshape(1, -1).T, (1, 2)) * dataMat).T, alphas) #得到2*1
return w.tolist() # 數組——>列表
def showClassifer(dataMat, labelMat, alphas,w ,b):
data_plus = []
data_minus = []
#注意六 把原始點畫出來,橙色的點對應的標籤是-1,藍色的點對應的標籤是1
for i in range(len(dataMat)):
if labelMat[i] > 0:
data_plus.append(dataMat[i])
else:
data_minus.append(dataMat[i])
data_plus_np = np.array(data_plus)
data_minus_np = np.array(data_minus)
plt.scatter(np.transpose(data_plus_np)[0],np.transpose(data_plus_np)[1],s = 30, alpha=0.7)
plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1], s=30, alpha=0.7)
#注意七:畫出訓練出來的超平面
x1 = max(dataMat)[0]
x2 = min(dataMat)[0]
a1, a2 = w
b = float(b)
a1 = float(a1[0])
a2 = float(a2[0])
y1, y2 = (-b - a1 * x1) / a2,(-b - a1 * x2) / a2 # 縱座標max min
plt.plot([x1,x2],[y1,y2])
# 注意八 畫出向量機點,和那些“忽略”的點
# 帶有紅色圓圈的是支持向量機點即間隔線上的點,帶有黑色的點是間隔線內的點
for i, alpha in enumerate(alphas): #將一個可遍歷的數據對象組合爲一個索引序列,同時列出數據和數據下標
if 0.6 > abs(alpha) > 0:
x, y = dataMat[i]
plt.scatter([x],[y],s=150,c='none',alpha=0.7,linewidths=1.5,edgecolors='red')
if 0.6 == abs(alpha):
x, y = dataMat[i]
plt.scatter([x],[y],s=150,c='none',alpha=0.7,linewidths=1.5,edgecolors='black')
plt.show()
2、MyTest
# -*- coding: utf-8 -*-#
import MySVM as svm
x=[[1,8],[3,20],[1,15],[3,35],[5,35],[4,40],[7,80],[6,49],[1.5,25],[3.5,45],[4.5,50],[6.5,15],[5.5,20],[5.8,74],[2.5,5]]
y=[1,1,-1,-1,1,-1,-1,1,-1,-1,-1,1,1,-1,1]
b,alphas = svm.smoSimple(x,y,0.6,0.001,40)
w = svm.calcWs(x,y,alphas)
print(b,'\n',alphas,'\t',w)
svm.showClassifer(x,y,alphas, w, b)
3、結果