目录
OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机字符的过程;即,针对印刷体字符,采用光学的方式将纸质文档中的文字转换成为黑白点阵的图像文件,并通过字符识别模型将图像中的文字处理成文本格式。
光学字符识别是OCR的核心,然而对于许多类型的机器学习算法来说,这种图像处理都是一项艰巨的任务。 将像素模式连接到更高概念的关系是极其复杂的,而且很难定义。 例如,让一个人识别一张面孔、一只猫或字母A是容易的,但用严格的规则来定义这些模式是很困难的。 此外,图像数据往往是噪声数据,对于光学字符图像,灯光、定位和对象的位置都能影响最终的图像数据。
支持向量机非常适合处理图像数据,它能够学习复杂的图案而不需要对噪声数据过度敏感,能够以较高的准确度识别光学图案。
1、数据来源
本博文中,将使用UCI公开的光学字符识别数据集(http://archive.ics.uci.edu/ml/datasets/Letter+Recognition),利用支持向量机(SVM)来构建光学字符识别模型。
该数据集包含了26个英文大写字母的20000个样本。 每一个样本代表光学图像中的一个矩形区域,该区域只包含单一字符。 每一个样本包含16个自变量和letter目标变量,letter指示当前样本是哪一个字母。每一个特征变量的具体含义如下:
- letter 字符 (取值为A,B,...,Z)
- x-box 字符所在矩形区域的水平位置
- y-box 字符所在矩形区域的竖直位置
- width 矩形区域的宽度
- high 矩形区域的高度
- onpix 矩阵区域的黑色像素数
- x-bar 矩形区域内黑色像素的平均x值
- y-bar 矩形区域内黑色像素的平均y值
- x2bar x平均方差
- y2bar y平均方差
- xybar x和y的平均相关性
- x2ybr x * x * y 均值
- xy2br x * y * y 均值
- x-ege 从左到右的边缘数目
- xegvy x边缘与y的相关性
- y-ege 从下到上的边缘数目
- yegvx y边缘与x的相关性
2、数据预处理
光学字符识别数据集中包含16个特征变量,这些变量用字符矩形区域的水平位置和竖直位置、黑色像素比例、黑色像素的平均水平和竖直位置来度量一个字符。
首先,使用pandas中的read_csv()函数将数据导入,实现代码如下所示:
-
import pandas
as pd
-
letters = pd.read_csv(
"./input/letterecognition.csv")
-
letters.head(
10)
前10行数据格式如下所示:
接下来使用pandas中Series的value_counts()函数,观察数据集中每一种字符的数量分布。
sort_index()函数可以让结果按照字母排序展示结果,实现代码如下所示:
letters["letter"].value_counts().sort_index()
效果如下所示:
可见,各个字符的样本数量分布相对均衡。
现在,进一步观察每一个自变量的取值分布,实现代码如下所示:
letters.iloc[:,1:].describe()
数据取值分布如下所示:
xbox | ybox | width | height | onpix | xbar | ybar | x2bar | y2bar | xybar | x2ybar | xy2bar | xedge | xedgey | yedge | yedgex | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 20000.000000 | 20000.000000 | 20000.000000 | 20000.00000 | 20000.000000 | 20000.000000 | 20000.000000 | 20000.000000 | 20000.000000 | 20000.000000 | 20000.00000 | 20000.000000 | 20000.000000 | 20000.000000 | 20000.000000 | 20000.00000 |
mean | 4.023550 | 7.035500 | 5.121850 | 5.37245 | 3.505850 | 6.897600 | 7.500450 | 4.628600 | 5.178650 | 8.282050 | 6.45400 | 7.929000 | 3.046100 | 8.338850 | 3.691750 | 7.80120 |
std | 1.913212 | 3.304555 | 2.014573 | 2.26139 | 2.190458 | 2.026035 | 2.325354 | 2.699968 | 2.380823 | 2.488475 | 2.63107 | 2.080619 | 2.332541 | 1.546722 | 2.567073 | 1.61747 |
min | 0.000000 | 0.000000 | 0.000000 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.00000 |
25% | 3.000000 | 5.000000 | 4.000000 | 4.00000 | 2.000000 | 6.000000 | 6.000000 | 3.000000 | 4.000000 | 7.000000 | 5.00000 | 7.000000 | 1.000000 | 8.000000 | 2.000000 | 7.00000 |
50% | 4.000000 | 7.000000 | 5.000000 | 6.00000 | 3.000000 | 7.000000 | 7.000000 | 4.000000 | 5.000000 | 8.000000 | 6.00000 | 8.000000 | 3.000000 | 8.000000 | 3.000000 | 8.00000 |
75% | 5.000000 | 9.000000 | 6.000000 | 7.00000 | 5.000000 | 8.000000 | 9.000000 | 6.000000 | 7.000000 | 10.000000 | 8.00000 | 9.000000 | 4.000000 | 9.000000 | 5.000000 | 9.00000 |
max | 15.000000 | 15.000000 | 15.000000 | 15.00000 | 15.000000 | 15.000000 | 15.000000 | 15.000000 | 15.000000 | 15.000000 | 15.00000 | 15.000000 | 15.000000 | 15.000000 | 15.000000 | 15.00000 |
观察发现16个自变量的取值范围都在0~15之间,因此对于该数据集不需要对变量进行标准化操作。
此外,数据集作者已经将样本随机排列,所以也不需要我们对数据进行随机打散。 此处,直接取前14000个样本(70%)作为训练集,后6000个样本(30%)作为测试集,实现代码如下所示:
-
letters_train = letters.iloc[
0:
14000,]
-
letters_test = letters.iloc[
14000:
20000,]
3、模型训练
接下来使用sklearn.svm包中的相关类来实现来构建基于支持向量机的光学字符识别模型。
在sklearn.svm包中,有三个类均实现了支持向量机算法:SVC, NuSVC 和 LinearSVC。 SVC 和 NuSVC接受的参数有细微差别,且底层的数学形式不一样。 而 LinearSVC 则是使用简单的线性核函数,其实现基于liblinear (https://www.csie.ntu.edu.tw/~cjlin/liblinear/), 对于大规模的样本训练速度会更快。 这三个支持向量机的具体介绍参考sklearn官方文档:http://scikit-learn.org/stable/modules/svm.html。
本案例中,选用 SVC 来进行模型构建。 SVC 有两个主要的参数可以设置:核函数参数 kernel 和约束惩罚参数C。 核函数参数 kernel的常用取值及其对应含义如下:
- "linear":线性核函数
- "poly":多项式核函数
- "rbf":径向基核函数
- "sigmoid": sigmoid核函数
约束惩罚参数C为对超过约束条件的样本的惩罚项。C值越大,惩罚越大,支持向量机的决策边界越窄。
现在,可以使用训练集构建分类模型了,选用最简单的线性核函数,C采用默认值1。实现代码如下所示:
-
from sklearn.svm
import SVC
-
letter_recognition_model = SVC(C =
1, kernel =
"linear")
-
letter_recognition_model.fit(letters_train.iloc[:,
1:],letters_train[
'letter'])
设置成功后,SVC配置参数效果如下所示:
-
SVC(C=
1, cache_size=
200, class_weight=None, coef
0=
0.
0,
-
decision_function_shape=None, degree=
3, gamma='auto', kernel='linear',
-
max_iter=-
1, probability=False, random_state=None, shrinking=True,
-
tol=
0.
001, verbose=False)
4、模型性能评估
接下来,使用predict()函数得到上一节训练的支持向量机模型在测试集合上的预测结果,然后使用 sklearn.metrics中的相关函数对模型的性能进行评估,实现代码如下所示:
-
from sklearn
import metrics
-
letters_pred = letter_recognition_model.predict(letters_test.iloc[:,
1:])
-
print(metrics.classification_report(lettters_test[
"letter"], letters_pred))
-
print(pd.DataFrame(metrics.confusion_matrix(lettters_test[
"letter"], letters_pred),\
-
columns = letters[
"letter"].value_counts().sort_index().index,\
-
index = letters[
"letter"].value_counts().sort_index().index))
效果如下所示:
-
precision
recall
f1-score
support
-
-
A
0.92
0.92
0.92
245
-
B
0.78
0.87
0.82
207
-
C
0.82
0.84
0.83
202
-
D
0.77
0.91
0.83
251
-
E
0.80
0.86
0.83
230
-
F
0.77
0.89
0.82
240
-
G
0.73
0.75
0.74
235
-
H
0.65
0.70
0.67
210
-
I
0.89
0.86
0.87
243
-
J
0.83
0.88
0.86
216
-
K
0.79
0.84
0.81
214
-
L
0.95
0.86
0.90
250
-
M
0.89
0.94
0.92
224
-
N
0.95
0.88
0.91
246
-
O
0.87
0.71
0.78
216
-
P
0.92
0.80
0.86
246
-
Q
0.85
0.75
0.80
252
-
R
0.81
0.84
0.82
242
-
S
0.75
0.67
0.71
240
-
T
0.89
0.90
0.90
226
-
U
0.91
0.92
0.92
248
-
V
0.91
0.91
0.91
212
-
W
0.90
0.92
0.91
216
-
X
0.89
0.84
0.86
230
-
Y
0.93
0.88
0.90
223
-
Z
0.86
0.83
0.84
236
-
-
avg
/
total
0.85
0.84
0.84
6000
-
-
A
B
C
D
E
F
G
H
I
J
...
Q
R
S
T
\
-
A
225
1
0
2
0
0
2
0
0
1
...
0
2
1
0
-
B
0
181
0
4
1
0
1
2
1
1
...
0
10
4
0
-
C
1
0
169
0
8
0
7
0
0
0
...
0
0
0
0
-
D
1
9
0
228
0
1
1
2
0
1
...
0
0
0
0
-
E
0
2
5
0
197
2
11
0
0
0
...
1
1
1
5
-
F
0
1
3
1
3
213
1
2
2
3
...
0
0
0
4
-
G
0
2
14
2
1
4
177
2
0
0
...
9
3
5
0
-
H
1
4
2
12
0
5
4
147
0
1
...
3
9
0
1
-
I
0
1
2
4
0
7
0
0
208
12
...
0
0
2
0
-
J
2
0
0
2
0
2
0
3
11
190
...
0
0
2
0
-
K
0
0
2
5
4
0
1
5
0
0
...
0
12
0
0
-
L
0
0
5
5
6
0
3
2
0
0
...
4
1
3
1
-
M
1
3
0
0
0
0
0
3
0
0
...
0
2
0
0
-
N
1
0
0
7
0
0
0
10
0
0
...
0
2
0
0
-
O
3
0
3
7
0
0
2
26
0
1
...
5
1
0
0
-
P
0
2
0
3
0
25
5
0
1
1
...
1
1
0
0
-
Q
5
5
0
1
7
1
14
3
0
4
...
190
1
13
0
-
R
0
11
0
4
0
0
2
6
0
0
...
0
203
0
0
-
S
1
8
0
1
10
7
7
0
4
1
...
9
1
160
3
-
T
1
0
0
0
0
3
2
5
0
0
...
0
1
2
204
-
U
1
0
0
1
0
0
0
1
0
0
...
0
0
0
1
-
V
0
2
0
0
0
2
0
4
0
0
...
0
1
0
0
-
W
1
0
0
0
0
0
0
0
0
0
...
0
0
0
0
-
X
0
1
0
5
5
1
1
0
6
3
...
0
0
2
2
-
Y
0
0
0
3
0
4
0
3
1
0
...
2
0
0
5
-
Z
1
0
0
1
4
1
0
0
1
9
...
0
0
18
3
-
-
U
V
W
X
Y
Z
-
A
2
0
0
0
3
3
-
B
0
0
0
1
0
0
-
C
4
0
0
0
0
0
-
D
3
0
0
0
0
0
-
E
0
0
0
2
0
2
-
F
0
0
0
0
1
0
-
G
0
6
1
0
0
0
-
H
2
3
0
2
0
0
-
I
0
0
0
4
0
3
-
J
0
0
0
0
0
2
-
K
2
0
0
4
0
0
-
L
0
0
0
6
0
0
-
M
1
0
4
0
0
0
-
N
1
2
0
0
0
0
-
O
3
1
4
1
0
0
-
P
1
0
0
0
5
0
-
Q
0
1
0
0
0
0
-
R
0
1
0
1
0
0
-
S
0
0
0
2
1
20
-
T
0
0
0
0
3
3
-
U
228
0
6
0
0
0
-
V
0
193
6
0
1
0
-
W
2
2
199
0
0
0
-
X
1
0
0
193
1
0
-
Y
0
4
1
1
196
0
-
Z
0
0
0
1
0
196
-
-
[
26
rows
x
26
columns]
上述混淆矩阵中对角线的元素表示模型正确预测数,对角元素之和表示模型整体预测正确的样本数。
而非对角线元素上的值则可以反映模型在哪些类的预测上容易犯错,例如第P行第F列的取值为25,说明模型有25次将“P”字符错误地识别为“F”字符。直观来看,“P”和“F”相似度比较高,对它们的区分也更具有挑战性。 现在,来通过这个来计算模型在测试集中的预测正确率。代码如下所示:
-
agreement = lettters_test[
"letter"] == letters_pred
-
print(agreement.value_counts())
-
print(
"Accuracy:", metrics.accuracy_score(lettters_test[
"letter"], letters_pred))
预测正确率,效果如下所示:
-
True
5068
-
False
932
-
dtype:
int64
-
Accuracy:
0.844666666667
可见,初步模型在6000个测试样本中,正确预测5068个,整体正确率(Accuaray)为84.47%。
5、模型性能提升
对于支持向量机,有两个主要的参数能够影响模型的性能:一是核函数的选取,二是惩罚参数C的选择。 下面,期望通过分别尝试这两个参数来进一步改善模型的预测性能。
5.1、核函数的选取
在 SVC 中,核函数参数kernel可选值为"rbf"(径向基核函数)、“poly”(多项式核函数)、"sigmoid"(sigmoid核函数)和"linear"(线性核函数)。我们的初始模型选取的是线性核函数,下面我们观察在其他三种核函数下模型正确率的改变。实现代码如下所示:
-
kernels = [
"rbf",
"poly",
"sigmoid"]
-
for kernel
in kernels:
-
letters_model = SVC(C =
1, kernel = kernel)
-
letters_model.fit(letters_train.iloc[:,
1:],letters_train[
'letter'])
-
letters_pred = letters_model.predict(letters_test.iloc[:,
1:])
-
print(
"kernel = ", kernel ,
", Accuracy:",\
-
metrics.accuracy_score(lettters_test[
"letter"], letters_pred))
效果如下所示:
-
kernel = rbf , Accuracy:
0.971166666667
-
kernel = poly , Accuracy:
0.943166666667
-
kernel = sigmoid , Accuracy:
0.0376666666667
从结果可以看到,当选取RBF核函数时:
- 模型正确率由84.47%提高到97.12%
- 多项式核函数下模型正确率为94.32%
- sigmoid核函数下模型的正确率只有3.77%
5.2、惩罚参数C的选取
我们将分别测试 𝐶=0.01,0.1,1,10,100C=0.01,0.1,1,10,100时字符识别模型正确率的变化。
核函数选取径向基核函数(即"rbf"),实现代码如下所示:
-
c_list = [
0.01,
0.1,
1,
10,
100]
-
for C
in c_list:
-
letters_model = SVC(C = C, kernel =
"rbf")
-
letters_model.fit(letters_train.iloc[:,
1:],letters_train[
'letter'])
-
letters_pred = letters_model.predict(letters_test.iloc[:,
1:])
-
print(
"C = ", C ,
", Accuracy:",\
-
metrics.accuracy_score(lettters_test[
"letter"], letters_pred))
效果如下所示:
-
C =
0.
01 , Accuracy:
0.
059
-
C =
0.
1 , Accuracy:
0.
886333333333
-
C =
1 , Accuracy:
0.
971166666667
-
C =
10 , Accuracy:
0.
976166666667
-
C =
100 , Accuracy:
0.
976333333333
可见,当惩罚参数C设置为10和100时,模型正确率进一步提升,分别达到97.62%和97.63%。
转载:https://blog.csdn.net/m0_38106923/article/details/115449342