机器学习:支持向量机(Support Vector Machine, SVM)

一:什么是支持向量机:

1:背景;

SVM是由模式识别中广义肖像算法(generalized portrait algorithm)发展而来的分类器   ,其早期工作来自前苏联学者Vladimir N. Vapnik和Alexander Y. Lerner在1963年发表的研究  。1964年,Vapnik和Alexey Y. Chervonenkis对广义肖像算法进行了进一步讨论并建立了硬边距的线性SVM   。此后在二十世纪70-80年代,随着模式识别中最大边距决策边界的理论研究  、基于松弛变量(slack variable)的规划问题求解技术的出现 ,和VC维(Vapnik-Chervonenkis dimension, VC dimension)的提出  ,SVM被逐步理论化并成为统计学习理论的一部分 。1992年,Bernhard E. Boser、Isabelle M. Guyon和Vapnik通过核方法得到了非线性SVM 。1995年,Corinna Cortes和Vapnik提出了软边距的非线性SVM并将其应用于手写字符识别问题,这份研究在发表后得到了关注和引用,为SVM在各领域的应用提供了参考。

2:简介

支持向量机是一类按监督学习(supervised learning)方式对数据进行二元分类的广义线性分类。(generalized linear classifier),其决策边界是对学习样本求解的最大边距超平面(maximum-margin hyperplane),广泛应用于机器学习(Machine Learning), 计算机视觉(Computer Vision) 和数据挖掘(Data Mining)当中。

二:理论:

参考

三:实现

from numpy import *
import matplotlib.pyplot as plt
import operator
import time

def loadDataSet(fileName):
	dataMat = []
	labelMat = []
	with open(fileName) as fr:
		for line in fr.readlines():
			lineArr = line.strip().split('\t')
			dataMat.append([float(lineArr[0]), float(lineArr[1])])
			labelMat.append(float(lineArr[2]))
	return dataMat, labelMat

def selectJrand(i, m):
	j = i
	while (j == i):
		j = int(random.uniform(0, m))
	return j

def clipAlpha(aj, H, L):
	if aj > H:
		aj = H
	if L > aj:
		aj = L
	return aj

class optStruct:
	def __init__(self, dataMatIn, classLabels, C, toler):
		self.X = dataMatIn
		self.labelMat = classLabels
		self.C = C
		self.tol = toler
		self.m = shape(dataMatIn)[0]
		self.alphas = mat(zeros((self.m, 1)))
		self.b = 0
		self.eCache = mat(zeros((self.m, 2)))

def calcEk(oS, k):
	fXk = float(multiply(oS.alphas, oS.labelMat).T * (oS.X * oS.X[k, :].T)) + oS.b
	Ek = fXk - float(oS.labelMat[k])
	return Ek

def selectJ(i, oS, Ei):
	maxK = -1
	maxDeltaE = 0
	Ej = 0
	oS.eCache[i] = [1, Ei]
	validEcacheList = nonzero(oS.eCache[:, 0].A)[0]
	if (len(validEcacheList)) > 1:
		for k in validEcacheList:
			if k == i:
				continue
			Ek = calcEk(oS, k)
			deltaE = abs(Ei - Ek)
			if (deltaE > maxDeltaE):
				maxK = k
				maxDeltaE = deltaE
				Ej = Ek
		return maxK, Ej
	else:
		j = selectJrand(i, oS.m)
		Ej = calcEk(oS, j)
	return j, Ej

def updateEk(oS, k):
	Ek = calcEk(oS, k)
	oS.eCache[k] = [1, Ek]

def innerL(i, oS):
	Ei = calcEk(oS, i)
	if ((oS.labelMat[i] * Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or ((oS.labelMat[i] * Ei > oS.tol) and (oS.alphas[i] > 0)):
		j, Ej = selectJ(i, oS, Ei)
		alphaIold = oS.alphas[i].copy()
		alphaJold = oS.alphas[j].copy()
		if (oS.labelMat[i] != oS.labelMat[j]):
			L = max(0, oS.alphas[j] - oS.alphas[i])
			H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i])
		else:
			L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C)
			H = min(oS.C, oS.alphas[j] + oS.alphas[i])
		if (L == H):
			# print("L == H")
			return 0
		eta = 2.0 * oS.X[i, :] * oS.X[j, :].T - oS.X[i, :] * oS.X[i, :].T - oS.X[j, :] * oS.X[j, :].T
		if eta >= 0:
			# print("eta >= 0")
			return 0
		oS.alphas[j] -= oS.labelMat[j] * (Ei - Ej) / eta
		oS.alphas[j] = clipAlpha(oS.alphas[j], H, L)
		updateEk(oS, j)
		if (abs(oS.alphas[j] - alphaJold) < 0.00001):
			# print("j not moving enough")
			return 0
		oS.alphas[i] += oS.labelMat[j] * oS.labelMat[i] * (alphaJold - oS.alphas[j])
		updateEk(oS, i)
		b1 = oS.b - Ei - oS.labelMat[i] * (oS.alphas[i] - alphaIold) * oS.X[i, :] * oS.X[i, :].T - oS.labelMat[j] * (oS.alphas[j] - alphaJold) * oS.X[i, :] * oS.X[j, :].T
		b2 = oS.b - Ei - oS.labelMat[i] * (oS.alphas[i] - alphaIold) * oS.X[i, :] * oS.X[j, :].T - oS.labelMat[j] * (oS.alphas[j] - alphaJold) * oS.X[j, :] * oS.X[j, :].T
		if (0 < oS.alphas[i]) and (oS.C > oS.alphas[i]):
			oS.b = b1
		elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]):
			oS.b = b2
		else:
			oS.b = (b1 + b2) / 2.0
		return 1
	else:
		return 0

def smoP(dataMatIn, classLabels, C, toler, maxIter, kTup=('lin', 0)):
	"""
	输入:数据集, 类别标签, 常数C, 容错率, 最大循环次数
	输出:目标b, 参数alphas
	"""
	oS = optStruct(mat(dataMatIn), mat(classLabels).transpose(), C, toler)
	iterr = 0
	entireSet = True
	alphaPairsChanged = 0
	while (iterr < maxIter) and ((alphaPairsChanged > 0) or (entireSet)):
		alphaPairsChanged = 0
		if entireSet:
			for i in range(oS.m):
				alphaPairsChanged += innerL(i, oS)
			# print("fullSet, iter: %d i:%d, pairs changed %d" % (iterr, i, alphaPairsChanged))
			iterr += 1
		else:
			nonBoundIs = nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0]
			for i in nonBoundIs:
				alphaPairsChanged += innerL(i, oS)
				# print("non-bound, iter: %d i:%d, pairs changed %d" % (iterr, i, alphaPairsChanged))
			iterr += 1
		if entireSet:
			entireSet = False
		elif (alphaPairsChanged == 0):
			entireSet = True
		# print("iteration number: %d" % iterr)
	return oS.b, oS.alphas

def calcWs(alphas, dataArr, classLabels):
	"""
	输入:alphas, 数据集, 类别标签
	输出:目标w
	"""
	X = mat(dataArr)
	labelMat = mat(classLabels).transpose()
	m, n = shape(X)
	w = zeros((n, 1))
	for i in range(m):
		w += multiply(alphas[i] * labelMat[i], X[i, :].T)
	return w

def plotFeature(dataMat, labelMat, weights, b):
	dataArr = array(dataMat)
	n = shape(dataArr)[0]
	xcord1 = []; ycord1 = []
	xcord2 = []; ycord2 = []
	for i in range(n):
		if int(labelMat[i]) == 1:
			xcord1.append(dataArr[i, 0])
			ycord1.append(dataArr[i, 1])
		else:
			xcord2.append(dataArr[i, 0])
			ycord2.append(dataArr[i, 1])
	fig = plt.figure()
	ax = fig.add_subplot(111)
	ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
	ax.scatter(xcord2, ycord2, s=30, c='green')
	x = arange(2, 7.0, 0.1)
	y = (-b[0, 0] * x) - 10 / linalg.norm(weights)
	ax.plot(x, y)
	plt.xlabel('X1'); plt.ylabel('X2')
	plt.show()

def main():
	trainDataSet, trainLabel = loadDataSet('testSet.txt')
	b, alphas = smoP(trainDataSet, trainLabel, 0.6, 0.0001, 40)
	ws = calcWs(alphas, trainDataSet, trainLabel)
	print("ws = \n", ws)
	print("b = \n", b)
	plotFeature(trainDataSet, trainLabel, ws, b)

if __name__ == '__main__':
	start = time.clock()
	main()
	end = time.clock()
	print('finish all in %s' % str(end - start))

结果:

 四:

1:优点:

(1)高维度:SVM 可以高效的处理高维度特征空间的分类问题。这在实际应用中意义深远。比如,在文章分类问题中,单词或是词组组成了特征空间,特征空间的维度高达 10 的 6 次方以上。

(2)节省内存:尽管训练样本点可能有很多,但 SVM 做决策时,仅仅依赖有限个样本(即支持向量),因此计算机内存仅仅需要储存这些支持向量。这大大降低了内存占用率。

(3)应用广泛:实际应用中的分类问题往往需要非线性的决策边界。通过灵活运用核函数,SVM 可以容易的生成不同的非线性决策边界,这保证它在不同问题上都可以有出色的表现(当然,对于不同的问题,如何选择最适合的核函数是一个需要使用者解决的问题)。

2:缺点:

(1)SVM算法对大规模训练样本难以实施
(2)用SVM解决多分类问题存在困难
(3)对缺失数据敏感,对参数和核函数的选择敏感(源自)

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值