Tensorflow實現knn算法

導言

knn是一個比較簡單的機器學習算法,區別於其他算法,它沒有顯式的模型訓練過程,模型直觀簡單,但是它的預測耗時較長(因爲需要與所有訓練樣本進行舉例計算,找出最近的k個訓練樣本進行投票,所有耗時久)。KNN中有一個比較重要的數據結構—KD樹,用來優化這一過程,KD樹在許多這類找最近k個樣例的問題中,都有廣泛的應用。
 

KNN相關問題

1、k值設定爲多大?

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

2、類別如何判定最合適?

投票法沒有考慮近鄰的距離的遠近,距離更近的近鄰也許更應該決定最終的分類,所以加權投票法更恰當一些。
 

3、如何選擇合適的距離衡量?

高維度對距離衡量的影響:衆所周知當變量數越多,歐式距離的區分能力就越差。變量值域對距離的影響:值域越大的變量常常會在距離計算中佔據主導作用,因此應先對變量進行標準化
 

4、訓練樣本是否要一視同仁?

在訓練集中,有些樣本可能是更值得依賴的。
可以給不同的樣本施加不同的權重,加強依賴樣本的權重,降低不可信賴樣本的影響
 

5、性能問題?

kNN是一種懶惰算法,懶惰的後果:構造模型很簡單,但在對測試樣本分類的開銷大,因爲要掃描全部訓練樣本並計算距離
已經有一些方法提高計算的效率,例如壓縮訓練樣本量等。
 

6、能否大幅減少訓練樣本量,同時又保持分類精度?

濃縮技術(condensing)、
編輯技術(editing)、

 

7.提高分類效率的改進算法

KNN算法的主要缺點

訓練樣本數量很大時將導致很高的計算開銷。KNN 算法是懶散的分類算法, 對於分類所需的計算都推遲到分類時才進行, 在其分類器中存儲有大量的樣本向量, 在未知類別樣本需要分類時, 再計算和所有存儲樣本的距離, 對於高維文本向量或樣本集規模較大的情況, 其時間和空間複雜度較高

優化:特徵降維&模式聚合

在精度下降有限的前提下,降低維度,減少算法的計算量

 

KNN的主要優點有:

1) 理論成熟,思想簡單,既可以用來做分類也可以用來做迴歸

2) 可用於非線性分類

3) 訓練時間複雜度比支持向量機之類的算法低,僅爲O(n)

4) 和樸素貝葉斯之類的算法比,對數據沒有假設,準確度高,對異常點不敏感

5) 由於KNN方法主要靠周圍有限的鄰近的樣本,而不是靠判別類域的方法來確定所屬類別的,因此對於類域的交叉或重疊較多的待分樣本集來說,KNN方法較其他方法更爲適合

6)該算法比較適用於樣本容量比較大的類域的自動分類,而那些樣本容量較小的類域採用這種算法比較容易產生誤分

 

KNN的主要缺點有:

1)計算量大,尤其是特徵數非常多的時候

2)樣本不平衡的時候,對稀有類別的預測準確率低

3)KD樹,球樹之類的模型建立需要大量的內存

4)使用懶散學習方法,基本上不學習,導致預測時速度比起邏輯迴歸之類的算法慢

5)相比決策樹模型,KNN模型可解釋性不強

 

具體實現

參考:https://blog.csdn.net/qq_35170267/article/details/84205585
我使用minst數據集驗證knn的效果

import tensorflow as tf
import numpy as np
import os
from tensorflow.examples.tutorials.mnist import input_data

os.environ['CUDA_VISIBLE_DEVICES'] = '0'

def KNN(Xtrain, Ytrain,Xtest, Ytest,k):
    x_train = tf.placeholder(tf.float64,[None,784])
    test = tf.placeholder(tf.float64,[784])

    # 歐式距離
    # knn = tf.reduce_sum(tf.pow(tf.subtract(x_train,test),2),reduction_indices=1)

    # L1 距離,不要忘記在哪條軸上做索引
    knn = tf.reduce_sum(tf.abs(tf.subtract(x_train,test)),reduction_indices=1)

    with tf.Session() as sess:
        acc = []
        for i in range(len(Xtest)):
            dists = sess.run(knn,feed_dict={x_train:Xtrain,test:Xtest[i]})
            min_dists_idx = dists.argsort()[:k]
            knn_labels = np.array([Ytrain[i] for i in min_dists_idx])
            pred = np.argmax(np.bincount(knn_labels))
            acc.append(pred == Ytest[i])

        accuracy = tf.reduce_mean(tf.cast(acc,dtype=tf.float64))
        print("accuracy: ", sess.run(accuracy))


# 當我們想要求一個數組中出新頻率最多的元素時,numpy類型的數組無法直接求出結果。我們需要先用np.bincount(array)來記錄每個元素出現的次數。
# 注意,它返回值是一個數組,大小是原數組中最大的數的值+1,下標表示原數組中的值。比如 x = np.bincount([2,4,4,1,1,3]),則x=[0,2,1,1,2],表示原數組中,0出現0次,1出現2次,3出現1次……
# 之後我們就可以用np.argmax(x)返回數組x中最大元素的下標,在bincount的返回值中即是最初數組中出現最多次的元素。

if __name__ == "__main__":
    mnist = input_data.read_data_sets("/home/minst_data", one_hot=False)

    Xtrain, Ytrain = mnist.train.next_batch(5000)  # 從數據集中選取5000個樣本作爲訓練集
    Xtest, Ytest = mnist.test.next_batch(200)  # 從數據集中選取200個樣本作爲測試集
    KNN(Xtrain, Ytrain,Xtest, Ytest,5)
發佈了84 篇原創文章 · 獲贊 23 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章