算法原理
模型
k近鄰算法是一個多分類的機器學習算法。它的實現過程很容易理解,簡單來說,就是通過計算待分類樣本與所有訓練樣本的“距離”,然後取出離待分類樣本最近的k個訓練樣本,最後將這k個訓練樣本中類別最多的一種作爲該待分類樣本的預測類別。
圖解
如圖所示,假設有若干個訓練樣本,不同顏色代表不同的類別。
現在放入一個待分類樣本。
定義k值(假設爲3),定義距離(假設是歐式距離),計算該待分類樣本與所有訓練樣本的距離。
選取距離最小的k個訓練樣本。
將這k個訓練樣本中出現最多的那個類別作爲該待分類樣本的預測類別。此時圖上待分類樣本的預測類別是紅色。
具體步驟
1、已知訓練集,訓練集的每個樣本包含特徵和類別,設定k值,定義樣本間的距離計算公式(這裏的距離需要自己定義,可以是曼哈頓距離,歐式距離等等)。
2、對於每個特徵爲的待分類樣本,計算其與所有訓練樣本的距離
3、取出距離最近的k個訓練樣本
將中出現次數最多的類別作爲待分類樣本的預測類別。
4、重複執行2、3步直至所有待分類樣本預測完畢。
程序實現
初始化函數
def __init__(self, k=10):
"""
k 最近鄰個數
"""
self.k = k
訓練函數
def fit(self, X, y):
self.X = X
self.y = y
訓練函數只需存儲樣本的特徵和類別,不需要進行計算,這是knn的一個優點。
預測函數
def predict(self, X):
res = []
for x in X:
# 計算平方和
sum = np.sum((x-self.X)**2, axis=1)
num = np.argsort(sum)[:self.k]
pred_y = np.argmax(np.bincount(self.y[num]))
res.append(pred_y)
return np.array(res)
因爲需要計算每個待分類樣本與每個訓練樣本的距離,所以雖然實現過程簡單,但計算比較耗時。
整合全部代碼
class KNeighborsClassifier():
def __init__(self, k=10):
"""
k 最近鄰個數
"""
self.k = k
def fit(self, X, y):
self.X = X
self.y = y
def predict(self, X):
res = []
for x in X:
# 計算平方和
sum = np.sum((x-self.X)**2, axis=1)
num = np.argsort(sum)[:self.k]
pred_y = np.argmax(np.bincount(self.y[num]))
res.append(pred_y)
return np.array(res)
實例化演示
導入相關庫並查看數據分佈。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
iris = load_iris()
X = iris.data[:100]
y = iris.target[:100]
train_x,test_x,train_y,test_y = train_test_split(X, y, test_size=0.3, random_state=1)
color = ['red','yellow']
plt.rcParams['font.sans-serif'] = ['SimHei']
for i in range(2):
plt.scatter(train_x[train_y==i,0], train_x[train_y==i,1], color=color[i])
plt.scatter(test_x[:,0], test_x[:,1],color='silver')
plt.legend([1,2,'待分類樣本'])
實例化函數並預測樣本類別。
clf = KNeighborsClassifier(k=20)
clf.fit(train_x, train_y)
pred_y = clf.predict(test_x)
accuracy_score(test_y, pred_y)
進一步
k值是一個超參數,k值的大小決定了模型的好壞,可以通過k折交叉驗證來選取適合的k值,注意k折交叉的k值和k近鄰的k值不是同一個意思,只是剛好都這麼叫而已。這裏採用5折交叉驗證,主要步驟是將訓練集均分爲5份小訓練集,取出其中的4份用於knn分類器的訓練,剩餘的1份用來驗證模型的效果,可以得到模型的準確率。不同的取法會得到不一樣的結果,對於每個k值都將計算得到5個模型的準確率,我們將在重新生成的二分類樣本集上進行操作。
from sklearn.model_selection import KFold
from sklearn.datasets import make_classification
X,y = make_classification(n_samples=300, n_features=5, shuffle=True, random_state=6, n_classes=2)
color = ['red','yellow']
for i in range(2):
plt.scatter(X[y==i,0], X[y==i,1], color=color[i])
進行5折交叉驗證,選出最優的k值。
kf = KFold(n_splits=5)
accuracy = []
for i in range(1,40):
acc = []
for train_index, test_index in kf.split(X):
train_x,train_y = X[train_index],y[train_index]
test_x,test_y = X[test_index],y[test_index]
clf = KNeighborsClassifier(k=i)
clf.fit(train_x,train_y)
pred_y = clf.predict(test_x)
acc.append(sum(pred_y==test_y)/len(pred_y))
accuracy.append(acc)
accuracy = np.array(accuracy)
m,n = accuracy.shape
for i in range(n):
plt.scatter(range(1,m+1),accuracy[:,i])
plt.errorbar(range(1,m+1),accuracy.mean(axis=1),accuracy.std(axis=1))
從圖上可以看出,當參數k取5的時候,模型的效果最好。
在數據量還不是很大的情況下,可以使用上述的k折交叉驗證或網格搜索來尋找最優的k值;但當數據量很大時,採用這些方法,雖然可以實現,但是同時計算時間也會很長,要慎重使用。
以上便是k近鄰算法的代碼實現,如有不對之處,歡迎交流。