使用K-近鄰分類器構造手寫識別系統,手寫數字圖片已經經過處理成爲文本文件,如下所示:
每張圖片都是32像素X32像素
首先,我們要把每個輸入的文本文件轉換KNN算法(前面的KNN算法實踐已經有了,這裏就不貼了)可以處理的格式,即一維數組的形式,定義以下函數:
def img2vector(filename):
"""
將32x32的圖像轉化爲1x1024的向量
:param filename:
:return:
"""
return_vect = zeros((1, 1024))
fr = open(filename)
for i in range(32): # 用for line in readlines()也可以
line_str = fr.readline() # 一行一行的讀
for j in range(32):
return_vect[0, 32*i+j] = int(line_str[j])
fr.close()
return return_vect
有了上面的函數,就可以設計循環,把訓練集,測試集,標籤都準備成KNN算法輸入的標準格式了
這裏標籤的提取需要從文件名稱中提取,比如文件名稱爲‘0_23.txt’,則表示這個圖像的正確分類爲數字‘0’
代碼如下:
from kNN import classify0
from numpy import *
from os import listdir
# 手寫數字識別系統測試代碼
def handwriting_class():
hw_labels = []
training_file_list = listdir('trainingDigits') # 獲取目錄下的文件名
m = len(training_file_list)
training_mat = zeros((m, 1024))
for i in range(m):
file_name_str = training_file_list[i]
file_str = file_name_str.split('.')[0]
class_num = int(file_str.split('_')[0])
hw_labels.append(class_num)
training_mat[i, :] = img2vector(r'trainingDigits/%s' % file_name_str)
test_file_list = listdir('testDigits')
error_count = 0.0
m_test = len(test_file_list)
for i in range(m_test):
file_name_str = test_file_list[i]
file_str = file_name_str.split('.')[0]
class_num = int(file_str.split('_')[0])
vector_under_test = img2vector(r'testDigits/%s' % file_name_str)
classifier_result = classify0(vector_under_test, training_mat, hw_labels, 3)
print 'the classifier came back with: %d, the real answer is: %d' % (classifier_result, class_num)
if classifier_result != class_num:
error_count += 1.0
print '\nthe total number of errors is : %d' % error_count
print '\nthe total error rate is : %f' % (error_count/float(m_test))
handwriting_class()
運行結果:
錯誤率達到1.8%,很不錯的結果(這是K選5的結果)
改變變量K的值,改變訓練樣本的數目,都會對結果有影響。
實際使用這個算法時,發現算法速度比較慢,因爲每個測試樣本都要與訓練樣本做距離計算,計算量非常大
K-近鄰算法必須保存全部數據集,如果訓練數據集很大,必須使用大量的存儲空間。另外,由於必須對數據集中每個數據計算距離,實際使用可能非常耗時。