KNN-1算法

K-近邻算法,KNN

概念

K-Nearest Neighbors(KNN):k个最近的邻居,即每个样本都可以用它最接近的k个邻居来代表。

分成5类

最近邻 (k-Nearest Neighbors, KNN) 算法是一种分类算法, 1968年由 Cover和 Hart 提出, 应用场景有字符识别、 文本分类、 图像识别等领域。
该算法的思想是: 一个样本与数据集中的k个样本最相似, 如果这k个样本中的大多数属于某一个类别, 则该样本也属于这个类别。

距离度量

L1 (Manhattan) distance

d 1 ( I 1 , I 2 ) = ∑ p ∣ I 1 p − I 2 p ∣ d1(I1,I2)=\sum_{p}|I_1^p-I_2^p| d1(I1,I2)=pI1pI2p

L2 (Euclidean) distance

d 1 ( I 1 , I 2 ) = ∑ p ( I 1 p − I 2 p ) 2 ) d1(I1,I2)=\sqrt {\sum_{p}(I_1^p -I_2^p)^2)} d1(I1,I2)=p(I1pI2p)2)

选择那个距离是更具具体的数据以及实际意义来定的,在选择时选择效果最好的距离即可

如何选择最佳的K和距离呢

选择最佳的K

第一种想法

只有训练集
在这里插入图片描述

在训练数据中找到最佳的K
最坏的情况是K=1,这个在训练集上总会得到完美的表现,但很有可能出现过拟合的现象。
但是在实际中应该使得K尽可能最大,这样对于在训练集中未出现过的数据分类性能更佳,因为我们不是要我们的方法尽可能拟合训练集,而是在训练集以外的未知数据上表现得更好。

第二种想法

将数据分为训练集和测试集
在训练集上训练好分类器,运用在测试集上,找到在测试集中表现最好的超参数。
在这里插入图片描述
但实际上别这么做,因为此方法给我们的是预估的一种方法,如果遇到全新的数据无法确定其表现如何。

第三种想法

将数据集划分为训练集验证集和测试集

在训练集上训练好分类器,运用在验证集上,找到表现最好的超参数,最后在测试集上做测试
在这里插入图片描述

第四种想法

使用K折交叉验证:

  1. 将数据分成k份,并进行k次训练。每次训练将1份作为验证集,剩下的k-1份作为训练集,k次训练正好每1份都当了一次验证集。

  2. 将每次训练的误差做平均得到平均误差。依据平均误差来调节模型的超参数。

  3. 超参数固定好之后,用完整的数据集来重新训练模型。
    在这里插入图片描述
    对于小数据集是非常有用的,但是在深度学习中并不是经常适用。

距离度量选择

在这里插入图片描述
上述图像分别是原始图像遮盖,下移和变蓝。如果用L1和L2来验证,上述几张图像差异不大计算得到L1和L2的结果一样。在差异很小的情况下,说明了在图像中不用L1和L2距离度量图像的相似性。

小结

在图像分类中,我们从图像的训练集开始,必须预测测试集上的标签。
K邻近分类器基于K个最邻近示例来预测标签
距离度量和K是超参数
使用验证集选择超参数
最后只在测试集上运行一次

代码

import numpy as np
from collections import Counter

class KNearestNeighbor(object):
    """ a kNN classifier with L2 distance """

    def __init__(self):
        pass

    def train(self, X, y):

        self.X_train = X
        self.y_train = y

    def predict(self, X, k=1, num_loops=0):

    if num_loops == 0:
          dists = self.compute_distances_no_loops(X)
    elif num_loops == 1:
          dists = self.compute_distances_one_loop(X)
    elif num_loops == 2:
          dists = self.compute_distances_two_loops(X)
    else:
          raise ValueError('Invalid value %d for num_loops' % num_loops)

    return self.predict_labels(dists, k=k)

  def compute_distances_two_loops(self, X):

    num_test = X.shape[0]
    num_train = self.X_train.shape[0]
    dists = np.zeros((num_test, num_train))
    for i in range(num_test):#测试样本的循环
          for j in range(num_train):#训练样本的循环            
        #dists[i,j]=np.sqrt(np.sum(np.square(self.X_train[j,:]-X[i,:])))
        dists[i,j]=np.linalg.norm(X[i]-self.X_train[j])
        #np.square是针对每个元素的平方方法  
    return dists

  def compute_distances_one_loop(self, X):

    num_test = X.shape[0]
    num_train = self.X_train.shape[0]
    dists = np.zeros((num_test, num_train))
    for i in range(num_test):
      #dists[i,:] = np.sqrt(np.sum(np.square(self.X_train-X[i,:]),axis = 1))
      dists[i,:]=np.linalg.norm(X[i,:]-self.X_train[:],axis=1)
    return dists

  def compute_distances_no_loops(self, X):
    num_test = X.shape[0]
    num_train = self.X_train.shape[0]
    dists = np.zeros((num_test, num_train)) 
    """
    mul1 = np.multiply(np.dot(X,self.X_train.T),-2)   
    sq1 = np.sum(np.square(X),axis=1,keepdims = True)   
    sq2 = np.sum(np.square(self.X_train),axis=1)   
    dists = mul1+sq1+sq2    
    dists = np.sqrt(dists) 
    """
    dists += np.sum(np.multiply(X,X),axis=1,keepdims = True).reshape(num_test,1)
    dists += np.sum(np.multiply(self.X_train,self.X_train),axis=1,keepdims = True).reshape(1,num_train)
    dists += -2*np.dot(X,self.X_train.T)
    dists = np.sqrt(dists) 

    return dists

  def predict_labels(self, dists, k=1):

    num_test = dists.shape[0]
    y_pred = np.zeros(num_test)
    for i in range(num_test):

        closest_y = []
        closest_y = self.y_train[np.argsort(dists[i, :])[:k]].flatten()
        c = Counter(closest_y)
        y_pred[i]=c.most_common(1)[0][0]
        """
        closest_y=self.y_train[np.argsort(dists[i, :])[:k]]      
        y_pred[i] = np.argmax(np.bincount(closest_y))
        """

    return y_pred

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值