支持向量机
其本质就是找到正确分类的一组线,也就是寻找一条y = kx+b的直线,使得这条直线距离最接近的点距离最远
-
距离最接近的数据点称为支持向量(support vector),支持向量定义的沿着分割线的区域称为间隔(margin)
以上所述只是二维下的情况,如果遇到三维、四维、五维或者更高维的更复杂问题,那么我们据需要找到一个超平面,使得它能够尽可能多的将两类数据点正确的分开,同时使分开的两类数据点距离分类面最远。
-
由于支持向量机在分类的时候可能将分割线划分在一定的范围内分割效果会更好,但是此范围内包含不同种类的数据,所以支持向量机存在一个参数叫 允许误差,也就是在划分错误个数允许的的范围内求分割线。(第一个允许误差最大,所以其分割线范围就很大,反之,最后一个允许误差最小)
-
非线性可分:并不是所有的数据都是可以直接使用二维空间的一条直线进行分割,有时可能需要对其进行升维,在更高维度可能会有更适合的分类办法。有时候二维线性不可分的数据,在更高维度可以找到线性可分的办法。但是,在更高维度分类完成之后一定要映射回数据原本的维度,映射回二维后的分割线称为分类超平面。虽然常常会用到映射到高维空间的做法,但是如果凡是遇到线性不可分的数据,一律都映射到高维空间(如果二维不可分,映射到三维,三维不可分再映射到四维,然后再依次向上映射),那么这个维度的大小会高到可怕。
-
核函数:它虽然也是将特征进行从低维到高维的转换,但是核函数事先在低维上进行计算,而将实质上的分类效果表现到了高维上,也就避免了直接在高维空间中的复杂计算,但其能这样做必须有两个先决条件:
-
定义的核函数能够对应于特征空间中的内积(内积就是点积)
-
识别方法中不需要计算特征空间中的矢量本身,只需算特征空间中两个矢量的内积
几类常用的核函数:
-
线性核函数:
-
多项式核函数:
-
高斯核函数:是一种鲁棒径向基核,对于数据中的噪音有着较好的抗干扰能力
-
-
支持向量机的时间过程:
未调整参数的支持向量机在分类精度上不及Knn算法,但是在速度上相对于Knn算法快很多,下面是用支持向量机对手写字识别进行的运算:
# -*- coding: utf-8 -*-
# @Time : 2021/7/22 12:42
# @Author : wcc
# @FileName: SkLearnTest.py
# @Software: PyCharm
# @Blog :https://blog.youkuaiyun.com/qq_41575517?spm=1000.2115.3001.5343
# 导入库
from sklearn import svm
import HandwritingRecognition as hw
training_dir_name = 'trainingDigits'
trainingSet, trainingLabelSet = hw.HwRecognition(dir_name=training_dir_name).pretreatment()
test_dir_name = 'testDigits'
testSet, testLabelSet = hw.HwRecognition(dir_name=test_dir_name).pretreatment()
# 模型定义
model = svm.SVC()
# 模型函数,参数为样本数据和数据标签
model.fit(trainingSet, trainingLabelSet)
# 模型测试,predict()方法为预测方法
result = model.predict(testSet)
# 错误条数
errorCount = 0
# 错误记录
errorRecords = {}
# 错误值与正确值的比对
correctRecords = {}
for i in range(int(testSet.shape[0])):
if testLabelSet[i] != result[i]:
errorCount += 1
errorRecords[i] = result[i]
correctRecords[i] = testLabelSet[i]
print('错误个数:')
print(errorCount)
print('错误位置及错误值:')
print(errorRecords)
print('相应位置的正确值:')
print(correctRecords)
print("正确率:%f%%" % ((1-errorCount / int(testSet.shape[0]))*100))
鸢尾花数据集用向量机进行处理:
# -*- coding: utf-8 -*-
# @Time : 2021/7/16 21:45
# @Author : wcc
# @FileName: KnnIris.py
# @Software: PyCharm
# @Blog :https://blog.youkuaiyun.com/qq_41575517?spm=1000.2115.3001.5343
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn import svm
class Iris:
def __init__(self, file_name, data_set, labels_set, normal_data_set, data_division):
self.fileName = file_name
self.dataMat = data_set
self.labelsMat = labels_set
self.normalDataSet = normal_data_set
self.dataDivision = data_division
# 数据预处理
def iris_processData(self):
fr = open(self.fileName)
numOfLines = len(fr.readlines())
# 此处一定记得要把标签排除在外
dataMat = np.zeros((numOfLines, 4))
# 标签单独成一列
labelsMat = []
fr.seek(0, 0)
index = 0
for line in fr.readlines():
line = line.strip()
listLine = line.split(',')
dataMat[index, :] = listLine[0:4]
if listLine[-1] == 'Iris-setosa':
labelsMat.append(1)
if listLine[-1] == 'Iris-versicolor':
labelsMat.append(2)
if listLine[-1] == 'Iris-virginica':
labelsMat.append(3)
index += 1
labelsMat = np.array(labelsMat)
self.dataMat = dataMat
self.labelsMat = labelsMat
# 数据归一化(0-1归一化)
def iris_normal(self):
colDataMax = self.dataMat.max(0)
colDatamin = self.dataMat.min(0)
normalDataSet = np.zeros(self.dataMat.shape)
normalDataSet = (self.dataMat - colDatamin)/(colDataMax - colDatamin)
self.normalDataSet = normalDataSet
# 支持向量机对测试集进行测试
def iris_vector(self):
totSize = int(self.normalDataSet.shape[0])
trainSize = int(self.normalDataSet.shape[0]*self.dataDivision)
testSize = int(self.normalDataSet.shape[0]*(1-self.dataDivision))
result = []
errorCount = 0
errorRecords = {}
correctRecords = {}
index = 0
# 使用支持向量机进行运算
# 模型定义
model = svm.SVC()
# 模型函数,参数为样本数据和数据标签
model.fit(self.normalDataSet[0:trainSize, :], self.labelsMat[0:trainSize])
# 模型测试,predict()方法为预测方法
result = model.predict(self.normalDataSet[trainSize:totSize, :])
for i in range(int(testSize)):
if self.labelsMat[trainSize + i] != result[i]:
errorCount += 1
errorRecords[i] = result[i]
correctRecords[i] = self.labelsMat[trainSize + i]
print('错误个数:')
print(errorCount)
print('错误位置及错误值:')
print(errorRecords)
print('相应位置的正确值:')
print(correctRecords)
print('正确率:%f%%' % ((1-errorCount/testSize)*100))
if __name__ == '__main__':
fileName = 'iris.txt' # 'datingTestSet.txt'# 文件路径
dataMat = [] # 数据集(自己读取)
labelsMat = [] # 标签集(自己读取)
normalDataSet = [] #归一化后的数据集
dataDivision = 0.8 # 数据集中训练集和测试集的划分比例
iris = Iris(file_name=fileName, data_set=dataMat, labels_set=labelsMat, normal_data_set=normalDataSet, data_division=dataDivision)
iris.iris_processData()
iris.iris_normal()
iris.iris_vector()