knn實戰:如何對手寫數字進行識別?

在 Python 的 sklearn 工具包中有 KNN 算法。KNN 既可以做分類器,也可以做迴歸。

如果是做分類,你需要引用:

from sklearn.neighbors import KNeighborsClassifier

如果是做迴歸,你需要引用:

from sklearn.neighbors import KNeighborsRegressor

 

 

如何在 sklearn 中創建 KNN 分類器:

我們使用構造函數 KNeighborsClassifier(n_neighbors=5, weights=‘uniform’,algorithm=‘auto’, leaf_size=30),這裏有幾個比較主要的參數:

 

n_neighbors

即 KNN 中的 K 值,代表的是鄰居的數量。

k小過擬合,k大欠擬合;一般默認使用5

weights

weights=uniform

 

代表所有鄰居的權重相同

weights=distance

 

代表權重是距離的倒數,即與距離成反比
自定義函數 你可以自定義不同距離所對應的權重。

algorithm

 

algorithm=auto

 

根據數據的情況自動選擇適合的算法,默認情況選擇 auto

algorithm=kd_tree

 

也叫作 KD 樹,是多維空間的數據結構,方便對關鍵數據進行檢索;不過 KD 樹適用於維度少的情況,一般維數不超過 20,如果維數大於 20 之後,效率反而會下降;

algorithm=ball_tree

 

 

也叫作球樹,它和 KD 樹一樣都是多維空間的數據結果,不同於 KD 樹,球樹更適用於維度大的情況;

algorithm=brute

 

也叫作暴力搜索,它和 KD 樹不同的地方是在於採用的是線性掃描,,而不是通過構造樹結構進行快速檢索。

leaf_size

 

代表構造 KD 樹或球樹時的葉子數,默認是 30,調整 leaf_size 會影響到樹的構造和搜索速度。

創建完 KNN 分類器之後,我們就可以輸入訓練集對它進行訓練,這裏我們使用 fit() 函數,傳入訓練集中的樣本特徵矩陣和分類標識,會自動得到訓練好的 KNN 分類器。然後可以使用 predict() 函數來對結果進行預測,這裏傳入測試集的特徵矩陣可以得到測試集的預測分類結果。

如何用 KNN 對手寫數字進行識別分類

手寫數字數據集是個非常有名的用於圖像識別的數據集。數字識別的過程就是將這些圖片與分類結果 0-9 一一對應起來。

完整的手寫數字數據集 MNIST 裏面包括了 60000 個訓練樣本,以及 10000 個測試樣本。如果你學習深度學習的話,MNIST 基本上是你接觸的第一個數據集。

今天我們用 sklearn 自帶的手寫數字數據集做 KNN 分類,它只包括了 1797 幅數字圖像,每幅圖像大小是 8*8 像素。

訓練分三個階段:

1、加載數據集;本地導入,線上調取,自帶數據集;在這裏,我們使用自帶數據集;

2、準備階段:可視化數據描述:樣本量多少,圖像長啥樣,輸入輸出特徵;數據處理:缺失值處理,異常值處理、特徵工程構造;

3、分類階段:通過訓練可以得到分類器,然後用測試集進行準確率的計算。

 

#加載庫
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_digits
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import MultinomialNB
from sklearn.tree import DecisionTreeClassifier
import matplotlib.pyplot as plt


# 加載數據
digits = load_digits()
data = digits.data
# 數據探索
print(data.shape)
# 查看第一幅圖像
print(digits.images[0])
# 第一幅圖像代表的數字含義
print(digits.target[0])
# 將第一幅圖像顯示出來
plt.gray()
plt.imshow(digits.images[0])
plt.show()

運行結果:

我們對原始數據集中的第一幅進行數據可視化,可以看到圖像是個 8*8 的像素矩陣,上面這幅圖像是一個“0”,從訓練集的分類標註中我們也可以看到分類標註爲“0”。

sklearn 自帶的手寫數字數據集一共包括了 1797 個樣本,每幅圖像都是 8*8 像素的矩陣。因爲並沒有專門的測試集,所以我們需要對數據集做劃分,劃分成訓練集和測試集。

因爲 KNN 算法和距離定義相關,我們需要對數據進行規範化處理,採用 Z-Score 規範化:

# 分割數據,將 25% 的數據作爲測試集,其餘作爲訓練集(你也可以指定其他比例的數據作爲訓練集)
train_x, test_x, train_y, test_y = train_test_split(data, digits.target, test_size=0.25, random_state=33)
# 採用 Z-Score 規範化
ss = preprocessing.StandardScaler()
train_ss_x = ss.fit_transform(train_x)
test_ss_x = ss.transform(test_x)

75%數據作爲訓練集;train_x作爲訓練集的輸入特徵值矩陣,train_y作爲訓練集的輸出特徵值;

對訓練集與測試集中的輸入特徵值進行z評分歸一化;(記住一定要對測試集輸入特徵進行同樣的處理!以後談論的變換默認都是對輸入特徵進行!)

fit_transform是fit和transform兩個函數都執行一次。所以ss是進行了fit擬合的。只有在fit擬合之後,才能進行transform
在進行test的時候,我們已經在train的時候fit過了,所以直接transform即可。
另外,如果我們沒有fit,直接進行transform會報錯,因爲需要先fit擬合,纔可以進行transform。

 

然後我們構造一個 KNN 分類器 knn,把訓練集的數據傳入構造好的 knn,並通過測試集進行結果預測,與測試集的結果進行對比,得到 KNN 分類器準確率,

# 創建 KNN 分類器
knn = KNeighborsClassifier() 
knn.fit(train_ss_x, train_y) 
predict_y = knn.predict(test_ss_x) 
print("KNN 準確率: %.4lf" % accuracy_score(predict_y, test_y))

knn.fit(訓練集輸入特徵,訓練集輸出特徵)

knn.predict(測試集輸入特徵)=模型輸出值

accquary_score(knn.predict(測試集輸入特徵),測試集輸出特徵)

KNN 準確率: 0.9756

我們選用之前學過的幾個模型,進行預測:

# 創建 SVM 分類器
svm = SVC()
svm.fit(train_ss_x, train_y)
predict_y=svm.predict(test_ss_x)
print('SVM 準確率: %0.4lf' % accuracy_score(predict_y, test_y))
# 採用 Min-Max 規範化
mm = preprocessing.MinMaxScaler()
train_mm_x = mm.fit_transform(train_x)
test_mm_x = mm.transform(test_x)
# 創建 Naive Bayes 分類器
mnb = MultinomialNB()
mnb.fit(train_mm_x, train_y) 
predict_y = mnb.predict(test_mm_x) 
print(" 多項式樸素貝葉斯準確率: %.4lf" % accuracy_score(predict_y, test_y))
# 創建 CART 決策樹分類器
dtc = DecisionTreeClassifier()
dtc.fit(train_mm_x, train_y) 
predict_y = dtc.predict(test_mm_x) 
print("CART 決策樹準確率: %.4lf" % accuracy_score(predict_y, test_y))

運行結果:

SVM 準確率: 0.9867
 多項式樸素貝葉斯準確率: 0.8844
CART 決策樹準確率: 0.8356

這裏需要注意的是,我們在做多項式樸素貝葉斯分類的時候,傳入的數據不能有負數。

因爲 Z-Score 會將數值規範化爲一個標準的正態分佈,即均值爲 0,方差爲 1,數值會包含負數。因此我們需要採用 Min-Max 規範化,將數據規範化到 [0,1] 範圍內。

數據預處理:無量綱化處理(線性:均值化與標準化;非線性),降維

當輸入特徵接近正態分佈,使用Z評分歸一化;

當輸入特徵呈現高度偏斜,而我們模型對輸入特徵的要求是正態分佈時,選用Box-Cox變換;

Z評分歸一化的特點:變換結果均值爲0,方差爲1;變換時對數值進行平移和縮放的同時,保留了密度圖的總體形態

Box-Cox變換:變換時對數值進行平移和縮放的同時,改變了整體形態,產生了比原始圖偏斜更少的密度圖。

降維:特徵縮減,比如PCA-主成分分析

特徵工程:根據原有的特徵,設計新的特徵(實際應用需要反覆驗證)

倘若同樣的數據集,改變k值,會得出如下結論:


knn默認k值爲5 準確率:0.9756
knn的k值爲200的準確率:0.8489
SVM分類準確率:0.9867
高斯樸素貝葉斯準確率:0.8111
多項式樸素貝葉斯分類器準確率:0.8844
CART決策樹準確率:0.8400

K值的選取如果過大,正確率降低。 
算法效率排行 SVM > KNN(k值在合適範圍內) >多項式樸素貝葉斯 > CART > 高斯樸素貝葉斯

分別用 KNN、SVM、樸素貝葉斯和決策樹做分類器,並統計了四個分類器的準確率。在數據量不大的情況下,使用 sklearn 還是方便的。

如果數據量很大,比如 MNIST 數據集中的 6 萬個訓練數據和 1 萬個測試數據,那麼採用深度學習 +GPU 運算的方式會更適合。

因爲深度學習的特點就是需要大量並行的重複計算,GPU 最擅長的就是做大量的並行計算。

 

總結:

1、各模型對輸入特徵是有分佈要求的;比如多項式樸素貝葉斯分類要求數據非負;最小二乘法模型要求數據是正態分佈,滿足四大假設;神經網絡則對數據分佈無要求。

2、特徵變換是針對輸入特徵的;特徵變化是數據處理的子集,決定模型的上限,而模型的好壞只是逼近這個上限

3、skearn適合數據量較小的訓練,若是數據量過大,可以採用深度學習框架+GPU運算。實際運用中,可以使用集成學習(機器學習+深度學習框架)完成。

 

參考:

數據分析實戰45講

用商業案例學R語言數據挖掘--特徵工程

數據預處理

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章