【機器學習實戰】利用KNN和其他分類器對手寫數字進行識別

一、在sklearn中創建KNN分類器

KNeighborsClassifier(n_neighbors=5, weights='uniform', algorithm='auto', leaf_size=30)

看一下這幾個參數

1. n_neighbors:即 KNN 中的 K 值,代表的是鄰居的數量。如果K 值比較小,會造成過擬合;如果 K 值比較大,無法將未知物體分類出來。一般我們使用默認值 5。

2. weights:是用來確定鄰居的權重,有兩種方式:

  1. weights=‘uniform’,代表所有鄰居的權重相同;
  2. weights=‘distance’,代表權重是距離的倒數,即與距離成反比。

3. algorithm:用來規定計算鄰居的方法,它有四種方式:

  1. algorithm=‘auto’,根據數據的情況自動選擇適合的算法,默認情況選擇 auto;
  2. algorithm=‘kd_tree’,也叫作 KD 樹,是多維空間的數據結構,方便對關鍵數據進行檢索,不過 KD 樹適用於維度少的情況,一般維數不超過 20,如果維數大於 20 之後,效率反而會下降;
  3. algorithm=‘ball_tree’,也叫作球樹,它和 KD 樹一樣都是多維空間的數據結果,不同於 KD 樹,球樹更適用於維度大的情況;
  4. algorithm=‘brute’,也叫作暴力搜索,它和 KD 樹不同的地方是在於採用的是線性掃描,而不是通過構造樹結構進行快速檢索。當訓練集大的時候,效率很低。

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

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

二、工作流程

我們用 sklearn 自帶的手寫數字數據集做 KNN 分類,你可以把這個數據集理解成一個簡版的 MNIST 數據集,它只包括了 1797 幅數字圖像,每幅圖像大小是 8*8 像素。

先劃分一下流程:

整個訓練過程基本上都會包括三個階段:

  1. 數據加載:直接從 sklearn 中加載自帶的手寫數字數據集;
  2. 準備階段:在這個階段中,我們需要對數據集有個初步的瞭解,比如樣本的個數、圖像長什麼樣、識別結果是怎樣的。你可以通過可視化的方式來查看圖像的呈現。通過數據規範化可以讓數據都在同一個數量級的維度。另外,因爲訓練集是圖像,每幅圖像是個 8*8 的矩陣,我們不需要對它進行特徵選擇,將全部的圖像數據作爲特徵值矩陣即可
  3. 分類階段:通過訓練可以得到分類器,然後用測試集進行準確率的計算。

三、實戰環節

1.導包

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from sklearn.datasets import load_digits
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.model_selection import train_test_split

from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import MultinomialNB
from sklearn.ensemble import AdaBoostClassifier

from sklearn.metrics import accuracy_score

2.加載數據並探索

# 加載數據
digits = load_digits()
data = digits.data

# 數據探索
print(data.shape)
# 查看第一幅圖像
print(digits.images[0])
# 第一幅圖像代表的數字含義
print(digits.target[0])

# 將第一幅圖像顯示出來
plt.imshow(digits.images[0])
plt.show()

輸出:

(1797, 64)
[[ 0.  0.  5. 13.  9.  1.  0.  0.]
 [ 0.  0. 13. 15. 10. 15.  5.  0.]
 [ 0.  3. 15.  2.  0. 11.  8.  0.]
 [ 0.  4. 12.  0.  0.  8.  8.  0.]
 [ 0.  5.  8.  0.  0.  9.  8.  0.]
 [ 0.  4. 11.  0.  1. 12.  7.  0.]
 [ 0.  2. 14.  5. 10. 12.  0.  0.]
 [ 0.  0.  6. 13. 10.  0.  0.  0.]]
0

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

3.分割數據集並規範化

sklearn 自帶的手寫數字數據集一共包括了 1797 個樣本,每幅圖像都是 8*8 像素的矩陣。因爲並沒有專門的測試集,所以我們需要對數據集做劃分,劃分成訓練集和測試集。因爲 KNN 算法和距離定義相關,我們需要對數據進行規範化處理,採用 Z-Score 規範化,代碼如下:

# 數據及目標
data1 = digits.data
target1 = digits.target

# 分割數據,將25%的數據作爲測試集,其餘作爲訓練集(你也可以指定其他比例的數據作爲訓練集)
train_x, test_x, train_y, test_y = train_test_split(data1, target1, test_size=0.25)

# 採用z-score規範化
ss = StandardScaler()
train_ss_scaled = ss.fit_transform(train_x)
test_ss_scaled = ss.transform(test_x)

# 採用0-1歸一化
mm = MinMaxScaler()
train_mm_scaled = mm.fit_transform(train_x)
test_mm_scaled = mm.transform(test_x)

這裏之所以用了0-1歸一化,是因爲多項式樸素貝葉斯分類這個模型,傳入的數據不能有負數。因爲 Z-Score 會將數值規範化爲一個標準的正態分佈,即均值爲 0,方差爲 1,數值會包含負數。因此我們需要採用 Min-Max 規範化,將數據規範化到[0,1]範圍內。

4.建立模型,並進行比較

這裏構造五個分類器, 分別是K近鄰,SVM, 多項式樸素貝葉斯, 決策樹模型, AdaBoost模型。並分別看看他們的效果。

models = {}
models['knn'] = KNeighborsClassifier()
models['svm'] = SVC()
models['bayes'] = MultinomialNB()
models['tree'] = DecisionTreeClassifier()
models['ada'] = AdaBoostClassifier(base_estimator=models['tree'], learning_rate=0.1)

for model_key in models.keys():
    if model_key == 'knn' or model_key == 'svm' or model_key == 'ada':
        model = models[model_key]
        model.fit(train_ss_scaled, train_y)
        predict = model.predict(test_ss_scaled)
        print(model_key, "準確率:", accuracy_score(test_y, predict))
    else:
        model = models[model_key]
        model.fit(train_mm_scaled, train_y)
        predict = model.predict(test_mm_scaled)
        print(model_key, "準確率: ", accuracy_score(test_y, predict))

輸出:

knn 準確率: 0.9777777777777777
svm 準確率: 0.9866666666666667
bayes 準確率:  0.8888888888888888
tree 準確率:  0.8444444444444444
ada 準確率: 0.8355555555555556

你能看出來 KNN 的準確率還是不錯的,和 SVM 不相上下。並且竟然比AdaBoost效果都要好,而讓我納悶的是決策樹和AdaBoost怎麼效果這麼差,不可思議。後來我發現了,原來是樣本數量的問題,我們最多數據集才1000多照片,數量太少了,AdaBoost的作用發揮不出來,所以我對數據進行擴增,複製了三遍原來的數據:

data2 = np.vstack((data1, data1, data1))
target2 = np.hstack((target1, target1, target1))

變成了5000多張數據,然後再進行測試,結果就是AdaBoost和tree的效果提升了,甚至可以和SVM效果媲美了。

輸出:

knn 準確率: 0.9821958456973294
svm 準確率: 0.9970326409495549
bayes 準確率:  0.9013353115727003
tree 準確率:  0.9955489614243324
ada 準確率: 0.9933234421364985

 

 

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