KNN算法

1、介紹

KNN算法又稱爲k近鄰分類(k-nearest neighbor classification)算法。KNN是一種監督類型的分類算法,通過計算新數據與訓練數據特徵值之間的距離,然後選取K(K>=1)個距離最近的鄰居進行分類判斷(投票法)或者回歸。

KNN算法的過程爲:

  1. 算距離:選擇一種距離計算方式, 通過數據所有的特徵計算新數據與已知類別數據集中的數據點的距離
  2. 找鄰居:按照距離遞增次序進行排序,選取與當前距離最小的k個點
  3. 做分類或迴歸:對於離散分類,返回k個點出現頻率最多的類別作預測分類;對於迴歸則返回k個點的加權值作爲預測值

2、重點

1)數據的所有特徵都要做可比較的量化。

若是數據特徵中存在非數值的類型,必須採取手段將其量化爲數值。舉個例子,若樣本特徵中包含顏色(紅黑藍)一項,顏色之間是沒有距離可言的,可通過將顏色轉換爲灰度值來實現距離計算。另外,樣本有多個參數,每一個參數都有自己的定義域和取值範圍,他們對distance計算的影響也就不一樣,如取值較大的影響力會蓋過取值較小的參數。爲了公平,樣本參數必須做歸一化。

2)選擇適合的計算距離函數

距離的定義有很多,如歐氏距離、餘弦距離、漢明距離、曼哈頓距離等等。一般情況下,選歐氏距離作爲距離度量,但是這是隻適用於連續變量。在文本分類這種非連續變量情況下,漢明距離可以用來作爲度量。通常情況下,如果運用一些特殊的算法來計算度量的話,K近鄰分類精度可顯著提高,如運用大邊緣最近鄰法或者近鄰成分分析法。

3)確定K的值

K是一個自定義的常數,K的值也直接影響最後的估計,一種選擇K值得方法是使用 cross-validate(交叉驗證)誤差統計選擇法。交叉驗證的概念之前提過,就是數據樣本的一部分作爲訓練樣本,一部分作爲測試樣本,比如選擇95%作爲訓練樣本,剩下的用作測試樣本。通過訓練數據訓練一個機器學習模型,然後利用測試數據測試其誤差率。 cross-validate(交叉驗證)誤差統計選擇法就是比較不同K值時的交叉驗證平均誤差率,選擇誤差率最小的那個K值。例如選擇K=1,2,3,… , 對每個K=i做100次交叉驗證,計算出平均誤差,然後比較、選出最小的那個。

3、補充

1)加權KNN

以上是KNN的基本算法,有一個問題就是該算法給所有的近鄰分配相等的權重,這個還可以這樣改進,就是給更近的鄰居分配更大的權重(你離我更近,那我就認爲你跟我更相似,就給你分配更大的權重),而較遠的鄰居的權重相應地減少,取其加權平均。需要一個能把距離轉換爲權重的函數,gaussian函數是一個比較普遍的選擇。

def gaussian(dist,sigma=10.0):
    """Input a distance and return it's weight"""
    weight = np.exp(-dist**2/(2*sigma**2))
    return weight

2)交叉驗證

Holdout Method(保留)

方法:將原始數據隨機分爲兩組,一組做爲訓練集,一組做爲驗證集,利用訓練集訓練分類器,然後利用驗證集驗證模型,記錄最後的分類準確率爲此Hold-OutMethod下分類器的性能指標.。Holdout Method相對於K-fold Cross Validation 又稱Double cross-validation ,或相對K-CV稱 2-fold cross-validation(2-CV)
優點:好處的處理簡單,只需隨機把原始數據分爲兩組即可
缺點:嚴格意義來說Holdout Method並不能算是CV,因爲這種方法沒有達到交叉的思想,由於是隨機的將原始數據分組,所以最後驗證集分類準確率的高低與原始數據的分組有很大的關係,所以這種方法得到的結果其實並不具有說服性.(主要原因是 訓練集樣本數太少,通常不足以代表母體樣本的分佈,導致 test 階段辨識率容易出現明顯落差。此外,2-CV 中一分爲二的分子集方法的變異度大,往往無法達到「實驗過程必須可以被複制」的要求。)

K-fold Cross Validation(k摺疊)

方法:作爲Holdout Methon的演進,將原始數據分成K組(一般是均分),將每個子集數據分別做一次驗證集,其餘的K-1組子集數據作爲訓練集,這樣會得到K個模型,用這K個模型最終的驗證集的分類準確率的平均數作爲此K-CV下分類器的性能指標.K一般大於等於2,實際操作時一般從3開始取,只有在原始數據集合數據量小的時候纔會嘗試取2. 而K-CV 的實驗共需要建立 k 個models,並計算 k 次 test sets 的平均辨識率。在實作上,k 要夠大才能使各回合中的 訓練樣本數夠多,一般而言 k=10 (作爲一個經驗參數)算是相當足夠了。
優點:K-CV可以有效的避免過學習以及欠學習狀態的發生,最後得到的結果也比較具有說服性.
缺點:K值選取上

Leave-One-Out Cross Validation(留一)

方法:如果設原始數據有N個樣本,那麼留一就是N-CV,即每個樣本單獨作爲驗證集,其餘的N-1個樣本作爲訓練集,所以留一會得到N個模型,用這N個模型最終的驗證集的分類準確率的平均數作爲此下LOO-CV分類器的性能指標.
優點:相比於前面的K-CV,留一有兩個明顯的優點:
a.每一回閤中幾乎所有的樣本皆用於訓練模型,因此最接近原始樣本的分佈,這樣評估所得的結果比較可靠。
b. 實驗過程中沒有隨機因素會影響實驗數據,確保實驗過程是可以被複制的.
缺點:計算成本高,因爲需要建立的模型數量與原始數據樣本數量相同,當原始數據樣本數量相當多時,LOO-CV在實作上便有困難幾乎就是不顯示,除非每次訓練分類器得到模型的速度很快,或是可以用並行化計算減少計算所需的時間。

Holdout method方法的想法很簡單,給一個train_size,然後算法就會在指定的比例(train_size)處把數據分爲兩部分,然後返回。

def my_train_test_split(X,y,train_size=0.95,shuffle=True):
    """
    Input X,y, split them and out put X_train, X_test; y_train, y_test.
    Example:
    ------
    X = np.array([[0, 1],[2, 3],[4, 5],[6, 7],[8, 9]])
    y = np.array([0, 1, 2, 3, 4])
    Then
    X_train = np.array([[4, 5],[0, 1],[6, 7]])
    X_test = np.array([[2, 3],[8, 9]])
    y_train = np.array([2, 0, 3])
    y_test = np.array([1, 4])
    """
    order = np.arange(len(y))
    if shuffle:
        order = np.random.permutation(order)
    border = int(train_size*len(y))
    X_train, X_test = X[:border], X[border:]
    y_train, y_test = y[:border], y[border:]
    return X_train, X_test, y_train, y_test

K folds算法是把數據分成k份,進行k此循環,每次不同的份分別來充當測試組數據。但是注意,該算法不直接操作數據,而是產生一個迭代器,返回訓練和測試數據的索引。看docstring裏的例子應該很清楚。

  """
    K-Folds cross validation iterator.
    Provides train/test indices to split data in train test sets. Split dataset 
    into k consecutive folds (without shuffling by default).
    Each fold is then used a validation set once while the k - 1 remaining fold form the training set.
    Example:
    ------
    X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
    y = np.array([1, 2, 3, 4])
    kf = KFold(4, n_folds=2,false)
    for train_index, test_index in kf:
        X_train, X_test = X[train_index], X[test_index]
        y_train, y_test = y[train_index], y[test_index]
        print("TRAIN:", train_index, "TEST:", test_index)
    TRAIN: [2 3] TEST: [0 1]
    TRAIN: [0 1] TEST: [2 3]
    """
def KFold(n,n_folds=5,shuffe=False):
    idx = np.arange(n)
    if shuffe:
        idx = np.random.permutation(idx)
    fold_sizes = (n // n_folds) * np.ones(n_folds, dtype=np.int) # folds have size n // n_folds
    fold_sizes[:n % n_folds] += 1 # The first n % n_folds folds have size n // n_folds + 1
    current = 0
    for fold_size in fold_sizes:
        start, stop = current, current + fold_size
        train_index = list(np.concatenate((idx[:start], idx[stop:])))
        test_index = list(idx[start:stop])
        yield train_index, test_index
        current = stop # move one step forward

評價算法
首先我們用一個函數評價算法,給定訓練數據與測試數據,計算平均的計算誤差,這是評價算法好壞的重要指標。

def test_algo(alg,X_train,X_test,y_train,y_test,kn=3):
    error = 0.0
    for i in range(len(y_test)):
        guess = alg(X_train,y_train,X_test[i],kn=kn)
        error += (y_test[i] - guess)**2
    return error/len(y_test)

參考博客:
http://www.jianshu.com/p/48d391dab189
http://www.th7.cn/Program/Python/201412/332782.shtml

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章