1. 程式人生 > 實用技巧 >K近鄰演算法

K近鄰演算法

1.演算法描述

  簡單的說,KNN演算法通過計算樣本特徵值之間的距離來進行分類。已知一系列帶標籤的資料集,通過計算未知樣本與資料集中樣本距離,並對距離進行排序,取距離最近的K個樣本的標籤,將未知樣本歸到距離最近的K個樣本相同的標籤中。

  實現步驟:(1)計算已知類別的資料集中的點到當前未知點之間的距離;

       (2)按照距離升序排序

       (3)選擇與當前點距離最小的前k個點

       (4)這k個點大多數屬於哪個類,那麼未知點也屬於這個類

  這裡的距離可以為:(1)歐式距離:(x,y是兩個樣本,xi,yi是兩個樣本歸一化後的特徵值,下式是計算的是兩個樣本之間的歐式距離)

            (2)曼哈頓距離:

      

            (3)......

2.實現過程

  以改進約會網站匹配效果為例(資料集)

#使用KNN演算法改進約會網站的配對效果,資料集為1000*3,標籤為1000*1
#K-近鄰演算法:已知一系列帶標籤的資料集,通過計算未知樣本與資料集中樣本的歐式距離,
# 並對距離進行排序,取距離最近的K個樣本的標籤,將未知樣本歸到距離最近的K個樣本相同的標籤中
import numpy as np
import operator
#K-近鄰演算法
def classify0(inX,dataSet,labels,k):#inX:1*3; dataSet:1000*3; Labels:1000*1
dataSetSize=dataSet.shape[0]#樣本資料集個數1000
diffMat=np.tile(inX,(dataSetSize,1))-dataSet#因為inX的大小與dataSetSize不一致,所以要進行陣列的賦值(延y軸),將1*3延y軸為1000*3
sqDiffMat=diffMat**2#對每個array陣列元素**2
sqDistances=sqDiffMat.sum(axis=1)#按行求和
distances=sqDistances**0.5
sortedSqDistance=distances.argsort()
classCount={}
for i in range(k):
voteILabel=labels[sortedSqDistance[i]]
classCount[voteILabel]=classCount.get(voteILabel,0)+1
sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
#將文字記錄轉化為numpy陣列
def file2matrix(filename):#filename檔案路徑
fr=open(filename)
arrayOLines=fr.readlines()#返回列表
numbersOfLines=len(arrayOLines)#文字檔案行數,資料集資料個數
returnMat=np.zeros((numbersOfLines,3))#3個特徵,資料集
classLabelVector=[]#標籤集
index=0
for line in arrayOLines:
line=line.strip()#去掉每行前後空格
listFromLine=line.split('\t')#分割特徵
returnMat[index,:]=listFromLine[0:3]#0,1,2
if listFromLine[-1]=='largeDoses':
classLabelVector.append(1)
elif listFromLine[-1]=='smallDoses':
classLabelVector.append(0)
else:
classLabelVector.append(-1)
index+=1
return returnMat,classLabelVector
#歸一化特徵值:在計算歐式距離的時候,數字差值最大的屬性對計算結果的影響最大,但是三個特徵的重要性是一樣的,所以要歸一化
def autoNorm(dataSet):#1000*3
minValue=dataSet.min(0)#1*3
maxValue = dataSet.max(0)#1*3
ranges=maxValue-minValue#1*3
normDataSet=np.zeros(np.shape(dataSet))#生成1000*3的全零矩陣
m=np.shape(dataSet)[0]#1000
normDataSet=dataSet-np.tile(minValue,(m,1))#沿y軸複製,延拓
normDataSet=normDataSet/np.tile(ranges,(m,1))#對應位置,對應相除,1*3->1000*3
return normDataSet,ranges,minValue
#測試
def datingClassTest():
hoRatio=0.1#選擇10%的資料作為測試資料
datingDataMax,datingDataLabels=file2matrix('E:\AI_Test\knn+dating\datingTestSet.txt')
normDataSet,ranges,minValue=autoNorm(datingDataMax)
m=int(np.shape(datingDataMax)[0])#資料集的大小
numberOfTest=int(hoRatio*m)#測試集數目
numberOfTrain=int(m-numberOfTest)#訓練集數量
errorCount=0
for i in range(numberOfTest):
classifyResult=classify0(datingDataMax[i,:],datingDataMax[numberOfTest:m,:],datingDataLabels[numberOfTest:m],3)
if classifyResult!=datingDataLabels[i]:
errorCount+=1
print("分類器分類標籤: %d,真實標籤 %d"%(classifyResult,datingDataLabels[i]))
print("分類錯誤率: %f"%(errorCount/numberOfTest))
if __name__ == '__main__':
datingClassTest()

3. sklearn實現

  以鳶尾花分類為例。

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
iris=datasets.load_iris()
x=iris.data
y=iris.target
print(iris.keys())
x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3)
knn=KNeighborsClassifier()
knn.fit(x_train,y_train)
acc=knn.score(x_test,y_test)
print('分類準確率為:%f'%acc)