5. K近邻算法(KNN)原理与实战详解

1 介绍

上一章节我们通过逻辑回归的方式实现了对数据的分类,本章节我们更进一步,学习如何使用算法根据已有的分类数据对未知数据进行分类预测。

而K近邻算法(KNN)便是最简单且实用的一种方法,是由最近邻算法(NN)推广而来的。

最近邻算法原理相当简单,就是计算未知点到各个已经分类之间的距离,哪个距离最短、或者根据其它标准,就能对未知点进行分类。

image.png

比如上图中,前三个X点代表已知的类型,那么对于未知的四,就可以通过分别计算它到其它三个点之间的距离来判断它的类型,距离谁更近,那么就预测它是什么类型。

但最近邻算法太过于绝对了,它只判断了哪个类别距离它最近、会导致分类效果不好。

而K近邻算法便是找出距离未知数据点最近的k个相邻样本,再根据这K个样本综合判断其类型。

2 距离计算

从上面我们已经了解到了,K近邻算法的关键就在于求点到点之间的距离,所以这里我们先来学习一下基本的距离算法。

而最常用的距离公式便是:曼哈顿距离欧式距离

这里我们以简单的二维数据点为例子,多维实际上也是在其上推演的,本质没区别。

假设我们有两个点:(x1,y1)(x_1,y_1)(x2,y2)(x_2,y_2)

那么曼哈顿距离指的就是:x1x2+y1y2|x_1-x_2|+|y_1-y_2|,也就是每个维度坐标差值的绝对值之和,它相当于求的是各个维度上两点的直线距离。

而欧式距离则更加符合我们的直觉,它求的是空间直线距离:d=(x1x2)2+(y2y2)2d=\sqrt{(x_1-x_2)^2+(y_2-y_2)^2},也就是每个维度坐标差值的平方和、最后开根号,实际上就是直角三角形的斜边长度计算公式。

将上面两个公式写为python代码如下:

def d_man(x, y):
    d = np.sum(np.abs(x - y))
    return d

def d_euc(x, y):
    d = np.sqrt(np.sum(np.square(x - y)))
    return d

注意这两个公式接收的是向量数据,里面是所有维度的值,逻辑是一样的。

3 K近邻算法实现

有了距离计算的基础之后,我们再来看看K近邻算法(KNN)的原理。

对于KNN算法来说,步骤实际上都是固定的、有以下四步:

image.png

  1. 数据准备:通过数据清洗、处理,将其整理为向量,使其可以用来计算距离。
  2. 计算距离:计算测试数据与训练数据之间的距离
  3. 寻找邻居:找到与测试数据最近的K个训练数据
  4. 决策分类:根据规则,通过K个数据得到测试数据的类型。

首先是数据准备:

import numpy as np
import matplotlib.pyplot as plt


def gen_data():
    features = np.array(
        [
            [2.9, 3.3],
            [3.0, 2.7],
            [3.2, 2.9],
            [2.9, 2.7],
            [2.8, 3.4],
            [3.2, 3.3],
            [3.2, 3.5],
            [3.5, 2.9],
            [3.9, 3.6],
            [3.4, 3.3],
        ]
    )
    labels = ["A", "A", "A", "A", "A", "B", "B", "B", "B", "B"]
    return features, labels


features, labels = gen_data()

x_feature = list(map(lambda x: x[0], features))  # 取出每个数据的x特征值组成新列表
y_feature = list(map(lambda y: y[1], features)) # 取出每个数据的Y特征值组成新列表

plt.scatter(x_feature[:5], y_feature[:5], c="b")  # 在画布上绘画出"A"类标签的数据点
plt.scatter(x_feature[5:], y_feature[5:], c="g")# 在画布上绘画出"B"类标签的数据点
plt.scatter([3.2], [3.2], c="r", marker="x")  # 待测试点的坐标为 [3.2,3.2]

plt.show()

运行效果如下:

image.png

其中前五个点与后五个点分别为两组数据,中间的x便是要进行预测分类的数据。

有了数据之后,然后我们就可以开始计算所有点到测试点之间的距离、并进行排序:

test = [3.2, 3.2]

dist = []
for i in range(len(features)):
    dist.append((labels[i], d_euc(test, features[i])))

dist.sort(key=lambda x: x[1])

有了所有点的距离后,假设选择K为5,使用多数表决的方式,也就是选择距离测试样本点最近的5个点,哪种类型最多、就认为测试数据是哪种类型:

k_distance = dist[:5]
a_num = 0
b_num = 0
for i in k_distance:
    if i[0] == "A":
        a_num += 1
    else:
        b_num += 1
作者:余识
全部文章:0
会员文章:0
总阅读量:0
c/c++pythonrustJavaScriptwindowslinux