天天看點

SVM算法實作光學字元識别

目錄

1、資料來源

2、資料預處理

3、模型訓練

4、模型性能評估

5、模型性能提升

5.1、核函數的選取

5.2、懲罰參數C的選取

OCR (Optical Character Recognition,光學字元識别)是指電子裝置(例如掃描器或數位相機)檢查紙上列印的字元,通過檢測暗、亮的模式确定其形狀,然後用字元識别方法将形狀翻譯成計算機字元的過程;即,針對印刷體字元,采用光學的方式将紙質文檔中的文字轉換成為黑白點陣的圖像檔案,并通過字元識别模型将圖像中的文字處理成文本格式。

光學字元識别是OCR的核心,然而對于許多類型的機器學習算法來說,這種圖像處理都是一項艱巨的任務。 将像素模式連接配接到更高概念的關系是極其複雜的,而且很難定義。 例如,讓一個人識别一張面孔、一隻貓或字母A是容易的,但用嚴格的規則來定義這些模式是很困難的。 此外,圖像資料往往是噪聲資料,對于光學字元圖像,燈光、定位和對象的位置都能影響最終的圖像資料。

支援向量機非常适合處理圖像資料,它能夠學習複雜的圖案而不需要對噪聲資料過度敏感,能夠以較高的準确度識别光學圖案。

本博文中,将使用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的相關性

光學字元識别資料集中包含16個特征變量,這些變量用字元矩形區域的水準位置和豎直位置、黑色像素比例、黑色像素的平均水準和豎直位置來度量一個字元。

首先,使用pandas中的read_csv()函數将資料導入,實作代碼如下所示:

import pandas as pd
letters = pd.read_csv("./input/letterecognition.csv")
letters.head(10)      

前10行資料格式如下所示:

SVM算法實作光學字元識别

接下來使用pandas中Series的value_counts()函數,觀察資料集中每一種字元的數量分布。

sort_index()函數可以讓結果按照字母排序展示結果,實作代碼如下所示:

letters["letter"].value_counts().sort_index()      

效果如下所示:

SVM算法實作光學字元識别

可見,各個字元的樣本數量分布相對均衡。

現在,進一步觀察每一個自變量的取值分布,實作代碼如下所示:

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,]      

接下來使用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, coef0=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)      

接下來,使用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%。

對于支援向量機,有兩個主要的參數能夠影響模型的性能:一是核函數的選取,二是懲罰參數C的選擇。 下面,期望通過分别嘗試這兩個參數來進一步改善模型的預測性能。

在 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%

我們将分别測試 𝐶=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%。