KNN-機器學習實戰系列(一)
開門見山,本文單說KNN:
作為機器學習實戰書籍介紹的第一個演算法,有一些值得說道的地方:
1:什麼是KNN?
機器學習的一些基本知識和概念不加敘述了,直接給出KNN的白話定義:給定M個樣本,每個樣本均有N個數字衡量的屬性,而每個樣本均帶有自身的標籤:
這裡,為什麼需要數字化定義屬性呢?這方便了我們衡量指標的計算,我們可以使用距離這一可用數學表示式實現的概念,來闡述何謂近鄰。
而KNN,英文名:k-Nearest Neigbhors :稱作K近鄰演算法,每次來一個新的樣本,就可以通過從M個樣本中,找出K個最近的樣本,通過這K個樣本的屬性來判別新樣本的類別:
可以看出,KNN屬於監督類學習演算法,對其提供支援的樣本,都是標記好的樣本;
2:演算法角度的實現:
from numpy import *
def createDataSet():
group = array([[1.0,1.1 ],[1.0,1.0],[0,0], [0,0.1]])
labels = ['A','A','B','B']
return group,labels
group,labels = createDataSet()
該段程式碼,負責樣本集合的生成,淺顯易懂,不多說:
這裡,給出的樣本非常簡單,而實際上來說,我們在使用該演算法的過程中,樣本都會比較複雜,屬性也會比較多,這些在本文不予涉及,生成樣本的方式是多種多樣的,我們這裡要做的,是直接對合規的樣本進行操作:
接下來是主題邏輯:
def classify0(intX,dataSet,labels,k): # 獲取樣本的總數,比如樣本是N行 dataSetSize = dataSet.shape[0] # tile方式,會生成N行與待測樣本完全一致的資料集 tiles = tile(intX, (dataSetSize,1)) # 取差值,這就是python的簡便之處了,一句話求取出所有的(x-x1)和(y-y1) diffMat = tiles - dataSet # 對於所有的元素進行平方操作 sqDiffMat = diffMat ** 2 # 平方操作加起和,得到距離 sqDistances = sqDiffMat.sum(axis=1) # 距離排序 sortedDistIndicies = sqDistances.argsort() # 取出距離最小的K個點,記錄標籤 classCount = {} for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] classCount[voteIlabel] = classCount.get(voteIlabel,0)+1 # 檢視這K個點中,哪種類別比較多 sortedClassCount = sorted(classCount.iteritems(),key = operator.itemgetter(1),reverse=True) return sortedClassCount[0][0];
總體思想就是這樣:很簡單,很好理解,用一句古話說就是:近朱者赤,近墨者黑。
3:我對該演算法的一些理解:
KNN算是機器學習之初誕生的一些老演算法了,其效能還算不錯,當然同時也是有缺陷的:
首先,其缺陷在於需要每次樣本都要遍歷一次所有的資料,這個計算量相對比較大,如果樣本集合已經有百萬,甚至是千萬那麼大,我們每次還要為一個樣本去計算數百萬,甚至是數千萬次,投入和產出明顯是不成正比的:
個人感覺,這裡其實可以用堆排序的方法來做優化,設定一個K元素大小的最小堆,來儘可能減小演算法的複雜度:
其二,這裡的K設定是很關鍵的,假如說K太小,可能很少的元素就決定了新樣例的樣本,這是不合理的,如果K太大,會導致計算和排序比較麻煩,所以需要從中調和:
其三,如果某個屬性值本身比較大,可能會導致在距離計算的時候,導致該屬性佔據的份額比較大,這是有問題的,所以可通過歸一化進行處理,將資料的計算都整合在0-1的範圍之內,方便我們的計算: