1. 程式人生 > >機器學習筆記九:K近鄰演算法(KNN)

機器學習筆記九:K近鄰演算法(KNN)

一.基本思想

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值.
計算複雜度高,空間複雜度高