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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章