不做調包俠,手撕KNN算法

啥是KNN算法

KNN是最簡單的分類算法之一,在給定樣本數據和標籤的情況下,判定新來的一個數據屬於哪一個標籤。如何判斷呢?關鍵值在於K,所謂K就是從距離新來數據最近的樣本數據中選取K個數據,我們來數一數這K的樣本數據對應的標籤,哪個標籤佔比高,那就把該新來的數據歸爲哪個標籤。
基本算法步驟:

  1. 設新來數據爲x,計算x與所有數據集S中樣本的距離。距離是歐式距離,哈密頓距離,根據具體業務而不同。
  2. 找出距離最近的K個樣本,並查看對應的標籤
  3. 看哪個標籤在K中佔比高,則把x記爲哪個標籤。

手撕KNN算法代碼

初始化樣本

構建一組樣本數據,樣本格式爲[point,label,distance],分別存放點座標,標籤和距離。初始化數據。samples0和samples1分別對應標籤爲0和1的數據集。samples=samples0+samples1爲總體數據。

import random
import matplotlib.pyplot as plt
import math
samplesNum=50
samples=[]
samples0=[]
samples1=[]
for i in range(samplesNum):
    point = [random.randint(0, 100), random.randint(0, 100)]
    samples0.append([point, 0, 0])
for i in range(samplesNum):
    point = [random.randint(60, 160), random.randint(60, 160)]
    samples1.append([point, 1, 0])
samples=samples0+samples1

樣本數據大概長這樣
在這裏插入圖片描述

KNN算法

我們用KNN算法返回inputTest這個點位的標籤。

def distEclud(A,B):
    return math.sqrt(math.pow(A[0]-B[0],2)+math.pow(A[1]-B[1],2))

def classfiyKNN(inputTest,dataSet,K):
    labelsList=[]
    for i in range(len(dataSet)):
        dataSet[i][2]=distEclud(inputTest,dataSet[i][0])
    dataSet.sort(key=lambda samp: samp[2],reverse=False)
    labelsList=[0,1]
    labelsNum=[0,0]
    for i in range(K):
        for j in labelsList:
            if dataSet[i][1]==labelsList[j]:
                labelsNum[j]=labelsNum[j]+1
                break
    labelIndex=labelsNum.index(max(labelsNum))
    return labelsList[labelIndex]

實驗幾個數據

我們生成10個測試數據,看下情況。其中圓形的數據爲測試數據。對應的顏色即爲其分類。

K=10
testSample=[]
for i in range(10):
    point = [random.randint(60, 100), random.randint(60, 100)]
    testSample.append(point)
for t in testSample:
    resultlabel = classfiyKNN(t, samples, K)
    plt.scatter(t[0], t[1], marker=markers[2], c=color[resultlabel], alpha=0.5)
plt.show()

在這裏插入圖片描述

K的選擇

KNN算法最關鍵的是確定K值。我們通過對原始樣本處理,找到最合適的K值。通過測試我們看到在K取1,2,3左右時,錯誤率較低。

TestNum=int(samplesNum*0.4)

TestSamples0=random.sample(samples0,TestNum)
TestSamples1=random.sample(samples1,TestNum)
for ts in TestSamples0:
    samples0.remove(ts)

for ts in TestSamples1:
    samples1.remove(ts)

TestSample=TestSamples0+TestSamples1
TrainSample=samples1+samples1
print("TestSample:",len(TestSample))
print("TrainSample:",len(TrainSample))
error_rate=[]
Kx=[]
for K in range(20):
    errorNum=0
    Kx.append(K)
    for TS in TestSample:
        resultlabel = classfiyKNN(TS[0], samples, K)
        if resultlabel!=TS[1]:
            errorNum+=1
    error_rate.append(round(errorNum/len(TestSample),2))

plt.plot(Kx,error_rate,'g')

print(error_rate)
plt.show()

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章