目录
支持向量机
0. 前言
一般来说,我们进行机器学习大致上有三种算法:
1.监督式学习
监督式学习算法包括一个目标变量(也就是因变量)和用来预测目标变量的预测变量(相当于自变量)。通过这些变量,我们可以搭建一个模型,从而对于一个自变量得到对应的因变量。重复训练这个模型直到它能在训练数据集上达到理想的准确率。
属于监督式学习的算法:回归模型、决策树、随机森林、K近邻算法、逻辑回归等算法。
2.无监督式算法
无监督式学习不同的是无监督学习中我们没有需要预测或估计的因变量。无监督式学习是用来对总体对象进行分类的。它在根据某一指标将客户分类上有广泛作用。
属于无监督式学习的算法:关联规则、K-means聚类算法等。
3.强化学习
这种算法可以训练程序作出某一决定,程序在某一情况下尝试所有的可能行为,记录不同行动的结果并试着找出最好的一次尝试来做决定。
属于强化学习的算法:马尔可夫决策过程。
1. 算法综述
支持向量机(Support Vector Machine, SVM)是一类按监督学习(supervised learning)方式对数据进行二元分类的广义线性分类器(generalized linear classifier),其决策边界是对学习样本求解的最大边距超平面(maximum-margin hyperplane)。它的基本模型是定义在特征空间上的间隔最大的线性分类器。
SVM使用铰链损失函数(hinge loss)计算经验风险(empirical risk)并在求解系统中加入了正则化项以优化结构风险(structural risk),是一个具有稀疏性和稳健性的分类器。SVM可以通过核方法(kernel method)进行非线性分类,是常见的核学习(kernel learning)方法之一。SVM被提出于1964年,在二十世纪90年代后得到快速发展并衍生出一系列改进和扩展算法,在人像识别、文本分类等模式识别(pattern recognition)问题中有得到应用。
2. 算法原理
假设给定一个特征空间上的训练数据集:
其中,,,,为第个特征向量,为第类标记。当其等于+1时为正例;为0时为负例。再假设训练数据集是线性可分的。
相关原理推导可以参考:支持向量机原理
3. 基本步骤
SVM学习的基本想法是求解能够正确划分训练数据集并且几何间隔最大的分离超平面。如下图所示,即为分离超平面。对于线性可分的数据集来说,这样的超平面有无穷多个(即感知机),但是几何间隔最大的分离超平面却是唯一的。这也是支持向量机与感知机的区别。
假设待分类数据的二维分布如下图所示,那么简单说来,我们就需要在图中找到一条直线能最大程度将不同组的点分开;如果我们仅仅是要把两组数据分开,那么在这两组数据之间有无数条斜线可以把两者分开,也就是说存在满足这样要求的斜线的斜率有无穷多个。但是根据支持向量机我们应当寻找两组数据中距离这条线最近的点到这条线的距离都应该是最远的,这样的直线有且只有一条。
假设求出了这样一条满足要求的最佳分割线。因为这条线到两组中距它最近的点的距离都是最远的,任何其他线必然会使得到其中一个点的距离比这个距离近。这样根据数据点分布在这条线的不同侧,就可以将数据归类。
3. 分步解释
3.1 库函数准备
#matplotlib&&numpy
import matplotlib.pyplot as plt
import numpy as np
编写支持向量机我们需要导入两个库函数:numpy和matplotlib,前者主要是用来进行“数组”计算方面;后者主要是完成结果的可视化输出,该库函数的语法与MATLAB的plot函数类似。
3.2 获取训练样本信息
# 获取训练数据并解析坐标
get = input("请输入训练数据,第三个参数为类别")
get = get.split(',')# 用split划分每行数据,默认则是分割所有
train_data = []# 定义数组
x1 = []# 后缀0&1代表原始数组的类别
y1 = []
x0 = []
y0 = []
for each in get:# 历遍list
# fromstring函数获取一个字符串信息,并转化为float类型
train_data.append(np.fromstring(each, dtype=float, sep=' '))
for each in train_data:# 循环判断转化的字符串归属的类型
if each[2] == 1:
x1.append(each[0])
y1.append(each[1])
else:
x0.append(each[0])
y0.append(each[1])
此处我们要处理的数据格式形如:[x,y,c];其中x和y为样本的两种属性,也可以理解为二维图中的横轴和纵轴;c为该种属性所属的类别,一般为两类,此处为[0,1]两种。
get变量为list,each为str,此处有一个函数需要注意理解一下,主要是将数据转换为float类型。随后循环判断样本数据的归属。
3.3 随机化数据
# 随机化数据
np.random.seed(np.random.randint(0, 10000, size=1, dtype=int))
order1 = np.random.permutation(len(x1))
order0 = np.random.permutation(len(x0))
这里随机化处理主要目的是为了提高准确性。如果不进行随机化,会使得支持向量机陷入某种极端情况,从而得出错误的解。首先初始化随机种子;然后随机化排列,这样可以得到一个随机的排列,以在后续处理数据时相对公平。
3.4 生成分界线
# 生成分界线斜率
slope = 1.0
adjust = 0.0
learn = 0.5
for i in range(len(x1)):
slope += (y1[order1[i]] - slope*x1[order1[i]] + adjust)/x1[order1[i]]*learn
slope += (y0[order0[i]] - slope*x0[order0[i]] - adjust)/x0[order0[i]]*learn
print(slope)
这一步是最核心的一步,我们通过输入的训练数据对直线斜率进行调整。
方法就是利用预测值与期望值之间的误差对slope进行调整,同时引入了两个变量:学习率learn
和调整量adjust,
来改变这种调整的速度,使得“训练过的”和“即将训练的”数据能同时起到作用。
3.5 处理测试数据
# 处理测试数据
get = input("请输入测试数据:")
get = get.split(',')
test_data = []
x2 = []
y2 = []
for i in get:
test_data.append(np.fromstring(i, dtype=float, sep=' '))
for i in test_data:
x2.append(i[0])
y2.append(i[1])
for i in range(len(x2)):
if x2[i]*slope > y2[i]:
print(0)
else:
print(1)
将类别为0的样本分在“下方”,类别为1的样本分在“上方”。
3.6 可视化输出
# 可视化输出
x = np.array(range(7))
y = []
for i in x:
y.append(slope*i)
plt.figure(figsize=(12, 10))
plt.xlim(0, 6)# 设定x轴的范围
plt.ylim(0, 5)
plt.plot(x, y, linestyle='-')
plt.plot(x1, y1, 'o', color='red')
plt.plot(x0, y0, 'v', color='blue')
plt.plot(x2, y2, 'x', color='black')
plt.show()
4. 代码实例
'''
@Author: FangChur
@Date: 2020-04-07 21:07:46
@LastEditTime: 2020-04-08 16:43:34
@LastEditors: Please set LastEditors
@Description: In User Settings Edit
@FilePath: \learn\classify.py
'''
#matplotlib&&numpy
import matplotlib.pyplot as plt
import numpy as np
# 获取训练数据并解析坐标
get = input("请输入训练数据,第三个参数为类别")
get = get.split(',')# 用split划分每行数据,默认则是分割所有
train_data = []# 定义数组
x1 = []# 后缀0&1代表原始数组的类别
y1 = []
x0 = []
y0 = []
for each in get:# 历遍list
# fromstring函数获取一个字符串信息,并转化为float类型
train_data.append(np.fromstring(each, dtype=float, sep=' '))
for each in train_data:# 循环判断转化的字符串归属的类型
if each[2] == 1:
x1.append(each[0])
y1.append(each[1])
else:
x0.append(each[0])
y0.append(each[1])
# 随机化数据
np.random.seed(np.random.randint(0, 10000, size=1, dtype=int))
order1 = np.random.permutation(len(x1))
order0 = np.random.permutation(len(x0))
# 生成分界线斜率
slope = 1.0
adjust = 0.0
learn = 0.5
for i in range(len(x1)):
slope += (y1[order1[i]] - slope*x1[order1[i]] + adjust)/x1[order1[i]]*learn
slope += (y0[order0[i]] - slope*x0[order0[i]] - adjust)/x0[order0[i]]*learn
print(slope)
# 处理测试数据
get = input("请输入测试数据:")
get = get.split(',')
test_data = []
x2 = []
y2 = []
for i in get:
test_data.append(np.fromstring(i, dtype=float, sep=' '))
for i in test_data:
x2.append(i[0])
y2.append(i[1])
for i in range(len(x2)):
if x2[i]*slope > y2[i]:
print(0)
else:
print(1)
# 可视化输出
x = np.array(range(7))
y = []
for i in x:
y.append(slope*i)
plt.figure(figsize=(12, 10))
plt.xlim(0, 6)
plt.ylim(0, 5)
plt.plot(x, y, linestyle='-')
plt.plot(x1, y1, 'o', color='red')
plt.plot(x0, y0, 'v', color='blue')
plt.plot(x2, y2, 'x', color='black')
plt.show()
注:本次代码在Visual Studio Code编译完成
'''
训练集# 1 3 1,3 1 0,2 2 1,4 1 0,2 4 1,4.5 1 0,3 2.5 1,5 2 0
1.0 3.0 1,
3.0 1.0 0,
2.0 2.0 1,
4.0 1.0 0,
2.0 4.0 1,
4.5 1.0 0,
3.0 2.5 1,
5.0 2.0 0
# 测试集# 4 3,2.5 2.5,3.6 1.5,5 1.5
4.0 3.0,
2.5 2.5,
3.6 1.5,
5.0 1.5
'''
5. 结果输出