KNN算法介绍

· · 算法·理论

KNN算法介绍

简介

KNN(k-Nearest Neighbor,k 最邻近算法)分类算法,是最简单的机器学习算法之一。这可不是什么租房找邻居的算法,而是判断一种数据属于哪个类别的算法。

算法思路

该方法的思路是:在特征空间中,如果一个样本附近的 k 个最近(即特征空间中最邻近)样本的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。

算法流程

KNN 算法包括以下 4 个步骤:

  1. 准备数据,对数据进行预处理。
  2. 计算未知样本到其他每个样本的距离。
  3. 对距离进行排序,然后选择出距离最小的 k 个点。
  4. k 个点所属的类别进行比较,将测试样本点归入 k 个点中占比高的那一类。

用法举例

机器在识别一样物品的时候,不会像人类一样,“觉得”这个物品“像”什么,它需要通过数据的计算和比较来识别。

我们要选择合适的比较对象,比如识别动物是狮子还是大象,我们就要比较它们的身长、身高、颜色等,而不是比较它们眼睛、腿的数量。

让我们就用识别数字是 1 还是 7 来举个例子。

计算像素数

17 的区别就在于 7 的上半部分占的像素会多一些,所以我们首先可以画一个 10 \times 10 的格子,并写出几个不同的 17 样本,并计算它们上半部分和下半部分占的像素数。

样本举例:

1:上半部分 7 个像素,下半部分 6 个像素。

7:上半部分 10 个像素,下半部分 5 个像素。

绘制坐标系

接着,我们可以把这些样本绘制在坐标系上,再绘制出一个需要分类的数据。x 轴表示上半部分像素数,y 轴表示下半部分像素数。

蓝点:1

红点:7

绿点:未知数据。

计算距离

最后,我们运算未知数据到每一个点的距离。我们一般使用直线距离。

$$\sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}$$ |样本|坐标|距离| |:-:|:-:|:-:| |蓝 $1$|$(6,5)$|$1.00$| |蓝 $2$|$(7,6)$|$1.00$| |蓝 $3$|$(7,7)$|$1.41$| |红 $1$|$(9,4)$|$3.61$| |红 $2$|$(9,5)$|$3.16$| |红 $3$|$(10,5)$|$4.12$| 排序后就是: |样本|坐标|距离| |:-:|:-:|:-:| |蓝 $2$|$(7,6)$|$1.00$| |蓝 $3$|$(6,5)$|$1.00$| |蓝 $1$|$(7,7)$|$1.41$| |红 $2$|$(9,5)$|$3.16$| |红 $3$|$(9,4)$|$3.61$| |红 $1$|$(10,5)$|$4.12$| ### 分类并得出结论 我们需要选取前 $k$ 个邻居($k$ 为奇数)来分类。 |$k$ 的值|蓝点数|红点数| |:-:|:-:|:-:| |$1$|$1$|$0$| |$3$|$3$|$0$| |$5$|$3$|$2$| 所以我们得出结论:未知数据是 `1`。 ## 简单编程实现 ``` #include <iostream> #include <cmath> #include <algorithm> using namespace std; struct Point // 一个样本点 { char C; // 分类 int X; // X坐标 int Y; // Y坐标 double Dis; // 距离 }; double dis(int disx1, int disy1, int disx2, int disy2) // 算直线距离 { return sqrt((disx1 - disx2) * (disx1 - disx2) + (disy1 - disy2) * (disy1 - disy2)); } bool cmp(Point A, Point B) // 排序 { return A.Dis < B.Dis; } Point P[200000]; int main() { int n; // 一种类别的样本数 int k; // 最近邻居数(默认为奇数) int x, y; // 未知数据坐标 int a, b; //最小的 k 个样本中不同类别的数量 cin >> n >> k; for (int i = 0; i < n; ++i) // 输入 { P[i].C = 'A'; cin >> P[i].X >> P[i].Y; } for (int i = 0; i < n; ++i) { P[i].C = 'B'; cin >> P[i].X >> P[i].Y; } cin >> x >> y; for (int i = 0; i < 2 * n; ++i) // 算距离 { P[i].Dis = dis(P[i].X, P[i].Y, x, y); } sort(P, P + n, cmp); // 排序 for (int i = 0; i < k; ++i) // 分类 { if (P[i].C == 'A') { a += 1; } else { b += 1; } } if (a > b) // 输出 { cout << 'A'; } else { cout << 'B'; } return 0; } ``` ## 优点和缺点 ### 优点 - 思路简单。 - 容易实现。 - 无需训练。 ### 缺点 - 计算量大。 - 计算复杂度高。 - 内存要求高。 ###### 1.10:图床使用有误,图片被删除无法显示。修改格式和更新图片后重新提交申请。 ## 猜你想看 [我的专栏](https://www.luogu.com.cn/user/1378097#article)