k近鄰(kNN)

1、算法概述算法

一、kNN算法又稱爲k近鄰分類(k-nearest neighbor classification)算法。 最簡單平凡的分類器也許是那種死記硬背式的分類器,記住全部的訓練數據,對於新的數據則直接和訓練數據匹配,若是存在相同屬性的訓練數據,則直接用它的分類來做爲新數據的分類。這種方式有一個明顯的缺點,那就是極可能沒法找到徹底匹配的訓練記錄。app

kNN算法則是從訓練集中找到和新數據最接近的k條記錄,而後根據他們的主要分類來決定新數據的類別。該算法涉及3個主要因素:訓練集、距離或類似的衡量、k的大小。ide

二、表明論文 Discriminant Adaptive Nearest Neighbor Classification Trevor Hastie and Rolbert Tibshirani IEEE TRANSACTIONS ON PAITERN ANALYSIS AND MACHINE INTELLIGENCE, VOL. 18, NO. 6, JUNE 1996 http://www.stanford.edu/~hastie/Papers/dann_IEEE.pdf性能

三、行業應用 客戶流失預測、欺詐偵測等(更適合於稀有事件的分類問題)學習

2、算法要點測試

一、指導思想 kNN算法的指導思想是「近朱者赤,近墨者黑」,由你的鄰居來推斷出你的類別。idea

計算步驟以下: 1)算距離:給定測試對象,計算它與訓練集中的每一個對象的距離 2)找鄰居:圈定距離最近的k個訓練對象,做爲測試對象的近鄰 3)作分類:根據這k個近鄰歸屬的主要類別,來對測試對象分類rest

二、距離或類似度的衡量 什麼是合適的距離衡量?距離越近應該意味着這兩個點屬於一個分類的可能性越大。 覺的距離衡量包括歐式距離、夾角餘弦等。 對於文本分類來講,使用餘弦(cosine)來計算類似度就比歐式(Euclidean)距離更合適。code

三、類別的斷定 投票決定:少數服從多數,近鄰中哪一個類別的點最多就分爲該類。 加權投票法:根據距離的遠近,對近鄰的投票進行加權,距離越近則權重越大(權重爲距離平方的倒數)orm

3、優缺點

一、優勢 簡單,易於理解,易於實現,無需估計參數,無需訓練 適合對稀有事件進行分類(例如當流失率很低時,好比低於0.5%,構造流失預測模型) 特別適合於多分類問題(multi-modal,對象具備多個類別標籤),例如根據基因特徵來判斷其功能分類,kNN比SVM的表現要好

二、缺點 懶惰算法,對測試樣本分類時的計算量大,內存開銷大,評分慢 可解釋性較差,沒法給出決策樹那樣的規則。

4、常見問題

一、k值設定爲多大? k過小,分類結果易受噪聲點影響;k太大,近鄰中又可能包含太多的其它類別的點。(對距離加權,能夠下降k值設定的影響) k值一般是採用交叉檢驗來肯定(以k=1爲基準) 經驗規則:k通常低於訓練樣本數的平方根

二、類別如何斷定最合適? 投票法沒有考慮近鄰的距離的遠近,距離更近的近鄰也許更應該決定最終的分類,因此加權投票法更恰當一些。

三、如何選擇合適的距離衡量? 高維度對距離衡量的影響:衆所周知當變量數越多,歐式距離的區分能力就越差。 變量值域對距離的影響:值域越大的變量經常會在距離計算中佔據主導做用,所以應先對變量進行標準化。

四、訓練樣本是否要一視同仁? 在訓練集中,有些樣本多是更值得依賴的。 能夠給不一樣的樣本施加不一樣的權重,增強依賴樣本的權重,下降不可信賴樣本的影響。

五、性能問題? kNN是一種懶惰算法,平時很差好學習,考試(對測試樣本分類)時才臨陣磨槍(臨時去找k個近鄰)。 懶惰的後果:構造模型很簡單,但在對測試樣本分類地的系統開銷大,由於要掃描所有訓練樣本並計算距離。 已經有一些方法提升計算的效率,例如壓縮訓練樣本量等。

六、可否大幅減小訓練樣本量,同時又保持分類精度? 濃縮技術(condensing) 編輯技術(editing)

# -*- coding:utf-8 -*-

import numpy
from collections import Counter

# 訓練集
TRAIN_SET = [
    [numpy.array([1.0, 0.9]), "A"],
    [numpy.array([1.0, 1.0]), "A"],
    [numpy.array([0.1, 0.2]), "B"],
    [numpy.array([0.0, 0.1]), "B"]
]


# 歸一化夾角餘弦相關度(距離越小,值越大)
def cos_dist_sim(A, B):
    A = numpy.mat(A)
    B = numpy.mat(B)
    num = float(A * B.T)
    denom = numpy.linalg.norm(A) * numpy.linalg.norm(B)
    cos = num / denom  # 餘弦值
    sim = 0.5 + 0.5 * cos  # 歸一化
    return sim


# 歸一化歐氏距離相關度(距離越小,值越大)
def euc_dist_sim(A, B):
    dist = numpy.linalg.norm(A - B)  # 歐氏距離
    sim = 1 / (1 + dist)  # 歸一化
    return sim


def knn_classify(X, train_set, k):
    # 計算距離相關度
    ds = []
    for D, label in train_set:
        ds.append((cos_dist_sim(X, D), label))

    # 相關度逆序
    ds.sort(key=lambda x: x[0], reverse=True)

    # 選取相關度最大的k個點
    max_k_ds = ds[:k]

    # 統計k個點所在類別的出現頻率
    counter = Counter([l[1] for l in max_k_ds]).most_common()
    return counter


print knn_classify(numpy.array([1.2, 1.0]), TRAIN_SET, 3)
相關文章
相關標籤/搜索