SVM:二类分类器,对多类问题应用SVM应该做一些修改
分隔超平面(separating hyperplane): 分类的决策边界
间隔(margin): 点到分隔面的距离。我们希望间隔尽可能大
支持向量(support vector): 离分隔超平面最近的那些点。
目标:最大化支持向量到分隔面的距离
分隔超平面:wTx+b
点到分隔面法线的长度:|wTx+b|/||w||
为什么标签用-1和+1?不是0和1?
扫描二维码关注公众号,回复:
2294283 查看本文章
因为可以用一个统一的公式来表示间隔:label*(wTx+b)
无论数据点处于正负方向,如果点离分隔平面很远的位置时,距离总是一个很大的正数。
目标:寻找w,b
找到最小间隔的数据点,对该间隔最大化:
argmaxw,b {minn(label*(wTx+b))*1/||w||}
这里推导根据andrew ng的课程来看:
应用简化版SMO算法处理小规模数据集:
import numpy as np
def load_dataset(filename):
dataset = []
labels = []
fr = open(filename)
for line in fr.readlines():
split_line = line.strip().split('\t')
dataset.append([float(split_line[0]), float(split_line[1])])
labels.append(float(split_line[2]))
return dataset, labels
def select_j_rand(i, m):
'''
随机选择另一个alphaj,与i构成alpha对
'''
j = i
while j == i:
j = int(np.random.uniform(0, m))
return j
def clip_alpha(aj, H, L):
'''
约束alpha范围在0-C
'''
if aj > H:
aj = H
if aj < L:
aj = L
return aj
def smo_simple(dataset, labels, C, toler, max_iter):
'''
简化的smo算法(svm实现)
:param dataset: 数据集
:param labels: 标签集
:param C: 松弛变量
:param toler: 容错率
:param max_iter: 最大循环次数
:return:
'''
data_matrix = np.mat(dataset)
labels_matrix = np.mat(labels).transpose()
b = 0
m, n = np.shape(data_matrix)
alphas = np.mat(np.zeros((m, 1)))
it = 0
while it < max_iter:
alpha_pari_changed = 0
for i in range(m):
# 预测值 h(x) = w'x+b = ∑ αi*yi*<xi,x>+b
fxi = float(np.multiply(alphas, labels_matrix).T * (data_matrix*data_matrix[i, :].T)) + b
# 误差
ei = fxi - float(labels_matrix[i])
# 如果alpha可以更改进入优化过程
if ((labels_matrix[i]*ei < -toler) and (alphas[i] < C)) or \
((labels_matrix[i]*ei > toler) and (alphas[i] > 0)):
j = select_j_rand(i, m)
fxj = float(np.multiply(alphas, labels_matrix).T * (data_matrix*data_matrix[j, :].T)) + b
ej = fxj - float(labels_matrix[j])
alpha_i_old = alphas[i].copy()
alpha_j_old = alphas[j].copy()
# 保证alpha在0与C之间
if labels_matrix[i] != labels_matrix[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
# alpha[j]的最优修改量
eta = 2.0 * data_matrix[i, :]*data_matrix[j, :].T - \
data_matrix[i, :]*data_matrix[i, :].T - \
data_matrix[j, :]*data_matrix[j, :].T
if eta >= 0:
print('eta>=0')
continue
# 修改alphai与alphaj,注意改变值相同,符号不同
alphas[j] -= labels_matrix[j] * (ei - ej)/eta
alphas[j] = clip_alpha(alphas[j], H, L)
if abs(alphas[j] - alpha_j_old) < 0.00001:
print('j not moving enough')
continue
alphas[i] += labels_matrix[j] * labels_matrix[i] * (alpha_j_old - alphas[j])
# 设置常数项
b1 = b - ei - labels_matrix[i]*(alphas[i] - alpha_i_old) * \
data_matrix[i, :]*data_matrix[i, :].T - \
labels_matrix[j]*(alphas[j] - alpha_j_old) * \
data_matrix[i, :]*data_matrix[j, :].T
b2 = b - ej - labels_matrix[i]*(alphas[i] - alpha_i_old) * \
data_matrix[i, :]*data_matrix[j, :].T - \
labels_matrix[j] * (alphas[j] - alpha_j_old) * \
data_matrix[j, :]* data_matrix[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
alpha_pari_changed += 1
print('iter:', it, end='')
print(' i:', i, end='')
print(' pari changed: ', alpha_pari_changed)
if alpha_pari_changed == 0:
it += 1
else:
it = 0
print('iteration number:', it)
return b, alphas
dataset, labels = load_dataset('SMO/testSet.txt')
# print(dataset)
# print(labels)
b, alphas = smo_simple(dataset, labels, 0.6, 0.001, 40)
print(b)
print(alphas)