背景與原理:
KNN算法其實是邏輯最簡單的分類算法——我們認爲一個數據的類型是由與其最接近的數據決定的,而“接近”實際上就是我們度量兩個數據點之間的距離,如果我們把一組數據看做一個向量$(x_{1},...,x_{n},y)$,其中$y$代表這個數據的類別,那麼兩組數據$X_{i},X_{j}$間的距離如果使用歐式距離表示爲$L_{ij}=\sqrt{\sum_{k=1}^{n}(x_{ik}-x_{jk})^{2}}$
那麼對於空間中已經分好類的若干數據,如果我們想預測輸入的某組數據屬於什麼類,那麼我們去計算空間中分好類的數據點離它的距離,然後選擇距離最近的認爲和想預測的數據是最接近的,直接選擇距離最近的數據點的類別即可。
當然,只選擇最近的是由很大問題的,所以K近鄰算法(K-Nearest Neighbours)就是將上述“最近”改成“K個最近的”,然後找出這K個數據點中概率最大的類別作爲我們預測的類別。
代碼實現:
import numpy as np import math from scipy import stats import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression def dis(alpha,beta): s=0 for i in range(0,len(alpha)-1): s+=(alpha[i]-beta[i])**2 return math.sqrt(s) def KNN_Test(input,dataset,siz,K): q=[] p=[] for i in range(0,siz): d=dis(input,dataset[i]) maxp=0 for j in range(0,len(q)): if q[j]>q[0]: maxp=j if len(q)<K: q.append(d) p.append(i) elif q[maxp]>d: q[maxp]=d p[maxp]=i cnt=0 for i in range(0,K): if dataset[p[i]][2]==1: cnt+=1 if cnt<K/2: return 0 else: return 1 x=np.arange(0.,10.,0.02) y=5-2*x/3+np.random.randn(500) now=0 dataset=[] for i in range(0,500): typ = 0 if 2*x[i]+3*y[i] <= 15: if abs(np.random.randn(1)[0])<2: typ = 1 else: typ = 0 else: if abs(np.random.randn(1)[0]) < 2: typ = 0 else: typ = 1 dataset.append([x[i],y[i],typ]) c_cnt=0 for i in range(0,500): predict_typ=KNN_Test(dataset[i],dataset,500,10) if predict_typ==dataset[i][2]: c_cnt+=1 print(c_cnt/500)
這段代碼生成的分類數據和邏輯迴歸的相同,我們這次使用KNN算法進行分類,準確率相對可觀
小結與改進:
KNN算法存在相當的不足之處,在改進中我們可以選擇加入權值——雖然我們考慮最近的K個“鄰居”,但是我們認爲一組數據肯定與離它最近的鄰居更接近,因此在計算概率時我們對於距離較近的數據點給出一個較高的權值,距離較遠的鄰居給出一個較低的權值,這樣能更好地體現“近鄰”這個觀點。
同樣,究竟選擇幾個“鄰居”也是值得考慮的,這一點可以通過權衡樣本數量來進行調整。
KNN算法的另一個缺點在於訓練樣本數量很大、維度很多的時候計算開銷很大,因此我們可以在預處理階段使用降維算法對維度進行簡化以提高效率