knn是一个比较简单的机器学习算法,区别于其他算法,它没有显式的模型训练过程,模型直观简单,但是它的预测耗时较长(因为需要与所有训练样本进行举例计算,找出最近的k个训练样本进行投票,所有耗时久)。KNN中有一个比较重要的数据结构—KD树
,用来优化这一过程,KD树在许多这类找最近k个样例的问题
中,都有广泛的应用。
交叉检验
来确定(以k=1为基准)经验规则:k一般低于训练样本数的平方根
投票法没有考虑近邻的距离的远近,距离更近的近邻也许更应该决定最终的分类,所以加权投票法
更恰当一些。
高维度对距离衡量的影响:众所周知当变量数越多,欧式距离的区分能力就越差
。变量值域对距离的影响:值域越大的变量常常会在距离计算中占据主导作用
,因此应先对变量进行标准化
。
在训练集中,有些样本可能是更值得依赖的。
可以给不同的样本施加不同的权重,加强依赖样本的权重,降低不可信赖样本的影响
。
kNN是一种懒惰算法,懒惰的后果:构造模型很简单,但在对测试样本分类的开销大,因为要扫描全部训练样本并计算距离
。
已经有一些方法提高计算的效率,例如压缩训练样本量
等。
浓缩技术(condensing)、
编辑技术(editing)、
当训练样本数量很大时将导致很高的计算开销
。KNN 算法是懒散的分类算法, 对于分类所需的计算都推迟到分类时才进行, 在其分类器中存储有大量的样本向量, 在未知类别样本需要分类时, 再计算和所有存储样本的距离, 对于高维文本向量或样本集规模较大的情况, 其时间和空间复杂度较高
。
在精度下降有限的前提下,降低维度,减少算法的计算量
1) 理论成熟,思想简单,既可以用来做分类也可以用来做回归
2) 可用于非线性分类
3) 训练时间复杂度比支持向量机之类的算法低,仅为O(n)
4) 和朴素贝叶斯之类的算法比,对数据没有假设,准确度高,对异常点不敏感
5) 由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合
6)该算法比较适用于样本容量比较大的类域的自动分类
,而那些样本容量较小的类域采用这种算法比较容易产生误分
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)