手寫數字是32x32的黑白影象。為了能使用knn分類器,我們需要把32x32的二進位制影象轉換為1x1024
from numpy import *#匯入科學計算包numpy和運算子模組operator
import
operator
from os import listdir
defimg2vector(filename):
"""將影象資料轉換為向量
:param filename: 檔案 因為我們的輸入資料的格式是 32 * 32的
:return: 一維矩陣
該函式將影象轉換為向量:該函式建立 1 * 1024 的numpy陣列,然後開啟給定的檔案,
迴圈讀出檔案的前32行,並將每行的頭32個字元值儲存在numpy陣列中,最後返回陣列。
"""returnvect = zeros((1, 1024))
fr =open(filename)
for i in range(32):
linestr =fr.readline()
for j in range(32):
returnvect[0, 32 * i + j] =int(linestr[j])
return returnvect
測試:
testvector = img2vector('')testvector[0, 0:31]
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1.,1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
defclassify0(inx, dataset, labels, k):
"""inx: 用於分類的輸入向量
dataset: 輸入的訓練樣本集
labels: 標籤向量
k: 選擇最近鄰居的數目
注意:labels元素數目和dataset行數相同;程式使用歐式距離公式.
"""#
求出資料集的行數
datasetsize =dataset.shape[0]
#tile生成和訓練樣本對應的矩陣,並與訓練樣本求差
"""tile: 列: 3表示複製的行數, 行:1/2 表示對inx的重複的次數
例:in : inx = [1, 2, 3]
tile(inx, (3, 1))
out: array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
"""#
用inx(輸入向量)生成和dataset型別一樣的矩陣,在減去dataset
diffmat = tile(inx, (datasetsize, 1)) -dataset
#取平方
sqdiffmat = diffmat ** 2
#將矩陣的每一行相加
sqdistances = sqdiffmat.sum(axis=1)
#開方distances = sqdistances ** 0.5
#根據距離排序從小到大的排序,返回對應的索引位置
#argsort() 是將x中的元素從小到大排列,提取其對應的index(索引),然後輸出到y。
"""in : y = argsort([3, 0, 2, -1, 4, 5])
print(y[0])
print(y[5])
out : 3
5由於最小的數是-1,它的序號是3,因此y[0] = 3, 最大的數是5,它的序號是5,因此y[5] = 5
"""sorteddistindicies =distances.argsort()
#2. 選擇距離最小的k個點
classcount ={}
for i in
range(k):
voteilabel =labels[sorteddistindicies[i]]
classcount[voteilabel] = classcount.get(voteilabel, 0) + 1sortedclasscount = sorted(classcount.items(), key=operator.itemgetter(1), reverse=true)
return sortedclasscount[0][0]
defhandwritingclasstest():
#1. 匯入資料
hwlabels =
trainingfilelist = listdir('
') #
load the training set
m =len(trainingfilelist)
trainingmat = zeros((m, 1024))
#hwlabels儲存0~9對應的index位置, trainingmat存放的每個位置對應的向量
for i in
range(m):
filenamestr =trainingfilelist[i]
filestr = filenamestr.split('
.')[0] #
take off .txt
classnumstr = int(filestr.split('_'
)[0])
#將 32*32的矩陣->1*1024的矩陣
trainingmat[i, :] = img2vector('
' %filenamestr)
#2. 匯入測試資料
testfilelist = listdir('
') #
iterate through the test set
errorcount = 0.0mtest =len(testfilelist)
for i in
range(mtest):
filenamestr =testfilelist[i]
filestr = filenamestr.split('
.')[0] #
take off .txt
classnumstr = int(filestr.split('_'
)[0])
vectorundertest = img2vector('
' %filenamestr)
classifierresult = classify0(vectorundertest, trainingmat, hwlabels, 3)
print("
the classifier came back with: %d, the real answer is: %d
" %(classifierresult, classnumstr))
if (classifierresult != classnumstr): errorcount += 1.0
print("
\nthe total number of errors is: %d
" %errorcount)
print("
\nthe total error rate is: %f
" % (errorcount / float(mtest)))
handwritingclasstest()
the classifier came back with: 0, the real answer is: 0the classifier came back with: 0, the real answer is: 0
...
the classifier came back with: 9, the real answer is: 9k-近鄰演算法的特點:the classifier came back with: 9, the real answer is: 9
the total number of errors is: 10
the total error rate is: 0.010571
k-近鄰演算法識別手寫數字,錯誤率在1.1%.改變k的值、修改函式 handwritingclasstest 隨機選取訓練樣本、改變訓練樣本的數目,都會對k-近鄰演算法的錯誤率產生影響。
實際上,這個演算法的執行效率並不高。因為每個演算法需要為每個測試向量做2000次距離計算,每個距離計算包括了1024個維度浮點運算,總計執行900次。
而k決策樹就是k-近鄰的優化版。
1. 是分類資料最簡單最有效的演算法
2. 必須儲存全部資料集,會使用大量儲存空間
3. 必須對每個資料計算距離值,非常耗時
手寫識別系統(k 近鄰演算法)
k 近鄰演算法 knn 是機器學習中乙個相對比較簡單的演算法。該演算法在訓練集中資料和標籤已知的情況下,輸入測試資料,將測試資料的特徵與訓練集中對應的特徵進行相互比較 比如通過歐氏距離 找到訓練集中與之最為相似的前k個資料,則該測試資料對應的類別就是k個資料中出現次數最多的那個分類,其演算法的描述為...
使用k 近鄰演算法完成手寫識別系統
2 準備資料 編寫函式classify0,將影象格式轉換為分類器使用的list格式 3 分析資料 在python命令提示符中檢查資料,確保它符合要求 4 訓練演算法 此步驟不適合用於k 近鄰演算法 5 測試演算法 編寫函式使用提供的部分資料集作為測試樣本,測試樣本與非測試樣本的 區別在於測試眼 恩是...
機器學習 使用k 近鄰演算法實現手寫識別系統
knn概述 k 近鄰演算法就是通過計算不同特徵值之間的距離來進行分類的演算法。假設我們現在有乙個樣本集,每個樣本都有幾個特徵用來描述這個樣本,以及乙個它所屬分類的標籤。當我們拿到乙個沒有標籤的樣本時,該如何判斷它屬於哪個樣本呢?我們將這個樣本與每乙個已知標籤的樣本做比較,找到相似度最大的k個樣本,記...