KNN及其改進演算法的python實現
一、馬氏距離
我們熟悉的歐氏距離雖然很有用,但也有明顯的缺點。它將樣品的不同屬性(即各指標或各變數)之間的差別等同看待,這一點有時不能滿足實際要求。例如,在教育研究中,經常遇到對人的分析和判別,個體的不同屬性對於區分個體有著不同的重要性。因此,有時需要採用不同的距離函式。
如果用dij表示第i個樣品和第j個樣品之間的距離,那麼對一切i,j和k,dij應該滿足如下四個條件:
①當且僅當i=j時,dij=0
②dij>0
③dij=dji(對稱性)
④dij≤dik+dkj(三角不等式)
顯然,歐氏距離滿足以上四個條件。滿足以上條件的函式有多種,本節將要用到的馬氏距離也是其中的一種。
第i個樣品與第
dij =(x i 一x j)'S-1(x i一xj)
其中,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)還有一種情況,滿足了條件總體樣本數大於樣本的維數,但是協方差矩陣的逆矩陣仍然不存在,比如A(3,4),B(5,6);C(7,8),這種情況是因為這三個樣本在其所處的二維空間平面內共線(如果是大於二維的話,比較複雜)。這種情況下,也採用歐式距離計算。
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:
是第i個近鄰的權值,其中1<i<k,是待測樣本距離第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演算法運用了訓練樣本中的每一個模式,對訓練樣本的每個類,
1 ≤ i ≤ c,在每一個類中找出距離測試樣本距離最近的k個近鄰,假設這k個近鄰的均值為,同樣的,i從1到c變化,我們得到,如果是M當中距離測試樣本最近的,則測試樣本屬於類。
如下圖所示,對於一個兩類的問題,每個類選三個近鄰,類用*表示,類用o表示,“Y”是測試樣本,則Y屬於類。
用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