在 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語言數據挖掘--特徵工程
數據預處理