一、KNN簡述
KNN是比較經典的算法,也是是數據挖掘分類技術中最簡單的方法之一。
KNN的核心思想很簡單:離誰近就是誰。具體解釋為如果一個實例在特征空間中的K個最相似(即特征空間中最近鄰)的實例中的大多數屬於某一個類別,則該實例也屬於這個類別。
換個說法可能更好理解,比如一個一定范圍的平面隨機分布着兩種顏色的樣本點,在這個平面內有個實例點不知道它是什么顏色,因此通過它周邊的不同顏色的點分布情況進行推測,假設取K=3,意思是在離這個實例點最近的樣本點中去前三個最近的, 然后看這三個當中那種類別占比大,就判斷該實例點屬於那個類別的,當k=5的時候也一樣這樣判斷,因此k的取值很關鍵,通常不會超過20。當然,因為每個樣本有多個特征,因此實際工作中,這個‘平面’就是三維甚至是多維的,道理是一樣的。如圖:
二、KNN算法原理
在KNN中,通過計算對象間距離來作為各個對象之間的非相似性指標,避免了對象之間的匹配問題,在這里距離一般使用歐氏距離或曼哈頓距離:
對KNN算法的思想總結一下:就是在訓練集中數據和標簽已知的情況下,輸入測試數據,將測試數據的特征與訓練集中對應的特征進行相互比較,找到訓練集中與之最為相似的前K個數據,則該測試數據對應的類別就是K個數據中出現次數最多的那個分類,其算法的描述為:
1)計算測試數據與各個訓練數據之間的距離;
2)按照距離的遞增關系進行排序;
3)選取距離最小的K個點;
4)確定前K個點所在類別的出現頻率;
5)返回前K個點中出現頻率最高的類別作為測試數據的預測分類。
三、KNN算法優缺點以及算法改進
優缺點:
1、簡單,易於理解,是一個天然的多分類器;
2、不需要龐大的樣本數據也可以完成一個簡單的分類;
3、不需要訓練和求解參數(既是優點也是缺點);
4、數據量大的時候,計算量也非常大(樣本多,特征多);
5、不平衡樣本處理能力差;
6、並沒有學習和優化的過程,嚴格來說不算是機器學習。
改進:
進行加權平均,離得近的樣本給予更大的權重,離得遠的樣本使其權重變小。
四、KNN代碼實現
import numpy as np import pandas as pd import matplotlib.pylab as plt data_=pd.read_csv('vehicle.csv') print(data_) feature=np.array(data_.iloc[:,0:2]) # 將參數與特征進行分離,返回數據類型為數組,這里只拿去前兩列 #print(feature) labels = data_['label'].tolist() # 將'label'標簽提取出來轉換為列表類型,方便后續使用 #print(labels) # 數據可視化 plt.scatter(data_['length'][data_['label']=='car'],data_['width'][data_['label']=='car'],c='y') #先取length的數值,里面有car和truck的長度,再單獨取label那一行為car的值 plt.scatter(data_['length'][data_['label']=='truck'],data_['width'][data_['label']=='truck'],c='r') #先取width的數值,里面有car和truck的長度,再單獨取label那一行為truck的值 #print(data_['length']) #print(plt.show()) test = [4.7,2.1] # 待測樣本 numSamples = data_.shape[0] # 讀取矩陣的長度,這里是讀取第一維的長度# 運行結果:150 diff_= np.tile(test,(numSamples,1)) #這里表示test列表豎向重復150次,橫向重復1一次,組成一個素組 # numpy.tile(A,B)函數:A=[4.7,2.1],B=(3,4),意思是列表A在行方向(從上到下)重復3次,在列放心(從左到右)重復4次 diff = diff_-feature # 利用這里的實驗值和樣本空間里的每一組數據進行相減 squreDiff = diff**2 # 將差值進行平方 squreDist = np.sum(squreDiff,axis=1) # 每一列橫向求和,最后返回一維數組 distance = squreDist ** 0.5 sorteDisIndices = np.argsort(distance) # 排序 k=9 # k個最近鄰 classCount = {} # 字典或者列表的數據類型需要聲明 label_count=[] # 字典或者列表的數據類型需要聲明 for i in range(k): voteLabel = labels[sorteDisIndices[i]] classCount[voteLabel] = classCount.get(voteLabel,0) + 1 label_count.append(voteLabel) from collections import Counter word_counts = Counter(label_count) top = word_counts.most_common(1) # 返回數量最多的值以及對應的標簽 #print(word_counts) #print(top) # 利用sklearn進行實現 import numpy as np import pandas as pd import matplotlib.pylab as plt
data_=pd.read_csv('vehicle.csv') feature=np.array(data_.iloc[:,0:2]) # 將參數與特征進行分離,返回數據類型為數組,這里只拿去前兩列 labels = data_['label'].tolist() # 將'label'標簽提取出來轉換為列表類型,方便后續使用 from sklearn.model_selection import train_test_split feautre_train,feautre_test,label_train,label_test=train_test_split(feature,labels,test_size=0.2) # 指出訓練集的標簽和特征以及測試集的標簽和特征,0.2為參數,對測試集以及訓練集按照2:8進行划分 from sklearn.neighbors import KNeighborsClassifier model=KNeighborsClassifier(n_neighbors= 9) model.fit(feautre_train,label_train) # 現在只需要傳入訓練集的數據 prediction=model.predict(feautre_test) #print(prediction) labels=['car','truck'] classes=['car', 'truck'] from sklearn.metrics import classification_report result_=classification_report(label_test,prediction,target_names = classes,labels=labels,digits=4) # target_names:類別;digits:int,輸出浮點值的位數 print(result_)