機器學習筆記九:K近鄰演算法(KNN)
阿新 • • 發佈:2018-12-31
一.基本思想
K近鄰演算法,即是給定一個訓練資料集,對新的輸入例項,在訓練資料集中找到與該例項最鄰近的K個例項,這K個例項的多數屬於某個類,就把該輸入例項分類到這個類中。如下面的圖:
通俗一點來說,就是找最“鄰近”的夥伴,通過這些夥伴的類別來看自己的類別。比如以性格和做過的事情為判斷特徵,和你最鄰近的10個人中(這裡暫且設k=10),有8個是醫生,有2個是強盜。那麼你是醫生的可能性更加大,就把你劃到醫生的類別裡面去,這就算是K近鄰的思想。
K近鄰思想是非常非常簡單直觀的思想。非常符合人類的直覺,易於理解。
至此,K近鄰演算法的核心思想就這麼多了。
K值選擇,距離度量,分類決策規則是K近鄰法的三個基本要素.
從K近鄰的思想可以知道,K近鄰演算法是離不開對於特徵之間“距離”的表徵的,至於一些常見的距離,參考:
機器學習筆記八:常見“距離”歸納
二.實戰
這一部分的資料集《機器學習實戰》中的KNN約會分析,程式碼按照自己的風格改了一部分內容。
首先是讀取資料部分(data.py):
import numpy as np
def creatData(filename):
#開啟檔案,並且讀入整個檔案到一個字串裡面
file=open(filename)
lines=file.readlines()
sizeOfRecord=len(lines)
#開始初始化資料集矩陣和標籤
group=np.zeros((sizeOfRecord,3))
labels=[]
row=0
#這裡從檔案讀取存到二維陣列的手法記住
for line in lines:
line=line.strip()
tempList=line.split('\t')
group[row,:]=tempList[:3]
labels.append(tempList[-1])
row+=1
return group,labels
然後是KNN演算法的模組:KNN.py
import numpy as np
#分類函式(核心)
def classify(testdata,dataset,labels,k) :
dataSize=dataset.shape[0]
testdata=np.tile(testdata,(dataSize,1))
#計算距離並且按照返回排序後的下標值列表
distance=(((testdata-dataset)**2).sum(axis=1))**0.5
index=distance.argsort()
classCount={}
for i in range(k):
label=labels[index[i]]
classCount[label]=classCount.get(label,0)+1
sortedClassCount=sorted(list(classCount.items()),
key=lambda d:d[1],reverse=True)
return sortedClassCount[0][0]
#歸一化函式(傳入的都是處理好的只帶資料的矩陣)
def norm(dataset):
#sum/min/max函式傳入0軸表示每列,得到單行M列的陣列
minValue=dataset.min(0)
maxValue=dataset.max(0)
m=dataset.shape[0]
return (dataset-np.tile(minValue,(m,1)))/np.tile(maxValue-minValue,(m,1))
#測試函式
def classifyTest(testdataset,dataset,dataset_labels,
testdataset_labels,k):
sampleAmount=testdataset.shape[0]
#歸一化測試集合和訓練集合
testdataset=norm(testdataset)
dataset=norm(dataset)
#測試
numOfWrong=0
for i in range(sampleAmount):
print("the real kind is:",testdataset_labels[i])
print("the result kind is:",
classify(testdataset[i],dataset,dataset_labels,k))
if testdataset_labels[i]==classify(testdataset[i],
dataset,dataset_labels,k):
print("correct!!")
else:
print("Wrong!!")
numOfWrong+=1
print()
print(numOfWrong)
畫圖模組(drawer.py):
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import data
def drawPlot(dataset,labels):
fig=plt.figure(1)
ax=fig.add_subplot(111,projection='3d')
for i in range(dataset.shape[0]):
x=dataset[i][0]
y=dataset[i][1]
z=dataset[i][2]
if labels[i]=='largeDoses':
ax.scatter(x,y,z,c='b',marker='o')
elif labels[i]=='smallDoses':
ax.scatter(x,y,z,c='r',marker='s')
else:
ax.scatter(x,y,z,c='g',marker='^')
plt.show()
測試模組(run.py)
import data
import KNN
import drawer
#這裡測試資料集和訓練資料集都是採用的同一個資料集
dataset,labels=data.creatData("datingTestSet.txt")
testdata_set,testdataset_labels=data.creatData("datingTestSet.txt")
print(type(dataset[0][0]))
#測試分類效果。K取得是10
KNN.classifyTest(testdata_set,dataset,labels,testdataset_labels,10)
#畫出訓練集的分佈
drawer.drawPlot(dataset,labels)
結果:
三.優缺點分析
從上面的程式碼可以看到,K近鄰法並不具有顯式的學習過程,你必須先把資料集存下來,然後類似於比對的來作比較。K近鄰法實際上是利用訓練資料集對特徵向量空間進行劃分,並且作為其分類的模型
優點:
多數表決規則等價於經驗風險最小化.
精度高,對異常值不敏感,無資料輸入假定
缺點:
K值選擇太小,意味著整體模型變得複雜,容易發生過擬合.但是K值要是選擇過大的話,容易忽略例項中大量有用的資訊,也不可取.一般是先取一個比較小的數值,通常採用交叉驗證的方式來選取最優的K值.
計算複雜度高,空間複雜度高