基於k-近鄰分類器(KNN)的手寫識別系統, 這裏構造的系統只能識別數字0到9。python
數據集和項目源代碼git
圖像轉換爲文本格式github
將圖像轉換爲測試向量算法
訓練集:app
測試集測試
將圖像格式化處理爲一個向量。咱們將把一個32×32的二進制圖像矩陣轉換爲1×1024的向量, 以下圖所示, 優化
import numpy as np def img2vector(filename): """ # 將圖像數據轉換爲(1,1024)向量 :param filename: :return: (1,1024)向量 """ # 生成一個1*1024且值全爲0的向量; returnVect = np.zeros((1, 1024)) # 讀取要轉換的信息; file = open(filename) # 依次填充 # 讀取每一行數據; for i in range(32): lineStr = file.readline() # 讀取每一列數據; for j in range(32): returnVect[0, 32 * i + j] = int(lineStr[j]) return returnVect
對未知類別屬性的數據集中的每一個點依次執行如下操做, 與上一個案例代碼相同:
(1) 計算已知類別數據集中的點與當前點之間的距離;
(2) 按照距離遞增次序排序;
(3) 選取與當前點距離最小的k個點;
(4) 肯定前k個點所在類別的出現頻率;
(5) 返回前k個點出現頻率最高的類別做爲當前點的預測分類。spa
def classify(inX, dataSet, labels, k): """ :param inX: 要預測的數據 :param dataSet: 咱們要傳入的已知數據集 :param labels: 咱們要傳入的標籤 :param k: KNN裏的k, 也就是說咱們要選幾個近鄰 :return: 排序的結果 """ dataSetSize = dataSet.shape[0] # (6,2) 6 # tile會重複inX, 把他重複成(datasetsize, 1)型的矩陣 # print(inX) # (x1 - y1), (x2- y2) diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet # 平方 sqDiffMat = diffMat ** 2 # 相加, axis=1 行相加 sqDistance = sqDiffMat.sum(axis=1) # 開根號 distances = sqDistance ** 0.5 # print(distances) # 排序 輸出的是序列號index,並非值 sortedDistIndicies = distances.argsort() # print(sortedDistIndicies) classCount = {} for i in range(k): voteLabel = labels[sortedDistIndicies[i]] classCount[voteLabel] = classCount.get(voteLabel, 0) + 1 # print(classCount) sortedClassCount = sorted(classCount.items(), key=lambda d: float(d[1]), reverse=True) return sortedClassCount[0]
使用 k-近鄰算法識別手寫數字code
def handWritingClassTest(k): """ # 測試手寫數字識別錯誤率的代碼 :param k: :return: """ hwLabels = [] import os # 讀取全部的訓練集文件; trainingFileList = os.listdir('data/knn-digits/trainingDigits') # 獲取訓練集個數; m = len(trainingFileList) # 生成m行1024列全爲0的矩陣; trainingMat = np.zeros((m, 1024)) # 填充訓練集矩陣; for i in range(m): fileNameStr = trainingFileList[i] # fileNameStr: 0_0.txt fileStr = fileNameStr.split('.')[0] # fileStr: 0_0 classNumStr = int(fileStr.split('_')[0]) # (數字分類的結果)classNumStr: 0 # 填寫真實的數字結果; hwLabels.append(classNumStr) # 圖形的數據: (1,1024)向量 trainingMat[i, :] = img2vector("data/knn-digits/trainingDigits/%s" % fileNameStr) # 填充測試集矩陣; testFileList = os.listdir('data/knn-digits/testDigits') # 默認錯誤率爲0; errorCount = 0.0 # 測試集的總數; mTest = len(testFileList) # 填充測試集矩陣; for i in range(mTest): fileNameStr = testFileList[i] fileStr = fileNameStr.split('.')[0] classNumStr = int(fileStr.split('_')[0]) vectorTest = img2vector("data/knn-digits/testDigits/%s" % fileNameStr) # 判斷預測結果與真實結果是否一致? result = classify(vectorTest, trainingMat, hwLabels, k) if result != classNumStr: # 若是不一致,則統計出來, 計算錯誤率; errorCount += 1.0 print("[預測失誤]:分類結果是:%d, 真實結果是:%d" % (result, classNumStr)) print("錯誤總數:%d" % errorCount) print("錯誤率:%f" % (errorCount / mTest)) print("模型準確率:%f" %(1-errorCount / mTest)) return errorCount print(handWritingClassTest(2))
算法的執行效率並不高。排序
有沒有更好的方法?