案例6:基于SVM的数字识别
为什么写本博客
前人种树,后人乘凉。希望自己的学习笔记可以帮助到需要的人。
需要的基础
懂不懂原理不重要,本系列的目标是使用python实现机器学习。
必须会的东西:python基础、numpy、pandas、matplotlib和库的使用技巧。
说明
完整的代码在最后,另外之前案例中出现过的方法不会再讲解。
目录结构
1. 涉及的新方法:
模型创建
from sklearn import svm
# 创建模型
model = svm.SVC()
'''
核心参数:
C 正则化因子,越大,意味着划分越严格,即越接近线性分割
kernel 核函数,常用的 poly\rbf\sigmoid
degree 当为poly多项式核函数的时候启用,指定多项式次数
'''
2. 数据集介绍与处理:
数据集介绍与下载
MNIST是一个经典的手写数字数据,也是一个公开的小型数据。
数据集可以通过官网进行下载http://yann.lecun.com/exdb/mnist/
,不过,这个网址似乎要用点魔法才可以打开,所以,我也用百度云分享下:
链接:https://pan.baidu.com/s/1P5c4GJQqfuWDP2g6wM5Slw
提取码:6666
其中,主要分为两个文件夹,一个是原始数据文件夹,即从网站下载的;第二个是做出处理后的文件夹,即划分为测试集和训练集,并且将图像数据转为矩阵数据了,这也是我们需要使用的数据(这个数据集来自于网上黑马的案例,特此声明)。
MNIST中的图像每个都是28*28=784的大小,并且为灰度图,值为0-255。训练集共有785列,第一列为标签列,后面每列为一个像素值。
数据集加载和提取
首先,使用pandas加载数据:
# 加载数据
data = pd.read_csv('./data/MNIST/train.csv')
print(data.head())
print(data.shape)
打印结果为:
label pixel0 pixel1 pixel2 ... pixel780 pixel781 pixel782 pixel783
0 1 0 0 0 ... 0 0 0 0
1 0 0 0 0 ... 0 0 0 0
2 1 0 0 0 ... 0 0 0 0
3 4 0 0 0 ... 0 0 0 0
4 0 0 0 0 ... 0 0 0 0
[5 rows x 785 columns]
(42000, 785)
接着,提取出x和y数据,但是由于整体数据量太大,足足有42000条,而这里我们又不采用降维或者特征提取等手段,会导致模型计算时间非常长,因此我们取出3000
条数据进行测试:
# 提取x和y
x_train = data.iloc[:3000,1:]
y_train = data.iloc[:3000,0]
print(y_train.head())
打印结果为:
0 1
1 0
2 1
3 4
4 0
Name: label, dtype: int64
数据集显示
我们定义一个显示函数,可以把任意一条数据显示为数字,处理的思路:首先把行向量转为矩阵,再用matplotlib显示即可;
# 定义显示函数
def show_image(index):
# index : 传入的索引
target = x_train.iloc[index,:].values.reshape(28,28)
plt.imshow(target)
plt.show()
# 尝试
show_image(0)
显示的结果为:
一个明显的问题,这里显然颜色不对劲,这是因为matplotlib的颜色空间和我们认为的颜色空间不一致所致。不过,这也无伤大雅,问题不大(当然,你想改还是很轻松的,可以使用opencv库中的颜色空间转变)。
归一化
下面,将数据归一化,本来归一化公式为:
(xi - x_min) / (x_max - x_min)
而这里最小值为0,最大值为255,所以直接改写为:
x / 255
因此,代码可写为:
# 归一化处理
x_train = x_train.values / 255
y_train = y_train.values
划分数据集
由于给出的test.csv中没有标签,因此暂时没有办法用,只好将训练集划分了:
# 数据集划分
x_train,x_test,y_train,y_test = train_test_split(x_train,y_train,test_size=0.2,random_state=2)
3. 创建模型、训练和评估:
创建模型、训练和评估:
# 创建模型
model = svm.SVC()
model.fit(x_train,y_train)
# 评估
score = model.score(x_test,y_test)
print('准确率:',score)
打印结果为:
准确率: 0.9416666666666667
4. 探究不同参数准确率结果:
探究数据量影响
这里,我分别使用1000\2000\3000\4000
的数据来测试,所得结果为:
# 3000 : 准确率: 0.9416666666666667
# 2000 : 准确率: 0.945
# 1000 : 准确率: 0.92
# 4000 : 准确率: 0.9325
不同正则化因子的影响:
数据集为3000条,进行测试,结果如下:
# 3000
# C=0.5 准确率: 0.9266666666666666
# C=0.7 准确率: 0.93
# C=1 准确率: 0.9416666666666667
# C=1.2 准确率: 0.9433333333333334
# C=5 准确率: 0.94
# C=20 准确率: 0.94
不同核函数
采取了高斯核函数、sigmoid核函数和多项式核函数:
# RBF : 准确率: 0.9416666666666667
# sigmoid : 准确率: 0.865
# poly : 次数为3 准确率: 0.915 ; 次数为4 准确率: 0.875 ; 次数为5 准确率: 0.82
通过上面的结果,知道不同的参数具有不同的影响,当然单纯通过数据集大小来判断模型好坏不可取,主要还是对数据集的利用程度。
5. 总结和完整代码:
这里不得不提一句,明明有这么多的数据,但是由于没有进行特征提取,导致我们只能对原始数据加载,这会导致我们的计算时间拉长。这告诉我们,特征提取在机器学习中的重要性。
完整代码:
# author: baiCai
# 导包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.model_selection import train_test_split
# 加载数据
data = pd.read_csv('./data/MNIST/train.csv')
# print(data.head())
# print(data.shape) # (42000, 785)
# 提取x和y
x_train = data.iloc[:3000,1:]
y_train = data.iloc[:3000,0]
# print(y_train.head())
# 定义显示函数
def show_image(index):
# index : 传入的索引
target = x_train.iloc[index,:].values.reshape(28,28)
plt.imshow(target)
plt.show()
# 尝试
# show_image(0)
# 归一化处理
x_train = x_train.values / 255
y_train = y_train.values
# 数据集划分
x_train,x_test,y_train,y_test = train_test_split(x_train,y_train,test_size=0.2,random_state=2)
# 创建模型
model = svm.SVC()
model.fit(x_train,y_train)
# 评估
score = model.score(x_test,y_test)
print('准确率:',score)
# 3000 : 准确率: 0.9416666666666667
# 2000 : 准确率: 0.945
# 1000 : 准确率: 0.92
# 4000 : 准确率: 0.9325
# 3000
# C=0.5 准确率: 0.9266666666666666
# C=0.7 准确率: 0.93
# C=1 准确率: 0.9416666666666667
# C=1.2 准确率: 0.9433333333333334
# C=5 准确率: 0.94
# C=20 准确率: 0.94
# RBF : 准确率: 0.9416666666666667
# sigmoid : 准确率: 0.865
# poly : 次数为3 准确率: 0.915 ; 次数为4 准确率: 0.875 ; 次数为5 准确率: 0.82