1. 程式人生 > >基於SVM和KNN的手寫數字的識別(分類)——小試牛刀篇

基於SVM和KNN的手寫數字的識別(分類)——小試牛刀篇

下面分別採用的是k近鄰演算法(KNN)和SVM實現的手寫數字識別。

python實現程式碼:

# -*- coding: utf-8 -*-
import os
import numpy as np

def img2vector(filename, label): #影象資料轉為向量
    f = open(filename,'r')
    row_data = f.read()
    row_data = row_data.replace('\n','')  #換行符轉為空格
    row_data = row_data + label
    row_data = np.array(map(int, list(row_data)))  #將string轉為np.array
    return row_data

#k緊鄰(KNN)分類演算法
def classify0(rowX, dataSet, k): 
    '''
    rowX是待分類的向量, dataSet是標記好的訓練集, k表示選擇最近鄰居的數目
    '''
    #距離計算:絕對值距離
    dataSetSize = dataSet.shape[0]
    #print dataSetSize
    rowMat = np.zeros((dataSetSize, 1025), np.int)
    for i in range(dataSetSize):
        rowMat[i] = rowX
    diffMat = rowMat - dataSet
    label0 = dataSet[:,1024]         #取出訓練集label
    diffMat2 = diffMat[:,0:1024]    #差分矩陣去除label列
    diffMat3 = diffMat2**2  #差分矩陣的平方,即是絕對值
    dis = diffMat3.sum(axis = 1)  #沿行求和,即是該待分類向量與訓練集中每條資料的距離
    
    #選擇距離最小的k個點
    sortedIndice = dis.argsort()
    #print sortedIndice
    vote_label = np.zeros((1,10), np.int)
     
    for i in range(k):
        label= label0[sortedIndice[i]] #獲取第i小距離的label
        vote_label[0,label] = vote_label[0,label] + 1
    sorted_vote = vote_label.argsort()
    #print sorted_vote
    return sorted_vote[0,9]
    
    
    
#將訓練集資料儲存到np陣列train_data中
train_dir = 'trainingDigits\\'   
train_filename = os.listdir(train_dir)  #獲取trainingDigits目錄下的檔名
m = len(train_filename)
train_data = np.zeros((m,1025), np.int)
for i in range(0, m):
    label = train_filename[i].split('_')[0]
    row = img2vector(train_dir +  train_filename[i], label)
    train_data[i] = row

#將測試集資料儲存到np陣列test_data中
test_dir = 'testDigits\\'   
test_filename = os.listdir(test_dir)  #獲取trainingDigits目錄下的檔名
m = len(test_filename)
test_data = np.zeros((m,1025), np.int)
test_result = np.zeros((m,1),np.int)
for i in range(0, m):
    label = test_filename[i].split('_')[0]
    test_result[i] = int(label)  #儲存測試集正確的分類
    row = img2vector(test_dir +  test_filename[i], '0')   #測試集初始分類設定為0
    test_data[i] = row

cc = 0

for i in range(m):
    ll = classify0(test_data[i], train_data, 5)
    #print ll,test_result[i]
    if ll == test_result[i]:
        cc = cc + 1
    else:
        print i,ll,test_result[i]
    
print '正確率是:%f' %(float(cc)/float(m))

    
    


執行結果如下圖:

輸出的每一行表示分類錯誤的資料,每一行的第1列是測試集的id,第2列是KNN演算法分類的結果,第三列是正確的分類結果。


svm實現手寫字型分類,程式碼如下:

# -*- coding: utf-8 -*-
import os
from sklearn import svm

def img2vector(filename): #影象資料轉為list
    f = open(filename,'r')
    row_data = f.read()
    row_data = row_data.replace('\n','')  #換行符轉為空格
    row_data = list(row_data)
    for i in range(len(row_data)):
        row_data[i] = int(row_data[i])
    return row_data

train_dir = 'trainingDigits\\'   
train_filename = os.listdir(train_dir)  #獲取trainingDigits目錄下的檔名
m = len(train_filename)

X = []
Y = []
for i in range(0, m):
    label = train_filename[i].split('_')[0]
    Y.append(int(label))
    row = img2vector(train_dir +  train_filename[i])
    X.append( row )

clf = svm.SVC(decision_function_shape='ovo')
clf.fit(X, Y) 

test_dir = 'testDigits\\'   
test_filename = os.listdir(test_dir)  #獲取trainingDigits目錄下的檔名
m = len(test_filename)
X_test = []
Y_test = []

for i in range(0, m):
    label = test_filename[i].split('_')[0]
    Y_test.append(int(label))  #儲存測試集正確的分類
    row = img2vector(test_dir +  test_filename[i])   
    X_test.append(row)
ans = clf.predict(X_test)

cc = 0
ll = len(ans)
for i in range(ll):
    if Y_test[i] == ans[i]:
        cc +=1
    else:
        print "分錯的檔案為%s,被分類為%d" %(test_filename[i],ans[i])

print '正確率是:%f' % (1.0*cc/ll)
執行結果:



參考資料:

1、機器學習實戰

2、http://scikit-learn.org/stable/modules/svm.html#svm