1. 程式人生 > >KNN及其改進演算法的python實現

KNN及其改進演算法的python實現

一、馬氏距離

我們熟悉的歐氏距離雖然很有用,但也有明顯的缺點。它將樣品的不同屬性(即各指標或各變數)之間的差別等同看待,這一點有時不能滿足實際要求。例如,在教育研究中,經常遇到對人的分析和判別,個體的不同屬性對於區分個體有著不同的重要性。因此,有時需要採用不同的距離函式。
  如果用dij表示第i個樣品和第j個樣品之間的距離,那麼對一切ijkdij應該滿足如下四個條件:
    ①當且僅當i=j時,dij=0
dij0
dijdji(對稱性)
dijdikdkj(三角不等式)
顯然,歐氏距離滿足以上四個條件。滿足以上條件的函式有多種,本節將要用到的馬氏距離也是其中的一種。
  第i個樣品與第

j個樣品的馬氏距離dij用下式計算:
dij =(x i x j)'S-1(x ixj)
  其中,x i x j分別為第i個和第j個樣品的m個指標所組成的向量,S為樣本協方差矩陣。
  馬氏距離有很多優點。它不受量綱的影響,兩點之間的馬氏距離與原始資料的測量單位無關;由標準化資料和中心化資料(即原始資料與均值之差)計算出的二點之間的馬氏距離相同。馬氏距離還可以排除變數之間的相關性的干擾。它的缺點是誇大了變化微小的變數的作用。舉例說明:

兩個樣本: 
His1 = {3,4,5,6} 
His2 = {2,2,8,4} 

它們的均值為: 
U = {2.5, 3, 6.5, 5} 

協方差矩陣為:

 
S = 
| 0.25  0.50  -0.75  0.50  | 
| 0.50  1.00  -1.50  1.00  |  
|-0.75  -1.50    2.25  -1.50  | 
| 0.50  1.00  -1.50  1.00  | 

其中S(i,j)={[His1(i)-u(i)]*[His1(j)-u(j)]+[His2(i)-u(i)]*[His2(j)-u(j)]}/2 
下一步就是求出逆矩陣S^(-1) 
馬氏距離 D=sqrt{[His1-His2] * S^(-1) * [(His1-His2)的轉置列向量]}
1
)馬氏距離的計算是建立在總體樣本的基礎上的,這一點可以從上述協方差矩陣的解釋中可以得出,也就是說,如果拿同樣的兩個樣本,放入兩個不同的總體中,最後計算得出的兩個樣本間的馬氏距離通常是不相同的,除非這兩個總體的協方差矩陣碰巧相同;
 
2
)在計算馬氏距離過程中,要求總體樣本數大於樣本的維數,否則得到的總體樣本協方差矩陣逆矩陣不存在,這種情況下,用歐式距離來代替馬氏距離,也可以理解為,如果樣本數小於樣本的維數,這種情況下求其中兩個樣本的距離,採用歐式距離計算即可。 
3
)還有一種情況,滿足了條件總體樣本數大於樣本的維數,但是協方差矩陣的逆矩陣仍然不存在,比如A34),B56);C78),這種情況是因為這三個樣本在其所處的二維空間平面內共線(如果是大於二維的話,比較複雜)。這種情況下,也採用歐式距離計算。 
4
)在實際應用中總體樣本數大於樣本的維數這個條件是很容易滿足的,而所有樣本點出現3)中所描述的情況是很少出現的,所以在絕大多數情況下,馬氏距離是可以順利計算的,但是馬氏距離的計算是不穩定的,不穩定的來源是協方差矩陣,這也是馬氏距離與歐式距離的最大差異之處。
綜上,我們用python編寫了馬氏距離,如下:

<span style="font-size:14px;">distances=[]
for i in range(dataSetSize):
    x = numpy.array(dataSet)
    xt=x.T
    D=numpy.cov(xt)
    invD=numpy.linalg.inv(D)
    tp=inX-dataSet[i]
    distances.append(numpy.sqrt(dot(dot(tp,invD),tp.T)))</span>

最後得到的distances就是測試樣本和每個訓練樣本的馬氏距離。

二、wk_NNC演算法

wk-NNC演算法是對經典knn演算法的改進,這種方法是對k個近鄰的樣本按照他們距離待分類樣本的遠近給一個權值w

clip_image002

clip_image004是第i個近鄰的權值,其中1<i<k,clip_image006是待測樣本距離第i個近鄰的距離。

python實現這個演算法比較簡單:

<span style="font-size:14px;">def wk_knn(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize,1)) - dataSet  
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)  
    distances = sqDistances**0.5 
    sortedDistIndicies = distances.argsort()         
    classCount={}    
    w=[]      
    for i in range(k):
        w.append((distances[sortedDistIndicies[k-1]]-distances[sortedDistIndicies[i]]\
        )/(distances[sortedDistIndicies[k-1]]-distances[sortedDistIndicies[0]]))
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + w[i]
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]</span>

三、knnm演算法

knnm演算法運用了訓練樣本中的每一個模式,對訓練樣本的每個類clip_image008

1 ≤ i ≤ c,在每一個類中找出距離測試樣本距離最近的k個近鄰clip_image010,假設這k個近鄰的均值為clip_image012,同樣的,i1c變化,我們得到clip_image014,如果clip_image016M當中距離測試樣本最近的,則測試樣本屬於clip_image018類。

如下圖所示,對於一個兩類的問題,每個類選三個近鄰,類clip_image020*表示,類clip_image022o表示,“Y”是測試樣本,則Y屬於clip_image022[1]類。

clip_image025

python實現如下:

<span style="font-size:14px;">def knnm(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet   #tile repeat inX to (dataSetSize,1)
    sqDiffMat = diffMat ** 2
    sqDistances = sqDiffMat.sum(axis=1)  #sum per row
    distances = sqDistances ** 0.5
    sortedDistIndicies = distances.argsort()
    classCount={}
    classNum={}
    i=0
    while i<dataSetSize:
        voteIlabel = labels[sortedDistIndicies[i]]
        if sum(classNum)==10*k:
            break
        elif classNum.get(voteIlabel,0)==k:
            i += 1
        else:
            classCount[voteIlabel] = classCount.get(voteIlabel,0) \
                                     + distances[sortedDistIndicies[i]]
            classNum[voteIlabel]=classNum.get(voteIlabel,0)+1
            i += 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1))
    return sortedClassCount[0][0]</span>

四、實驗過程

我在手寫字元和約會數集分別作了實驗,結果如下(k=7):

約會數集錯誤率

KNN

WK_KNN

KNNM

馬氏距離

6%

6.6%

6.2%

歐氏距離

5.8%

6.2%

6.2%

由於手寫字元訓練樣本協方差矩陣不可逆,因此只能求歐氏距離

手寫字元錯誤率

KNN

WK_KNN

KNNM

歐式距離

1.1628%(k=3最小)

0.9514%(k=5最小)

1.2685%(k=3最小)

五、實驗小結

歐式距離比馬氏距離計算量小得多,速度快,而且可以看出分類的效果甚至比馬氏距離要好,,可以看到,在約會數集中,knn的表現要優於其他兩種演算法,歐式距離的knn錯誤率最低,而wk_knn在手寫字元識別中有較為出色的表現,相對於其他兩種演算法,knnm並沒有想象中的效果

相關推薦

KNN及其改進演算法python實現

一、馬氏距離 我們熟悉的歐氏距離雖然很有用,但也有明顯的缺點。它將樣品的不同屬性(即各指標或各變數)之間的差別等同看待,這一點有時不能滿足實際要求。例如,在教育研究中,經常遇到對人的分析和判別,個體的

K近鄰演算法(KNN)原理解析及python實現程式碼

KNN演算法是一個有監督的演算法,也就是樣本是有標籤的。KNN可以用於分類,也可以用於迴歸。這裡主要講knn在分類上的原理。KNN的原理很簡單:            放入一個待分類的樣本,使用者指定k的大小,然後計算所有訓練樣本與該樣

【機器學習演算法-python實現KNN-k近鄰演算法實現(附原始碼)

 下載地址 kNN演算法及例項原始碼實現#coding=utf-8 ''' Created on Sep 16, 2010 kNN: k Nearest Neighbors Input: inX: vector to compare to existing dataset (1xN)

[機器學習]kNN演算法python實現(例項:數字識別)

# 使用好任何機器學習演算法的前提是選好Featuresfrom numpy import * import operator from os import listdir def classify0(inX, dataSet, labels, k):     data

cart樹回歸及其剪枝的python實現

mat 接下來 更多 split 討論 也有 其中 程序 target 轉自穆晨 閱讀目錄 前言 回歸樹 回歸樹的優化工作 - 剪枝 模型樹 回歸樹 / 模型樹的使用 小結 回到頂部 前言 前文討論的回歸算法都是全局且針對線性問題的回歸,即使是其中的局

機器學習實戰——k-近鄰演算法Python實現問題記錄

  準備 kNN.py 的python模組 from numpy import * import operator def createDataSet(): group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])

小白向Apriori演算法Python實現

  參考部落格:http://www.cnblogs.com/llhthinker/p/6719779.html      學習的別人的程式碼,用Python實現的Apriori演算法,演算法介紹見https://www.cnblogs.com/1113127139aaa/p/9926507.html

遺傳演算法-python實現

已經調通,並有大量註釋 # encoding=utf-8 import math import random import operator class GA(): def __init__(self, length, count): # 染色體長度

機器學習——樸素貝葉斯演算法Python實現

簡介 這裡參考《統計學習方法》李航編進行學習總結。詳細演算法介紹參見書籍,這裡只說明關鍵內容。 即 條件獨立下:p{X=x|Y=y}=p{X1=x1|Y=y} * p{X2=x2|Y=y} *...* p{Xn=xn|Y=y} (4.4)等價於p{Y=ck|X=x

快速排序演算法Python實現

快速排序演算法,簡稱快排,是最實用的排序演算法,沒有之一,各大語言標準庫的排序函式也基本都是基於快排實現的。 本文用python語言介紹四種不同的快排實現。 1. 一行程式碼實現的簡潔版本 quick_sort = lambda array: array if le

聚類演算法(一)—— k-means演算法及其改進演算法

      聚類演算法是一種無監督學習,它把資料分成若干類,同一類中的資料的相似性應儘可能地大,不同類中的資料的差異性應儘可能地大。聚類演算法可分為“軟聚類”和“硬聚類”,對於“硬聚類”,樣本中的每一個點都是 100%確定分到某一個類別;而“軟聚類”是指樣本點以一定的概率被分

N數碼問題的啟發式搜尋演算法--A*演算法python實現

一、啟發式搜尋:A演算法 1)評價函式的一般形式 : f(n) = g(n) + h(n) g(n):從S0到Sn的實際代價(搜尋的橫向因子) h(n):從N到目標節點的估計代價,稱為啟發函式(搜尋的縱向因子); 特點: 效率高, 無回溯,   搜尋演算法 OPEN表 : 存放待擴充套件的節點. CLOS

python學習之旅 | k_means演算法python實現

寫在前面 前一段時間看到一篇文章,建議學生時代寫程式碼不要光呼叫庫和複製貼上,而是要儘量每一行程式碼都自己寫。因為以後工作的時候都主要是用別人寫好的東西,就沒有這樣鍛鍊基本功的機會了。 筆者最近入門python,希望能夠通過這些重複造輪子的簡單工作來加強基本功,

最短路徑迪傑斯特拉演算法Python實現

回顧下最短路徑的地傑斯特拉演算法 迪傑斯特拉演算法是求從某一個起點到其餘所有結點的最短路徑,是一對多的對映關係,是一種貪婪演算法 示例: 演算法實現流程思路: 迪傑斯特拉演算法每次只找離起點最近的一個結點,並將之併入已經訪問過結點的集合(以防重複訪問,陷入死迴圈),然後

k-medoid(k中心點)聚類演算法Python實現

k-means演算法有個很大的缺點,就是對孤立點敏感性太高,孤立點即是脫離群眾的點,與眾不同的點,即在顯示中與其他點不是抱在一團的點。 為了體現兩者的不同,我特意溫習了一下知識,在構造初始點的時候,自己定義加入了幾個孤立點,使用k-means演算法跑的效果如下: 一開始的所有點:(可以看出其

機器學習實戰(第二篇)-k-近鄰演算法Python實現

      上一篇幅中,我們介紹了k-近鄰演算法的基本概念、具體的分析步驟和分析方法,本篇中我們將介紹如何通過Python工具實現一個k-近鄰演算法。 1. 準備-使用Python匯入資料     首

樸素貝葉斯分類演算法python實現

1 #==================================== 2 # 輸入: 3 # 空 4 # 輸出: 5 # postingList: 文件列表 6 # classVec: 分類標籤列表 7 #===

樸素貝葉斯演算法python實現

樸素貝葉斯是一種十分簡單的分類演算法,稱其樸素是因為其思想基礎的簡單性,就文字分類而言,他認為詞袋中的兩兩詞之間的關係是相互獨立的,即一個物件的特徵向量中的每個維度都是互相獨立的。這是樸素貝葉斯理論的思想基礎。 樸素貝葉斯分類的正式定義: 設x={}為一個待分類項,而每個a為x的一個特徵屬性有類別集合C={

K-近鄰演算法python實現

內容主要來源於機器學習實戰這本書,加上自己的理解。 1.KNN演算法的簡單描述  K最近鄰(k-Nearest Neighbor,KNN)分類演算法可以說是最簡單的機器學習演算法了。它採用測量不同特徵值之間的距離方法進行分類。它的思想很簡單:如果一個樣本在特徵空間中的k個最

壓縮感知重構演算法之IRLS演算法python實現

IRLS(iteratively reweighted least squares)演算法 (本文給出的程式碼未進行優化,只是為了說明演算法流程 ,所以執行速度不是很快) IRLS(iteratively reweighted least squar