這裡是寫給小白看的,大牛路過勿噴。
1 KNN算法簡介
KNN(K-Nearest Neighbor)工作原理:存在一個樣本資料集合,也稱為訓練樣本集,并且樣本集中每個資料都存在标簽,即我們知道樣本集中每一資料與所屬分類對應的關系。輸入沒有标簽的資料後,将新資料中的每個特征與樣本集中資料對應的特征進行比較,提取出樣本集中特征最相似資料(最近鄰)的分類标簽。一般來說,我們隻選擇樣本資料集中前k個最相似的資料,這就是k近鄰算法中k的出處,通常k是不大于20的整數。最後選擇k個最相似資料中出現次數最多的分類作為新資料的分類
2 KNN算法優缺點
優點:精度高,對異常值不敏感、無資料輸入假定
缺點:計算複雜度高、空間複雜度高
做一個簡單的應用:
一種花叫做虹膜花:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnauQTNwITNzQTM30SO2gDNxMTN4ETOwQDM4EDMy0yNwcjMxMTMvwFNwgTMwIzLcdDM3ITMzEzLcd2bsJ2Lc12bj5ycn9Gbi52YugTMwIzcldWYtl2Lc9CX6MHc0RHaiojIsJye.jpg)
收集一些執行個體 萼片長度,萼片寬度,花瓣長度,花瓣寬度 (sepal length, sepal width, petal length and petal width) 類别: Iris setosa, Iris versicolor, Iris virginica. 學習目标是:根據四種屬性判斷類别 用python的sklearn庫實作: (sklearn中已經存在的資料集)
from sklearn import neighbors
from sklearn import datasets
knn = neighbors.KNeighborsClassifier()
iris = datasets.load_iris()
knn.fit(iris.data, iris.target)
# 當資料為0.1, 0.2, 0.3, 0.4時,預測它是什麼花
predictedLabel = knn.predict([[0.1, 0.2, 0.3, 0.4]])
print(predictedLabel)
不調用sklearn,自己實作: 這是一個資料集文本 截取資料集(irisdata.txt)的一段:
5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5.0,3.6,1.4,0.2,Iris-setosa
5.4,3.9,1.7,0.4,Iris-setosa
4.6,3.4,1.4,0.3,Iris-setosa
5.0,3.4,1.5,0.2,Iris-setosa
導入幾個基本的庫:
import csv
import random
import math
import operator
全局定義兩個集合:訓練集、測試集
# 訓練集
trainingSet = []
# 測試集
testSet = []
讀取資料并做一些初步的處理:
傳入一個分割機率,随機劃分訓練集和測試集
def loadDataset(filename, split):
with open(filename, 'r') as csvfile:
lines = csv.reader(csvfile)
dataset = list(lines)
for x in range(len(dataset) - 1):
for y in range(4):
dataset[x][y] = float(dataset[x][y])
if random.random() < split:
trainingSet.append(dataset[x])
else:
testSet.append(dataset[x])
歐式距離: 類似代數中直角坐标系的兩點距離,隻是擴充到多元
def euclideanDistance(instance1, instance2, length):
distance = 0
for x in range(length):
distance += pow((instance1[x] - instance2[x]), 2)
return math.sqrt(distance)
從訓練集中選出距離測試集中一個執行個體最近的k個資料:
計算訓練集中每一項和該執行個體的歐氏距離,取最小的k個距離
def getNeighbors(k, testInstance):
distances = []
length = len(testInstance) - 1
for x in range(len(trainingSet)):
dist = euclideanDistance(testInstance, trainingSet[x], length)
distances.append((trainingSet[x], dist))
distances.sort(key=operator.itemgetter(1))
neighbors = []
for x in range(k):
neighbors.append(distances[x][0])
return neighbors
擷取的這些k項未必是同一類,接下來統計類别個數,并傳回出現次數最多的類作為最終的結果:
def getResponse(neighbors):
classVotes = {}
for x in range(len(neighbors)):
response = neighbors[x][-1]
if response in classVotes:
classVotes[response] += 1
else:
classVotes[response] = 1
sortedVotes = sorted(classVotes.items(), key=operator.itemgetter(1), reverse=True)
return sortedVotes[0][0]
驗證精确度:
将測試集中預測的類别和測試集中真實的類别對比,得出精确度百分比:
def getAccuracy(predictions):
correct = 0
for x in range(len(testSet)):
if testSet[x][-1] == predictions[x]:
correct += 1
return (correct / float(len(testSet))) * 100.0
主函數:
if __name__ == '__main__':
main()
def main():
split = 0.70
loadDataset(r'D:\ml\irisdata.txt', split)
print('Train set: ' + repr(len(trainingSet)))
print('Test set: ' + repr(len(testSet)))
讀取後列印下個數:
Train set: 102
Test set: 48
接下來預測:
predictions = []
k = 3
for x in range(len(testSet)):
neighbors = getNeighbors(k, testSet[x])
result = getResponse(neighbors)
predictions.append(result)
print('>predicted=' + repr(result) + ', actual=' + repr(testSet[x][-1]))
看一下預測的一部分結果:
發現基本預測準确,測試精确度:
accuracy = getAccuracy(predictions)
print('Accuracy: ' + repr(accuracy) + '%')
發現精确度很高:
由于處理資料時候采用随機劃分的方式,可以反複運作測試,發現準确率基本在90%到96%,說明這個模型是合适的
小結:
KNN是簡單有效的分類資料算法,在使用時必須有訓練樣本資料,還要計算距離,如果資料量非常大會非常消耗空間和時間。它的另一個缺陷是無法給出任何資料的基礎結構資訊,是以我們無法平均執行個體樣本和典型執行個體樣本具體特征,
轉載于:https://www.cnblogs.com/xuyiqing/p/8762066.html