1. 程式人生 > >KNN-機器學習實戰系列(一)

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的範圍之內,方便我們的計算: