K最近鄰(KNN,K-NearestNeighbor)是1967年由Cover T和Hart P提出的一種基本分類與回歸方法,它是數據挖掘分類技術中最簡單的方法之一,非常容易理解應用。所謂K最近鄰,就是K個最近的鄰居的意思,說的是每個樣本都可以用它最接近的(一般用距離最短表示最接近)K個鄰居來代表。如果K個鄰居里大多數都屬於某一個類別,那么該樣本也被划分為這個類別。
KNN算法中所選擇的鄰居都是已經正確分類的對象,屬於懶惰學習,即KNN沒有顯式的學習過程,沒有訓練階段。待收到新樣本后直接進行處理。
算法描述:
1)計算測試數據與各個訓練數據之間的距離;
2)按照距離的遞增關系進行排序;
3)選取距離最小的K個點;
4)確定前K個點所在類別的出現頻率;
5)返回前K個點中出現頻率最高的類別作為測試數據的預測分類.
通常k是不大於20的整數,上限是訓練數據集數量n的開方,隨着數據集的增大,K的值也要增大。
依賴於訓練數據集和K的取值,輸出結果可能會有不同。所以需要評估算法的正確率,選取產生最小誤差率的K:比如我們可以提供已有數據的90%作為訓練樣本來訓練分類器,而使用其余的10%數據去測試分類器,檢測錯誤率是否隨着K值的變化而減小。需要注意的是,10%的測試數據應該是隨機選擇的。
python示例1(
sklearn包封裝了KNN算法
)
import numpy as np
from sklearn import neighbors
from sklearn import datasets
knn = neighbors.KNeighborsClassifier()
iris = datasets.load_iris() #加載"\Anaconda2\Lib\site-packages\sklearn\datasets\data\iris.csv"
#print iris
#print iris.data
#print iris.target
knn.fit(iris.data, iris.target) #用KNN分類器進行建模,這里用的默認的參數
predictedLabel = knn.predict([[5.1, 5.2, 5.3, 5.4]])
print ("predictedLabel is :" + str(predictedLabel))
predictedLabel = knn.predict([[0.1, 0.2, 0.3, 0.4]])
print ("predictedLabel is :" + str(predictedLabel))
#拆分測試集和訓練集,計算算法的准確率
np.random.seed(0)
#permutation隨機生成50個訓練數,測試集就是sum-50
indices = np.random.permutation(len(iris_y))
iris_X_train = iris_X[indices[:50]]
iris_y_train = iris_y[indices[:50]]
iris_X_test = iris_X[indices[50:]]
iris_y_test = iris_y[indices[50:]]
#print iris_X_train
#用KNN分類器進行建模,和上面相比,不再使用所有數據,而是訓練集數據
knn.fit(iris_X_train, iris_y_train)
#預測所有測試集數據的鳶尾花類型
predict_result = knn.predict(iris_X_test)
#計算預測的准確率
print(knn.score(iris_X_test, iris_y_test))
python示例2
(自己寫KNN算法,簡單示例
)
import numpy as np
import math
a=[]
p=np.array([0,4,5])
p1=np.array([3,0,0])
p2=np.array([3,1,2])
p3=np.array([3,4,5])
labels=['red','blue','yellow']#p1/p2/p3分別對應的label
p11=p1-p
p21=p2-p
p31=p3-p
#math.hypot用來計算兩點之間距離((x1-x2)^2+(y1-y2)^2)^0.5
#因為是三維數組,所以需要計算三點之間距離,math.hypot只能傳參2個,所以計算2次達到目的
p111=math.hypot(p11[0],p11[1])
p1111=math.hypot(p11[2],p111)
a.append(p1111)
p211=math.hypot(p21[0],p21[1])
p2111=math.hypot(p21[2],p211)
a.append(p2111)
p311=math.hypot(p31[0],p31[1])
p3111=math.hypot(p31[2],p311)
a.append(p3111)
#對數組a排序,返回索引,第一個索引對應的訓練數據和p的距離最短,那么p的label=該數據的label
#相當於K=1,只找最近的那一個鄰居
a=np.array(a)
b=a.argsort()
print labels[b[0]]
python示例3
(自己寫KNN算法,進階示例
)
import numpy as np
from math import sqrt
import operator as opt
#對數據進行[0,1]格式化處理
def normData(dataSet):
maxVals = dataSet.max(axis=0)
minVals = dataSet.min(axis=0)
ranges = maxVals - minVals
retData = (dataSet - minVals) / ranges
return retData, ranges, minVals
def kNN(dataSet, labels, testData, k):
distSquareMat = (dataSet - testData) ** 2 # 計算差值的平方
distSquareSums = distSquareMat.sum(axis=1) # 求每一行的差值平方和
distances = distSquareSums ** 0.5 # 開根號,得出每個樣本到測試點的距離
sortedIndices = distances.argsort() # 排序,得到排序后的下標
indices = sortedIndices[:k] # 取最小的k個
labelCount = {} # 存儲每個label的出現次數
for i in indices:
label = labels[i]
labelCount[label] = labelCount.get(label, 0) + 1 # 次數加一
sortedCount = sorted(labelCount.items(), key=opt.itemgetter(1), reverse=True)
# 對label出現的次數從大到小進行排序
return sortedCount[0][0] # 返回出現次數最大的label
if __name__ == "__main__":
dataSet = np.array([[2.0, 3], [6.0, 8], [3.0, 4]])
normDataSet, ranges, minVals = normData(dataSet)
print normDataSet
labels = ['a', 'a', 'c']
testData = np.array([3.0, 5])
normTestData = (testData - minVals) / ranges
print normTestData
result = kNN(normDataSet, labels, normTestData, 3)
#k=1時就會取到最近的那一個點[3.0, 4]對應的label'c'
print(result)
學習參考: