《机器学习》之 KNN近邻算法原理及代码

KNN原理浅析及代码实战

Posted by 予以初始 on July 16, 2020

1 介绍

KNN (K Nearest Neighbors) 是经典的机器学习算法之一,可用于分类及回归任务。跟逻辑回归一样,属于有监督学习。不同点是,KNN不是学习相应的权重,而是通过一些统计方法得到预测结果,原理简单,接下来看一下详细介绍。

2 原理

先看个栗子 如果有一群人,身高及性别已知,让你根据身高来预测另一批人的性别。你会怎么做? KNN的做法是,选出与预测目标身高最相似的k个人,然后把这k个人中出现次数最多的性别当做预测值。

原理就是一句话 KNN就是当预测一个新的值x的时候,根据它距离最近的K个点是什么类别来判断x属于哪个类别。 在这里插入图片描述 比如要预测上图绿色方块的类别。当k=3时,选出与其距离最小的三个点,即上图小圆圈内的三个点,两个三角形与一个圆形,所以把出现次数多的三角形作为绿色方块的类别。当k=5时,选出的点即上图大圆圈内的点,此时把出现次数多的圆形作为绿色方块的类别。是不是很简单,接下来看一下KNN需要注意的点。

注意: 1) k的值如何选择? 2) 样本之间的距离如何度量?

解答: 1)细心的小伙伴也注意到了,当k取值不同时,预测的结果也可能是不同 (如上图栗子)。那么k该如何选择?k值是KNN算法的唯一超参数,需要自己调整,找到使KNN精度最高的那个值。k值如果太小,比如k=1,预测结果就是距离最近的那个点的类别,KNN容易过拟合;如果k值太大,比如k=n(整个样本数),预测结果就是所有样本中出现次数最多的那个类别,丧失了分类能力,又容易欠拟合。一般可以在 [10, 20] 区间内进行尝试,具体应根据样本量进行调整。 2) 距离的度量有多种,上图的栗子使用的是二维坐标上的距离,也就是欧式距离。一般的距离度量指标有如下几种: 一范式:(曼哈顿距离) 在这里插入图片描述

二范式:(欧式距离) 在这里插入图片描述 无穷范式: 在这里插入图片描述 一般常用的就是这几种,最常用的就是二范式(欧式距离)。

3 总结

优点: 1 原理简单,易上手; 2 对异常值不敏感,预测效果好。

缺点: 1 对k值的选择比较敏感; 2 时间空间复杂度比较大,k值越大,复杂度越高。

4 代码实现

定义KNN算法类: (代码中加入了充分的注释,方便理解)

import numpy as np
import pandas as pd

class KNN:
    def __init__(self, k):
        self.k = k #超参数

    # 计算两向量的距离(欧式距离)
    def get_distance(self, n1, n2):
        return np.linalg.norm(n1-n2, ord=2) #二范式计算

    # 输入训练集与标签,以及测试集
    def predict(self, X_train, y_train, X_test):
        predict = [] #存放预测结果

        #遍历测试集每个样本(该循环为每个样本预测一个结果并存入predict)
        for test in X_test:
            distances = [] #存放训练集每个样本与该测试样本的距离
            labels = [] #存放距离对应的标签

            #遍历训练集每个样本(该循环计算与每个训练样本的距离,并保存)
            for idx in range(len(X_train)):
                dist = self.get_distance(test, X_train[idx]) #计算测试样本与每个训练样本的距离
                distances.append(dist)
                labels.append(y_train[idx])

            #将距离与标签当做数据框的两列,便于排序与选出数量最多的类别
            res = pd.DataFrame({'distances': distances, 'labels': labels})
            res = res.sort_values('distances')[0:self.k] #排序后取前k个距离及对应类别
            predict.append(res['labels'].mode()[0]) #取类别的众数当做预测结果

        return predict

使用:

from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

train = np.loadtxt('datingTestSet2.txt')
X = train[:, 0:3]  #训练集
y = train[:, -1]   #训练集标签
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) #划分测试集

y_pre = KNN(15).predict(X_train, y_train, X_test)
print(accuracy_score(y_test, y_pre)) #准确率82.5%

训练集地址: datingTestSet2.txt

希望看完此文的你,能够对KNN有个很好的理解。 如果有收获的话,就请给个赞吧~ 感激不尽!