首页 > 其他分享 >机器学习之支持向量机

机器学习之支持向量机

时间:2024-06-11 15:43:28浏览次数:10  
标签:alphas 机器 学习 labelMat dataMat np alpha data 向量

什么是SVM
SVM(全称Support Vector Machine)中文名支持向量机。SVM是一种监督机器学习算法,是一种二分类模型,它的目的是寻找一个超平面来对样本进行分割,分割的原则是间隔最大化,最终转化为一个凸二次规划问题来求解。可用于分类或回归挑战。然而,它主要用于分类问题。
最大间隔与分类
如果一个线性函数能够将样本分开,称这些数据样本是线性可分的。那么什么是线性函数呢?其实很简单,在二维空间中就是一条直线,在三维空间中就是一个平面,以此类推,如果不考虑空间维数,这样的线性函数统称为超平面。我们看一个简单的二维空间的例子,+代表正类,-代表负类,样本是线性可分的,但是很显然不只有这一条直线可以将样本分开,而是有无数条,我们所说的线性可分支持向量机就对应着能将数据正确划分并且间隔最大的直线。
在样本空间中寻找一个超平面, 将不同类别的样本分开。


最大化间隔: 寻找参数w和b , 使得下述公式最大:

最大间隔问题的拉格朗日乘法
第一步:引入拉格朗日乘子ai≥ 0得到拉格朗日函数

第二步:令L(w,b,a)对w和b的偏导为零

第三步:w, b回代到第一步

对偶问题
1.等式约束

2.不等式约束的KKT条件

3.KKT

SMO高效优化算法
SMO算法的目标是求出一系列alpha和b,一旦求出这些alpha,就很容易算出权重向量w并得到分割超平面。
SMO算法工作原理:每次循环中选择两个alpha进行优化处理。一旦找到一对合适的alpha,那么就增大其中一个,减小另外一个。

算法流程:每次选取两个a进行更新

编程求解线性SVM
通过简约版线性SMO算法进行支持向量机分类:
部分数据集展示:

运行代码
`# -- coding:UTF-8 --
import matplotlib.pyplot as plt
import numpy as np
import random
def loadDataSet(fileName):
dataMat = []; labelMat = []
fr = open(fileName)
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 #选择一个不等于i的j
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

def showDataSet(dataMat, labelMat):
data_plus = [] #正样本
data_minus = [] #负样本
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) #转换为numpy矩阵
data_minus_np = np.array(data_minus) #转换为numpy矩阵
plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1]) #正样本散点图
plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1]) #负样本散点图
plt.show()

def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
#转换为numpy的mat存储
dataMatrix = np.mat(dataMatIn); labelMat = np.mat(classLabels).transpose()
#初始化b参数,统计dataMatrix的维度
b = 0; m,n = np.shape(dataMatrix)
#初始化alpha参数,设为0
alphas = np.mat(np.zeros((m,1)))
#初始化迭代次数
iter_num = 0
#最多迭代matIter次
while (iter_num < maxIter):
alphaPairsChanged = 0
for i in range(m):
#步骤1:计算误差Ei
fXi = float(np.multiply(alphas,labelMat).T(dataMatrixdataMatrix[i,:].T)) + b
Ei = fXi - float(labelMat[i])
#优化alpha,设定一定的容错率。
if ((labelMat[i]Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]Ei > toler) and (alphas[i] > 0)):
#随机选择另一个与alpha_i成对优化的alpha_j
j = selectJrand(i,m)
#步骤1:计算误差Ej
fXj = float(np.multiply(alphas,labelMat).T(dataMatrixdataMatrix[j,:].T)) + b
Ej = fXj - float(labelMat[j])
#保存更新前的aplpha值,使用深拷贝
alphaIold = alphas[i].copy(); alphaJold = alphas[j].copy();
#步骤2:计算上下界L和H
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 LH: print("LH"); continue
#步骤3:计算eta
eta = 2.0 * dataMatrix[i,:]dataMatrix[j,:].T - dataMatrix[i,:]dataMatrix[i,:].T - dataMatrix[j,:]dataMatrix[j,:].T
if eta >= 0: print("eta>=0"); continue
#步骤4:更新alpha_j
alphas[j] -= labelMat[j]
(Ei - Ej)/eta
#步骤5:修剪alpha_j
alphas[j] = clipAlpha(alphas[j],H,L)
if (abs(alphas[j] - alphaJold) < 0.00001): print("alpha_j变化太小"); continue
#步骤6:更新alpha_i
alphas[i] += labelMat[j]labelMat[i](alphaJold - alphas[j])
#步骤7:更新b_1和b_2
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
#步骤8:根据b_1和b_2更新b
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
print("迭代次数: %d" % iter_num)
return b,alphas

def showClassifer(dataMat, w, b):
#绘制样本点
data_plus = [] #正样本
data_minus = [] #负样本
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) #转换为numpy矩阵
data_minus_np = np.array(data_minus) #转换为numpy矩阵
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- a1x1)/a2, (-b - a1x2)/a2
plt.plot([x1, x2], [y1, y2])
#找出支持向量点
for i, alpha in enumerate(alphas):
if abs(alpha) > 0:
x, y = dataMat[i]
plt.scatter([x], [y], s=150, c='none', alpha=0.7, linewidth=1.5, edgecolor='red')
plt.show()

def get_w(dataMat, labelMat, alphas):
alphas, dataMat, labelMat = np.array(alphas), np.array(dataMat), np.array(labelMat)
w = np.dot((np.tile(labelMat.reshape(1, -1).T, (1, 2)) * dataMat).T, alphas)
return w.tolist()

if name == 'main':
dataMat, labelMat = loadDataSet('testSet.txt')
b,alphas = smoSimple(dataMat, labelMat, 0.6, 0.001, 40)
w = get_w(dataMat, labelMat, alphas)
showClassifer(dataMat, w, b)
`

运行结果:
可以看到红色圈圈圈起来点是支持向量点。

通过SMO-SVM实现对鸢尾花数据集的二分类

`
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
鸢尾花(iris)数据集
数据集内包含 3 类共 150 条记录,每类各 50 个数据,
每条记录都有 4 项特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度,
可以通过这4个特征预测鸢尾花卉属于(iris-setosa, iris-versicolour, iris-virginica)中的哪一品种。
这里只取前100条记录,两项特征,两个类别。
def create_data():
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['label'] = iris.target
df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
data = np.array(df.iloc[:100, [0, 1, -1]])
for i in range(len(data)):
if data[i,-1] == 0:
data[i,-1] = -1
return data[:,:2], data[:,-1]
使用RBF(Radial basis function)核函数处理
def K(x,z,sigma=1.5):
return np.exp(np.dot((x-z),(x-z).T)/-(2sigma**2))
对应课本147页的g(x_i),该函数助于验证KKT条件
def g(i,x,y,alpha,b):
sum=b
for j in range(len(y)):
sum+=alpha[j]
y[j]K(x[i],x[j])
return sum
验证第i个样本点是否满足KKT条件
def isKKT(alpha,i,x,y,b,C):
if alpha[i]==0 and y[i]
g(i,x,y,alpha,b)>=1:
return True
elif alpha[i]C and y[i]g(i,x,y,alpha,b)<=1:
return True
elif alpha[i]>0 and alpha[i]<C and y[i]
g(i,x,y,alpha,b)
1:
return True
else:
return False
验证第i个样本点违反KKT条件的程度。由于KKT条件和y_ig(x_i)与1的不等式有关
因此计算y_i
g(x_i)与1之间差值的绝对值作为衡量违反程度的标准
def vioKKT(alpha,i,x,y,b):
return abs(y[i]g(i,x,y,alpha,b)-1)
在数组x中找到值为a的元素第一次出现的位置
def findindex(x,a):
for i in range(len(x)):
if x[i]==a:
return i
某个样本点分类误差函数
def E(w,b,x_k,y_k):
predi_k=int(np.sign(np.dot(w,x_k.T)+b))
return predi_k-y_k
计算样本点与分割直线的距离
def distance_count(x,w,b):
return abs(w[0]
x[0]+w[1]*x[1]+b) / np.sqrt(w[0]2 + w[1]2)


from functions import *
from numpy import *
from random import *
from matplotlib import pyplot as plt
def train(C=1.0):
#获得数据集
x,y=create_data()
#设定迭代次数为100次
iter=100
#样本容量也就是标签的个数
N=len(y)
#alpha的初始值取全0
alpha=zeros(len(y))
#设置i,j的初始值(对应alpha1和alpha2)
i,j=randint(0,N-1),randint(0,N-1)
#保证i≠j
while ij:
i=randint(0,N-1)
for k in range(iter):
#x的尺寸为一个1×2行向量
x_i,x_j=x[i],x[j]
#y的取值为+1或-1
y_i,y_j=y[i],y[j]
#计算ita,为计算a2_newunc做准备
ita=K(x_i,x_i)+K(x_j,x_j)-2*K(x_i,x_j)
if ita
0:
continue
#计算分割平面参数w与b
#x:100×2矩阵,w:1×2矩阵
#由于y-dot(w,x.T)是个与y等长的行向量,取其各元素平均值
w=dot(alphay,x)
b=mean(y-dot(w,x.T))
#计算误差E1和E2
E_i=E(w,b,x_i,y_i)
E_j=E(w,b,x_j,y_j)
#计算a2_ewunc
a1_old=alpha[i]
a2_old=alpha[j]
a2_newunc=a2_old+y_j
(E_i-E_j)/ita
#计算L与H
L,H=0.0,0.0
if y_i!=y_j:
L=max(0,a2_old-a1_old)
H=min(C,C+a2_old-a1_old)
elif y_iy_j:
L=max(0,a2_old+a1_old-C)
H=min(C,a2_old+a1_old)
#计算剪辑后a2_new与a1_new的值
a2_new=max(L,min(H,a2_newunc))
a1_new=a1_old+y_iy_j(a2_old-a2_new)
#更新alpha
alpha[i],alpha[j]=a1_new,a2_new
#violation表示每个元素违反KKT条件的程度
violation=zeros(N)
#对每一个样本点检验KKT条件,在violation内记录每个样本点违反KKT的程度
for k in range(N):
if isKKT(alpha,k,x,y,b,C)
False:
violation[k]=float(vioKKT(alpha,k,x,y,b))
#如果没有违反KKT条件,则违反程度是0
else:
violation[k]=0.0
#找到violation中违反程度最大的点,设定为i,对应alpha_1
i=findindex(violation,max(violation))
#这里设置j(对应alpha_2)为不等于i的随机数。
#原本alpha_2的选取应该是令abs(E_i-E_k)最大的k值对应的alpha点
#经过测试,在大多数情况下,abs(E_i-E_k)(1×100向量)的所有元素都是0
#即预测每个元素都准确,每个元素的分类误差都是0,误差的差值也是0
#只有少数情况下,会有一个误差差值不等于0
#对于前一种情况,无所谓“最大的误差差值”(因为都是0),因此只能设置j为随机数
#对于后一种情况,由于出现的次数少,并且那一个不为0的差值的元素出现的位置具有随机性
#因此总是将j设定为随机数
j=randint(0,N-1)
while ji:
j = randint(0, N - 1)
#计算最终(迭代100次)分割平面参数
w = dot(alpha * y, x)
b = mean(y - dot(w, x.T))
draw_x, draw_y, draw_label = [], [], []
#在散点图上标记样本点的位置,样本点第一个元素作为x坐标,第二个元素作为y坐标
for p in x:
draw_x.append(p[0])
draw_y.append(p[1])
#画散点图,其中支持向量呈现绿色,正类呈现红色,负类呈现蓝色
#样本点离分割直线最近的为支持向量
distance=zeros(len(y))
for i in range(len(y)):
distance[i]=distance_count(x[i],w,b)
vector=findindex(distance,min(distance))
for i in range(len(y)):
if i
vector:
draw_label.append('g')
else:
if y[i] > 0:
draw_label.append('r')
else:
draw_label.append('b')
plt.scatter(draw_x, draw_y, color=draw_label)
plain_x = range(4, 8, 1)
plain_y = []
for i in plain_x:
temp = double(-(w[0] * i + b) / w[1])
plain_y.append(temp)
plt.plot(plain_x, plain_y)
#最终绘图
plt.savefig('SMO.jpg')
plt.show()
if name == 'main':
train()

`
总结
SVM优点
1、解决小样本下机器学习问题。
2、解决非线性问题。
3、无局部极小值问题。(相对于神经网络等算法)
4、可以很好的处理高维数据集。
5、泛化能力比较强。
SVM缺点
1、对于核函数的高维映射解释力不强,尤其是径向基函数。
2、对缺失数据敏感。
3、调参麻烦,核函数难选难调

标签:alphas,机器,学习,labelMat,dataMat,np,alpha,data,向量
From: https://www.cnblogs.com/ls111/p/18242143

相关文章

  • Lucene的IK分词器学习,增加支持单个特殊符号搜索
    前言感谢CSDN这篇文章,原始代码基于这里。正常对于“[email protected]”这段文字,搜索'@'这个符号是搜不出来的。本文主要修改是扩展IK分词器,增加了对诸如"@-"这种特殊文字的检索。当然这个其实并没有多少实际意义,所以基本也是出于学习的目的。正文IK分词器分析这里不深入原理,......
  • r语言数据分析案例25-基于向量自回归模型的标准普尔 500 指数长期预测与机制分析
    一、背景介绍2007年的全球经济危机深刻改变了世界经济格局,引发了一系列连锁反应,波及各大洲。经济增长停滞不前,甚至在某些情况下出现负增长,给出口导向型发展中国家带来了不确定性。实体经济受到的冲击尤为严重,生产成本上升,利润下降,实际经济价值缩水。相比之下,金融部门的投资活......
  • 机器学习实践——支持向量机
    一.什么是支持向量机支持向量机(SVM)是一种广泛使用的监督学习方法,主要用于分类和回归分析。它的基本原理是找到一个超平面(在二维空间中是一条直线),以最大化不同类别之间的边界。以下是SVM的关键概念:超平面:决策边界,用于分类的直线或平面。 边界(Margin):从超平面到最近的数据点的最......
  • 我所理解的机器学习
    (2017年写的博客,搬过来)断断续续看了几个月的机器学习,我觉得是时候总结一下了。正如题目讲的那样,我只说我所理解的机器学习,我不能保证我理解的都对,很多东西可能是我的误解,但无论说错了什么,我都认。如果有人发现错误,恳请指正,不胜感激。我不讲算法也不讲公式推导,因为,我从头到尾都......
  • 由AtCoder_ABC357D引发的除法同余学习
    鉴于最近的Atcoder周赛又出现除法求余,下定决心学习逆元相关内容同余概述定义同余定义:若a和b是整数,且m|(a-b),则称a和b模m同余。即两者除以m得到的余数相同。剩余系:一个模m完全剩余系是一个整数集合,任何一个整数恰好与该集合中的一个元素模m同余。例如0,1,...,m-1的集......
  • Java与机器学习:从零开始的入门指南
    引言随着人工智能和大数据的迅猛发展,机器学习已经成为现代技术的核心之一。虽然Python在机器学习领域占据主导地位,但Java凭借其稳定性、跨平台性和丰富的生态系统,依然是许多企业级应用的首选语言。在本系列文章中,我们将深入探讨如何使用Java进行机器学习,从基础概念到实际应......
  • 工业机器人远程运维,增强智慧工厂运营管理
    1、需求背景随着工业自动化技术的普及和工业机器人应用的增加,制造业对于生产线稳定性和效率的要求不断提高。然而,传统的现场监控方式存在着地理位置限制、实时监控难度大以及诊断能力有限等问题,迫切需要一种更具灵活性和效率的监控方式。实时监控与数据收集工厂希望能够通过......
  • 华为OD刷题C卷 - 每日刷题 22(计算面积、绘图机器,信道分配)
    1、(计算面积、绘图机器):这段代码是解决“计算面积、绘图机器”的问题。它提供了一个Java类Main,其中包含main方法,用于计算绘图机器按照给定指令绘制直线所形成的图形面积。main方法首先读取指令数量n和横坐标终点值end_X。然后,初始化面积和area为0,以及上一个点的坐标last_X......
  • nofile参数的学习与整理
    nofile参数的学习与整理背景前段时间正好总结了文件描述符泄露的问题.最近在客户现场,也遇到了一个问题.其实两个问题都是因为nofile参数限制所引发.所以总结一下:nginx的worker的连接数是受到到nofile的限制的.虽然那可以通过修改配置文件和直接ulimit-HSn进......
  • Python数据分析与机器学习在电子商务推荐系统中的应用
    文章目录......