鄰近算法又叫作K臨近算法或者KNN(K-NearestNeighbor),是機器學習中很是重要的一個算法,but它簡單得一塌糊塗,其核心思想就是樣本的類別由距離其最近的K個鄰居投票來決定。如今假設咱們已經有一個已經標記好的數據集,也就是說咱們已經知道了數據集中每一個樣本所屬於的類別。這個時候咱們擁有一個未標記的數據樣本,咱們的任務是預測出來這個數據樣本所屬於的類別。顯然鄰近算法是屬於監督學習(Supervised Learning)的一種,它的原理是計算這個待標記的數據樣本和數據集中每一個樣本的距離,取其距離最近的k個樣本,那麼待標記的數據樣本所屬於的類別,就由這距離最近的k個樣本投票產生。在這個過程當中,有一個動做是標記數據集,這一點在企業中通常是有專門人來負責標記數據的。python
爲了更加直觀的瞭解鄰近算法,請看下面的例子。有兩種水果長得很是像,一個是菠蘿,另外一個是鳳梨,很長一段時間我都覺得它們是同一種水果。
菠蘿與鳳梨的核心區別是菠蘿的葉子有刺,而鳳梨的葉子沒有刺。菠蘿的凹槽處的顏色是黃色,而鳳梨的凹槽處的顏色是綠色。首先咱們把這兩種水果抽取出其中的兩個特色(凹槽處的顏色、葉子上是否有刺)後,放入一個直角座標系中吧。以下圖:
咱們按照兩種水果的特色,已經把它們放在了直角座標系中,按照咱們所說的算法原理,此時有一個未標記的樣本,咱們來預測這個樣本究竟是屬於哪一種水果。以下圖,這個時候來了一個未標記的樣本,也就是不知道是什麼類別的水果。
在原理中,咱們說過,由其最近的K個鄰居來投票決定,這個未標記的水果究竟是什麼水果,那麼這個時候,咱們把K的值設置爲3,以下圖:
從圖片中,咱們看到,在K的值爲3的時候,與未標記樣本最近的3個鄰居其中2個爲菠蘿,而1個爲鳳梨,那麼這個時候咱們預測這個未知的水果爲菠蘿。算法
咱們先來看一下如何用僞代碼來實現這個算法,這樣咱們在後邊的學習中才能更好的寫出來這段代碼。數組
# 從sklearn庫中的數據集對象裏導入樣本生成器中的make_blobs方法幫助咱們生成數據 from sklearn.datasets.samples_generator import make_blobs # 聲明三個直角座標系中的位置 centers = [[-2, 2], [2, 2], [0, 4]] # 生成數據,其中n_samples是生成數據的個數,centers是中心點,cluster_std是標準差,指明離散程度 x, y = make_blobs(n_samples=60, centers=centers, cluster_std=0.6) # x是生成的數據,y是不一樣的數據對應所屬的的類別0,1,2 print(x, y)
import matplotlib.pyplot as plt import numpy as np plt.figure(figsize=(16, 10), dpi=144) c = np.array(centers) # x軸,y軸,c顏色 s指定點的大小 plt.scatter(x[:, 0], x[:, 1], c=y, s=100, cmap="cool") # 畫出中心點 plt.scatter(c[:, 0], c[:, 1], s=100, marker="^", c="orange") plt.show()
圖形顯示以下圖所示:
圖形中顯示的三個三角形的點就是中心點,圍繞在它們周圍的圓點就是咱們隨機生成的數據的點。app
# 從sklearn庫中導入K鄰居分類器:KNeighbosrClassifier from sklearn.neighbors import KNeighborsClassifier # 設定K值 k = 5 # 聲明k臨近分類器對象 clf = KNeighborsClassifier(n_neighbors=k) # 訓練模型 clf.fit(x, y)
# 定義樣本數據 x_sample = [[0, 2]] # 使用模型進預測 neighbors = clf.kneighbors(x_sample, return_distance=False) print(neighbors) # 輸出值:[[23 39 21 47 29]]
x_sample變量是咱們要進行預測的樣本,而後使用clf.kneighbors方法就能夠對這個樣本進行預測了。關於clf.kneighbors的參數return_distance,它決定了是否返回計算後的距離,默認是True,這裏我把它修改爲了False,你若是想要看一下值爲True是什麼樣子,能夠本身手動修改成True。到這裏你能夠有一點懵,這怎麼就預測完成了呢?輸出值表示的是什麼意思呢?
輸出值表示的是5個通過計算以後的位於x訓練集中的索引值,它們並非直接的位置。機器學習
爲了可以使預測的結果更加直觀,咱們還須要用代碼把他們畫出來。學習
# 把帶預測的樣本以及和其最近的5個點標記出來 plt.figure(figsize=(8, 5), dpi=144) # dpi是像素值 plt.scatter(x[:, 0], x[:, 1], c=y, s=100, cmap='cool') # 樣本數據 plt.scatter(c[:, 0], c[:, 1], s=100, marker='^', c='k') # 中心點 # 帶預測的點 plt.scatter(x_sample[0][0], x_sample[0][1], marker='x', s=100, cmap='cool') # 把預測點與距離最近的5個樣本連成線 for i in neighbors[0]: plt.plot([x[i][0], x_sample[0][0]], [x[i][1], x_sample[0][1]], 'k--', linewidth=0.6) plt.show()
顯示結果以下圖所示:測試
在這一小節咱們將經過一個花卉識別項目的練習來鞏固咱們所講的KNN算法,訓練數據集是很是著名的鳶尾花數據集,涉及到的花的種類一共分爲三種:
第一種花是山鳶尾,長下面這個樣子
第二種花是錦葵,也叫虹膜錦葵
第三種花是變色鳶尾ui
咱們能夠經過sklearn庫的自帶數據集直接引入鳶尾花的數據集,在這個數據集中,咱們能夠經過花萼長度,花萼寬度,花瓣長度和花瓣寬度四個屬性來預測未標記的鳶尾花屬於哪一個類別。rest
# 1 導入鳶尾花數據集 from sklearn.datasets import load_iris # 2 聲明一個鳶尾花的類對象 iris = load_iris() # 3 獲取鳶尾花的數據 iris_data = iris.data # 4 獲取數據對應的種類 iris_target = iris.target print(iris_data) print(iris_target)
查看數據後你會看到iris_data變量裏每個元素一共有4個值,這四個值就是分別對應花萼長度、花萼寬度、花瓣長度、花瓣寬度4個屬性,iris_target變量對應的就是每個花所屬的類別。一共對應的是3個類別,0的意思是山鳶尾,1是虹膜錦葵,2是變色鳶尾。code
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split # 分割訓練集和測試集 from sklearn.neighbors import KNeighborsClassifier iris = load_iris() iris_data = iris.data iris_target = iris.target # 把數據分爲訓練集和測試集,x表示特徵值,y表示目標值,test_size=0.25表示將25%的數據用做測試集 x_train, x_test, y_train, y_test = train_test_split(iris_data, iris_target, test_size=0.25) # 建立KNN算法實例,n_neighbors參數默認爲5,後續能夠經過網格搜索獲取最優參數 knn = KNeighborsClassifier(n_neighbors=5) # 訓練測試集數據 knn.fit(x_train, y_train) # 獲取預測結果 y_predict = knn.predict(x_test) # 展現預測結果 labels = ['山鳶尾', '虹膜錦葵', '變色鳶尾'] for i in range(len(y_predict)): print('第%d次測試:預測值:%s 真實值:%s' %((i + 1), labels[y_predict[i]], labels[y_test[i]])) print('準確率:', knn.score(x_test, y_test))
k值選取的思路是咱們先來選擇一個k值的範圍,把這個範圍中全部的偏差值都獲取到,而後咱們再來選擇偏差最小的值做爲k值。
from sklearn.datasets import load_iris from sklearn.model_selection import cross_val_score from sklearn.neighbors import KNeighborsClassifier import matplotlib.pyplot as plt # 中文顯示 plt.rcParams["font.family"] = 'Arial Unicode MS' # 導入數據集 iris = load_iris() x = iris.data y = iris.target # 限制k的取值範圍 k_range = range(1, 31) # 記錄每當k值變換一次,它的錯誤值是多少 k_error = [] for k in k_range: knn = KNeighborsClassifier(n_neighbors=k) # cv參數決定數據集劃分比例,這裏按照5:1劃分訓練集和測試集 scores = cross_val_score(knn, x, y, cv=6) print(scores) k_error.append(1 / scores.mean()) # 把結果畫成圖,直觀看出k取什麼值偏差最小,x軸爲k值,y軸爲偏差值 plt.plot(k_range, k_error) plt.xlabel('k值') plt.ylabel('偏差值') plt.show()
圖形顯示結果以下圖所示:
根據這個圖形咱們就能夠看得出來,k值大概是在12這個位置時,偏差是最小的。這時當咱們把12從新放入到以前的代碼中,可能你會發現他的準確率並無提高甚至還有可能降低了,實際上是由於數據量比較小的緣故,並不影響咱們解決問題的方式。
經過前面的練習,相信你已經基本掌握了KNeighborsClassifier的使用方法了,最後,在這裏咱們會對這個方法的參數進行更細緻的說明和講解。
# 查看KNeighborsClassifier源代碼 NeighborsClassifier( n_neighbors=5, weights="uniform」, algorithm=」auto「, leaf_size=30, p=2, metric="minkowski", metric_params=None, n_jobs=None, **kwargs, )
一樣的,最後咱們會有一個小的練習,請點擊下方連接下載:
chapter9-1.zip