一、序
機器學習實戰_K近鄰算法 ——手寫數字預測 調用的是自己編寫的分類器classify0,主要是爲了學習理論原理;在實際是項目中通常調用工具包的api接口,比如sklearn,這也體現了python的一個便利性,不用總是自己造輪子。雖然python提供了很多機器學習的工具包,但是也是在我們瞭解和熟悉算法的基本實現原理。
二、sklearn中KNeighborsClassifier的介紹
class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, weights=‘uniform’, algorithm=‘auto’, leaf_size=30, p=2, metric=‘minkowski’, metric_params=None, n_jobs=None, **kwargs)
官方api文檔:KNeighborsClassifier
1、KNeighborsClassifier的參數(官方文譯):
n_neighbors: int, 可選參數(默認爲 5)
用於kneighbors查詢的默認鄰居的數量
weights(權重): str or callable(自定義類型), 可選參數(默認爲 ‘uniform’)
用於預測的權重函數。可選參數如下:
- ‘uniform’ : 統一的權重. 在每一個鄰居區域裏的點的權重都是一樣的。
- ‘distance’ : 權重點等於他們距離的倒數。使用此函數,更近的鄰居對於所預測的點的影響更大。
- [callable] : 一個用戶自定義的方法,此方法接收一個距離的數組,然後返回一個相同形狀並且包含權重的數組。
algorithm(算法): {‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, 可選參數(默認爲 ‘auto’)
計算最近鄰居用的算法:
注意 : 如果傳入fit方法的輸入是稀疏的,將會重載參數設置,直接使用暴力搜索。
leaf_size(葉子數量): int, 可選參數(默認爲 30)
傳入BallTree或者KDTree算法的葉子數量。此參數會影響構建、查詢BallTree或者KDTree的速度,以及存儲BallTree或者KDTree所需要的內存大小。 此可選參數根據是否是問題所需選擇性使用。
p: integer, 可選參數(默認爲 2)
用於Minkowski metric(閔可夫斯基空間)的超參數。p = 1, 相當於使用曼哈頓距離 (l1),p = 2, 相當於使用歐幾里得距離(l2) 對於任何 p ,使用的是閔可夫斯基空間(l_p)
metric(矩陣): string or callable, 默認爲 ‘minkowski’
用於樹的距離矩陣。默認爲閔可夫斯基空間,如果和p=2一塊使用相當於使用標準歐幾里得矩陣. 所有可用的矩陣列表請查詢 DistanceMetric 的文檔。
metric_params(矩陣參數): dict, 可選參數(默認爲 None)
給矩陣方法使用的其他的關鍵詞參數。
n_jobs: int, 可選參數(默認爲 1)
用於搜索鄰居的,可並行運行的任務數量。如果爲-1, 任務數量設置爲CPU核的數量。不會影響fit方法。
2、 KNeighborsClassifier的方法(官方文譯)
方法名 | 含義 |
---|---|
fit(X, y) | 使用X作爲訓練數據,y作爲目標值(類似於標籤)來擬合模型。 |
get_params([deep]) | 獲取估值器的參數。 |
kneighbors([X, n_neighbors, return_distance]) | 查找一個或幾個點的K個鄰居。 |
kneighbors_graph([X, n_neighbors, mode]) | 計算在X數組中每個點的k鄰居的(權重)圖。 |
predict(X) | 給提供的數據預測對應的標籤。 |
predict_proba(X) | 返回測試數據X的概率估值。 |
score(X, y[, sample_weight]) | 返回給定測試數據和標籤的平均準確值。 |
set_params(**params) | 設置估值器的參數。 |
三、手寫數字預測(sklearn api)
1、修改內容
- 1)、增加的代碼
# 構造kNN分類器
knn = KNeighborsClassifier(n_neighbors=3, algorithm='auto')
# 擬合模型,trainingMat爲測試矩陣,hwLabels爲對應標籤
knn.fit(trainingMat, hwLabels)
- 2)、替換的內容
# 獲得預測結果
classifierResult = knn.predict(vectorUnderTest) # 替換 classifierResult = classify0(vectorUnderTest)
2、代碼
import numpy as np
from os import listdir
from sklearn.neighbors import KNeighborsClassifier
def img2vector(filename):
"""
函數說明:將32*32的二進制圖像轉換爲1*1024向量
Parameters:
filename - 文件名
Returns:
returnVect - 返回二進制圖像的1*1024向量
"""
# 創建1*1024零向量
returnVect = np.zeros((1, 1024))
with open(filename) as fr:
# 按行讀取
for i in range(32):
# 讀取一行數據
lineStr = fr.readline()
# 每一行的前32個數據依次存儲到returnVect中
for j in range(32):
returnVect[0, 32 * i + j] = int(lineStr[j])
# 返回轉換後的1*1024向量
return returnVect
def handwritingClassTest():
"""
函數說明:手寫數字分類測試
Parameters:
None
Returns:
None
"""
# 測試集的Labels
hwLabels = []
# 返回trainingDigits目錄下的文件名
trainingFileList = listdir('trainingDigits')
# 返回文件夾下文件的個數
m = len(trainingFileList)
# 初始化訓練的Mat矩陣(全零陣),測試集
trainingMat = np.zeros((m, 1024))
# 從文件名中解析出訓練集的類別
for i in range(m):
# 獲得文件的名字
fileNameStr = trainingFileList[i]
# 獲得分類的數字
classNumStr = int(fileNameStr.split('_')[0])
# 將獲得的類別添加到hwLabels中
hwLabels.append(classNumStr)
# 將每一個文件的1x1024數據存儲到trainingMat矩陣中
trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
# 構造kNN分類器
knn = KNeighborsClassifier(n_neighbors=3, algorithm='auto')
# 擬合模型,trainingMat爲測試矩陣,hwLabels爲對應標籤
knn.fit(trainingMat, hwLabels)
# 返回testDigits目錄下的文件列表
testFileList = listdir('testDigits')
# 錯誤檢測計數
errorCount = 0.0
# 測試數據的數量
mTest = len(testFileList)
# 從文件中解析出測試集的類別並進行分類測試
for i in range(mTest):
# 獲得文件名字
fileNameStr = testFileList[i]
# 獲得分類的數字
classNumStr = int(fileNameStr.split('_')[0])
vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
# 獲得預測結果
classifierResult = knn.predict(vectorUnderTest)
print("分類返回結果爲%d\t真實結果爲%d" % (classifierResult, classNumStr))
if classifierResult != classNumStr:
errorCount += 1.0
print("總共錯了%d個數據\n錯誤率爲%f%%" % (errorCount, errorCount / mTest * 100))
if __name__ == '__main__':
handwritingClassTest()