k近鄰演算法及python實現

2021-07-25 11:52:00 字數 4344 閱讀 2458

k近鄰演算法是機器學習中最簡單的一種演算法,簡單粗暴,給定乙個訓練資料集,對新的輸入例項,在訓練資料集中找到與該例項最鄰近的k個例項,把這k個例項中出現最多的類作為輸入例項的類。對於初學者可能會好奇,這個近鄰是什麼意思?例如調查一群人的資訊,會對研究目標調查多個特徵,記錄人的頭髮長度、身高、年齡、體重、膚色,性別,對這些特徵採用數值進行刻畫。假設現在我們需要通過頭髮長度、身高、年齡、體重和膚色這些資料來判斷乙個人的性別,我們會計算這個人的資料與其他(她)人的資料的差值,對差值取絕對值求和,找出差別最小的k個人,而把這k個人中性別多數作為這個人的性別判斷結果。

輸入:訓練資料集

其中,xi屬於特徵向量,yi為例項的類別,i=1,2,...,n

輸出:例項x所屬的類y

(1)根據給定的距離度量,在訓練集t中找出與x最近的k個點,涵蓋這個k個點的x的領域記做nk(x).

(2)根據分類決策規則決定x的類別y,通常採用多數表決策略:

上式中i為指示函式,當yi=cj是i為1,否則為零。

從上面的演算法可以看出,k近鄰演算法並不像其它的機器學習演算法那樣通過訓練資料得到乙個模型,通過這個學習到的模型來對資料進行**。而是需要對每個**資料計算與樣本資料集中的每個例項的距離,因此,k近鄰演算法的時間代價是隨著樣本空間的遞增而遞增的,所以對於大型資料集k近鄰不是乙個很好的選擇,一次**可能要好幾天甚至更久才能得到結果。可以嘗試將訓練資料複製貼上多次擴大訓練樣本(僅作為測試時間變化),比較計算時間的變化。

k近鄰演算法,是通過訓練資料對特徵空間的乙個劃分,每個樣本點都有乙個距離該樣本點比其它樣本點都近的領域,如果將k值設定為1,那麼任何落入這個領域的測試樣例都可以認為是和該樣本點有著相同的類。  因此當乙個k近鄰演算法,給定了訓練樣本、距離度量和k值,任何乙個測試樣例的類別是唯一確定的。

k近鄰的相似度通過兩個例項點的距離度量,常用的距離度量有,曼哈頓距離,歐式距離等,這些距離的通式如下:

當p取1時即為曼哈頓距離,當p取2時即為歐式距離。不同的取值,與中心點圍成多維圖形的區域大小也會不同,因此**的結果也會有所不同。

首先需要從檔案中讀取資料

def loaddataset(filename):

dataset=

labelset=

fr=open(filename)

for line in fr.readlines():

curline=line.strip().split('\t')

dataarr=

for feat in curline[:-1]:

return np.array(dataset),np.array(labelset)

loaddataset函式傳入乙個檔名,讀取檔案中的資料並返回特徵資料集和標籤集。

因為在資料中不同的特徵的取值範圍可能不同,例如人的身高和年齡,數值的取值範圍不同,在計算距離的時候取值範圍大的特徵列對最後的結果影響大,而這種影響可能會掩蓋取值小的資料對結果的影響。在沒有任何先驗知識的情況下,認為任何特徵對結果的影響相同,因此有必要將資料規範化,通常的做法是將資料變化為0-1的範圍內。

下面的minmax函式計算每一列的取值最小值,和取值範圍:

def minmax(self):

self.min=dataset.min(0)

self.range=dataset.max(0)-self.min

然後通過autonormal函式將資料規範化:

def autonorm(self,dataset):

self.minmax()

dataset=dataset-self.min

return dataset/self.range

這裡採用的是歐式距離:

def distance(self,x,y):

return np.sum(pow(x-y,2))

通過計算輸入資料與訓練資料中的每個例項距離,按照從小到大排序,選擇最小的k個,並從找出這k個例項中出現最多的類:

def calculate(self,test):

distances=

for data in self.dataset:

sortedindicies=np.argsort(np.array(distances))

classcount={}

for i in range(self.k):

voteilabel=self.labelset[sortedindicies[i]]

classcount[voteilabel]=classcount.get(voteilabel,0)+1

sortedclasscount=sorted(classcount.iteritems(),key=operator.itemgetter(1),reverse=true)

return sortedclasscount[0][0]

我對整個演算法進行了乙個封裝,通過初始化函式設定演算法的k值,在fit()函式中傳入訓練資料,通過predict()函式對給定的資料進行**。knn類完整**如下:

class knn:

dataset=

labelset=

#初始化,設定k值

def __init__(self,k):

self.k=k

#設定模型的資料

def fit(self,dataset,label):

self.labelset=label

self.minmax(dataset)

self.dataset=self.autonorm(dataset)

#計算各列的最小值和取值範圍

def minmax(self,dataset):

self.min=dataset.min(0)

self.range=dataset.max(0)-self.min

#在對資料無任何先驗知識的情況下預設各列的重要性相同,對各列進行標準化

def autonorm(self,dataset):

dataset=dataset-self.min

return dataset/self.range

#計算兩個資料點的距離(x1-y1)^2+(x2-y2)^2+...(xn-yn)^2

def distance(self,x,y):

return np.sum(pow(x-y,2))

def predict(self,data):

data=self.autonorm(data)

predictlabel=

for temp in data:

return predictlabel

def calculate(self,test):

distances=

for data in self.dataset:

sortedindicies=np.argsort(np.array(distances))

classcount={}

for i in range(self.k):

voteilabel=self.labelset[sortedindicies[i]]

classcount[voteilabel]=classcount.get(voteilabel,0)+1

sortedclasscount=sorted(classcount.iteritems(),key=operator.itemgetter(1),reverse=true)

return sortedclasscount[0][0]

k近鄰演算法對k值的選擇對**結果影響非常大,較小的取值會對異常值敏感,例如k取1,剛好落在乙個異常點的區域內,則**會出錯。k值太小,只有較小的鄰域對**有影響,意味著整體模型的複雜度變得複雜,容易發生過擬合。k值取得太大,較遠距離的點會影響資料的**,極端情況下,取整個訓練資料集,這時任何資料的**結果一定是資料集中出現最多的類,這種情況忽略了訓練資料中的有用資訊。k值的增大,意味著模型複雜度降低,但是模型趨於簡單,容易發生欠擬合。因此k值的選取很重要,通常採用交叉驗證的方法,通過網格搜尋方法選擇合適的k值。

k近鄰演算法 python實現

k近鄰演算法 k nearest neighbor,knn 是一種非常直觀的,易於理解的有監督的演算法 對於乙個待分類的樣本,在已知的樣本集合中尋 找與它距離最近的k個樣本,及所謂的k近鄰。通過這這k個近鄰的所述類別來決定分類結果。距離度量距離度量方法有很多種,例如 歐式距離 曼哈頓距離 切比雪夫距...

k近鄰演算法 python實現

特徵距離計算 距離計算方法有很多,這裡先列三種 簡單例子 電影型別 根據歐氏距離計算公式,算出未知電影與已知電影型別之間的距離。電影名稱 打鬥鏡頭 接吻鏡頭 電影型別 歐式距離13 104愛情片 20.522 100愛情片 18.731 81愛情片 19.2 4101 10動作片 115.3599 ...

K近鄰演算法 python實現

k近鄰演算法 演算法原理 將資料轉換成向量形式 計算輸入向量與樣本中的距離 比如歐式距離等 對距離計算結果排序 取前k個 根據指定規則 多數或者按照一定權重進行計算 確定輸入向量類別。python實現 import numpy as np import operator class knnmetho...