K近邻法(KNN)

K近邻法(KNN)

什么是KNN?

​ KNN的英文全称叫K-Nearest Neighbor,翻译过来就是K邻近算法。具体的来说就是根据你旁边的物品来决定你是什么物体。

​ 举个例子,我们现在要分类豆子,一共有两类黄豆和绿豆,如果你拿起的豆子旁边都是黄豆,那么根据KNN算法,你手里的豆子就是黄豆;当然如果你拿起豆子旁边是绿豆,那么KNN也会认为你拿起的是绿豆。

KNN的算法流程

  1. 计算测试数据与各个训练数据之间的距离;
  2. 按照距离的递增关系进行排序;
  3. 选取距离最小的K个点;
  4. 确定前K个点所在类别的出现频率;
  5. 返回前K个点中出现频率最高的类别作为测试数据的预测分类。

KNN有什么用?具体应用在哪些方面?

​ 知道了KNN是什么之后,我们会容易想到它可以用来解决分类问题,上面的豆子就是二分类问题,当我们增加豆子的种类时,它又会变成多分类问题。

​ 具体来说KNN可以应用的哪些方面?

​ 先给出结论,KNN可以用于分类,也可以用于回归。

​ 分类比较好理解,因为上面豆子的例子就是分类问题,但是回归怎么说?回归和分类有什么区别?

​ 回归任务的目标是预测连续值。分类是预测一个离散的值。

​ 那么KNN怎么做回归任务?

​ 使用kNN计算某个数据点的预测值时,模型会从训练数据集中选择离该数据点最近的k个数据点,并且把他们的y值取均值,把该均值作为新数据点的预测值

​ 举个例子:就拿鸢尾花数据集来说,可以使用KNN通过前三个的特征值,预测第四个特征值

根据前三个特征找出新数据的k个最近邻,将这些邻居的第四个特征的平均值赋给该数据,就可以得到该数据对应第四个特征的值。

影响KNN的因素有哪些?

​ 根据上面豆子的例子可以看出,我K值的选取会影响结果(K值就是选取几个邻居作为参考);判别的规则,也就是说选取的邻居中几个黄豆,我才认为我手里拿的是黄豆;其实距离的度量也会影响,选取不同的距离,会影响算法的结果

K值的选择:

​ K值过小,邻域小,预测结果对邻域里的训练数据非常敏感,容易造成过拟合。

​ K值过大,邻域大,距离远的训练数据也会对预测结果产生影响,极端值会影响预测结果。

​ 那么怎么选取合适的K值呢?

交叉验证

​ 具体实现步骤:

  1. 将数据集分成K(折)段,并将每段拆分成训练集和验证集
  2. 遍历所有指定的K(KNN)值对每段进行KNN模型训练
  3. 将每段评估的准确率进行相加,并除以K(折),得出KNN模型为某K值时的最终准确率
  4. 最终比较所有K(KNN)值的最终准确率,最高说明是这几个K(KNN)值中最合适的
判别的规则

​ k 近邻法中的分类决策规则往往是多数表决,即由待分类样本的 k 个邻近分类样本中的多数类决定它的类。

​ 回归通常是直接取平均。

距离度量

​ 距离的度量描述了测试样本与训练样本的临近程度,这个临近程度就是K个样本选择的依据,在KNN算法中,如果特征是连续的,那么距离函数一般用曼哈顿距离(L1距离)或欧氏距离(L2距离),如果特征是离散的,一般选用汉明距离。

KNN的问题

​ 从上面的豆子例子中可以看出,KNN要保存训练数据,这也就意味着如果训练集过大,算法将不可用。

​ 而且如何最快的找到需要的训练集也成为了一个问题,对于这个问题前人提出了KD树算法

怎么实现KNN?

下面给出python实现,

import numpy as np

#生成数据
def create_data(nums):
    data1 = np.random.randint(42,size=(nums,3))
    data2 = np.random.randint(0,10,size=(nums,1))
    data = np.hstack((data1,data2))
    columns = ['A','B','C','label']
    df = pd.DataFrame(data,columns=columns)
    df.to_csv('./data.csv')
    
    
#载入数据
def dataloader(path):
    data = pd.read_csv(path)
    train_data = data.iloc[:,-1].to_numpy()
    train_label = data.iloc[:,-1].to_numpy()
    return train_data,train_label

#计算距离
def distance(x1,x2):
    return np.sqrt(np.sum(np.square(x1 - x2)))



def getclose(train_data,train_label,x,k):
    distance_list = [0] * len(train_label) 
    for i in range(len(train_data)):
        x1 = train_data[i]
        curdist = distance(x1,x)
        distance_list.append(curdist)

    K_list = np.argsort(np.array(distance_list))[:k]
    label_list = [0]*10
    for index in K_list:
        label_list[int(train_label[index])] += 1

    return label_list.index(max(label_list))


if __name__ == "__main__":
    create_data(42)
    train_data,train_label = dataloader('./data.csv')
    x = np.array([1,2,3,4])
    result = getclose(train_data,train_label,x,5)

你如果使用上述代码预测一个数组的label,大概率是不准的,因为是随机数。其实不如将上面的数据换成mnist数据集,这样就会有点用,起码可以预测准一点。思路都是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值