K近邻法(KNN)

1、KNN算法简介

  KNN(K-Nearest Neighbor)算法即K最邻近算法,是实现分类器中比较简单易懂的一种分类算法。K临近之所以简单是因为它比较符合人们直观感受,即人们在观察事物,对事物进行分类的时候,人们最容易想到的就是谁离那一类最近谁就属于哪一类,即俗话常说的“近朱者赤,近墨者黑”,人们自然而然地把这种观察方式延伸到数据分类处理领域。K-NN算法就是基于欧几里得距离推断事物类别的一种实现方法。

这里写图片描述

2、距离度量

这里写图片描述

  由图可知,p=1时与原点的Lp距离为1的点的图形是菱形,p=2是圆形。

3、KNN算法的思想

  KNN算法假设给定的训练集中的实例都已经分好类了,对于新的实例,根据离它最近的k个训练实例的类别来预测它的类别。即这k个实例大多数属于某个类别则该实例就属于某个类别。比如k为5,离新实例a最近的5个样本的情况为,3个样本属于A类,1个样本属于B类,一个样本属于C类,那么新实例a属于A类。由此也说明了KNN算法的结果很大程度取决于K的选择。

这里写图片描述

4、KNN算法流程

(1)线性扫描

1. 计算测试数据与各个训练数据之间的距离;

2. 按照距离的递增关系进行排序;

3. 选取距离最小的K个点;

4. 确定前K个点所在类别的出现频率;

5. 返回前K个点中出现频率最高的类别作为测试数据的预测分类。

代码实现:

#include <iostream>
#include <vector>
#include <Eigen/Dense>
#include <cmath>
#include <algorithm>
#include <map>
#include <utility>

using namespace Eigen;
using namespace std;

const int n = 5;
const int N = 2;
const int k = 3;

int main()
{
    MatrixXd a(n, N + 1);
    a << 1, 2, 1,
        1.2, 0.1, 1,
        0.1, 1.4, 2,
        0.3, 3.5, 2,
        0.4, 2.0, 2;
    vector<pair<double, int>> dis;
    pair<double, int> pr;
    vector<double> test = { 0.5, 2.3 };
    for (int i = 0; i < n; ++i)
    {
        double d = 0.0;
        for (int j = 0; j < N; ++j)
        {
            d += pow((a(i, j) - test[j]), 2);
        }
        pr.first = sqrt(d);
        pr.second = a(i, 2);
        dis.push_back(pr);
    }
    cout << "计算测试数据与各个训练数据之间的距离:" << endl;
    for (auto d : dis)
        cout << d.first << " " << d.second << endl;
    cout << "按照距离的递增关系进行排序,选取距离最小的K个点:" << endl;
    partial_sort(dis.begin(), dis.begin() + k, dis.end());
    for (auto d : dis)
        cout << d.first << " " << d.second << endl;
    cout << "确定前K个点所在类别的出现频率:" << endl;
    map<double, int> mp;
    for (int i = 0; i < k; ++i)
        mp[dis[i].second]++;
    for (auto m : mp)
        cout << m.first << " " << m.second << endl;
    cout << "返回前K个点中出现频率最高的类别作为测试数据的预测分类:" << endl;
    vector<pair<int, int>> mp_test;
    for (auto it = mp.begin(); it != mp.end(); it++)
        mp_test.push_back(make_pair(it->first, it->second));
    sort(mp_test.begin(), mp_test.end(), [](pair<double, int> x, pair<double, int> y) -> bool {
        return x.second > y.second;
    });
    auto it = mp_test.begin();
    cout << it->first << endl;
    system("pause");
}

(2)kd树

  线性扫描非常耗时,为了减少计算距离的次数提高效率,使用kd树方法,它能快速地找到查询点近邻。可以通过将搜索空间进行层次划分建立索引树以加快检索速度。对于二维空间,它最终要划分的空间类似如下,

这里写图片描述

  决定在哪个维度上进行分割是由所有数据在各个维度的方差决定的,方差越大说明该维度上的数据波动越大,更应该再该维度上对点进行划分。例如x维度方差较大,所以以x维度方向划分。分割时一般取分割维度上的所有值的中值的点,比如下图,第一次计算方差较大的维度为x维度,中值点为A,以x=Ax分割,接着对分割后的点分别又继续分割,计算方差并寻找中值,以y=Cy、y=By分割,以此类推。

这里写图片描述

  从根节点开始查找,直到叶子节点,整个过程将最短距离d和相应的点记录下来。回溯,通过计算待预测的点到分割平面的距离l与最短距离d比较,看是否要进入节点的相邻空间去查找。回溯的过程是为了确认是否有必要进入相邻子空间去搜索,当待预测点到最近点的距离d大于待预测点到分割面的距离l时,则需要到相邻子空间查找,否则则没必要,直接往上一层回溯。

5、KNN算法总结

(1)优点

1. 简单,易于理解,易于实现,无需估计参数,无需训练;

2. 适合对稀有事件进行分类(例如当流失率很低时,比如低于0.5%,构造流失预测模型);

3. 特别适合于多分类问题(multi-modal,对象具有多个类别标签),例如根据基因特征来判断其功能分类,kNN比SVM的表现要好。

(2)缺点

1. 懒惰算法,对测试样本分类时的计算量大,内存开销大,评分慢;

2. 可解释性较差,无法给出决策树那样的规则。

(3)常见问题

1. k值设定为多大?

  k太小,分类结果易受噪声点影响;k太大,近邻中又可能包含太多的其它类别的点。(对距离加权,可以降低k值设定的影响)。k值通常是采用交叉检验来确定(以k=1为基准)。经验规则:k一般低于训练样本数的平方根

2. 类别如何判定最合适?

  投票法没有考虑近邻的距离的远近,距离更近的近邻也许更应该决定最终的分类,所以加权投票法更恰当一些。

3. 如何选择合适的距离衡量?

  高维度对距离衡量的影响:众所周知当变量数越多,欧式距离的区分能力就越差。变量值域对距离的影响:值域越大的变量常常会在距离计算中占据主导作用,因此应先对变量进行标准化。

4. 训练样本是否要一视同仁?

  在训练集中,有些样本可能是更值得依赖的。可以给不同的样本施加不同的权重,加强依赖样本的权重,降低不可信赖样本的影响

5. 性能问题?

  kNN是一种懒惰算法,平时不好好学习,考试(对测试样本分类)时才临阵磨枪(临时去找k个近邻)。懒惰的后果:构造模型很简单,但在对测试样本分类地的系统开销大,因为要扫描全部训练样本并计算距离。已经有一些方法提高计算的效率,例如压缩训练样本量等。

6. 能否大幅减少训练样本量,同时又保持分类精度?

  浓缩技术(condensing),编辑技术(editing)。

参考:https://blog.youkuaiyun.com/jmydream/article/details/8644004
https://blog.youkuaiyun.com/wangyangzhizhou/article/details/70940953

<think>好的,我需要帮助用户理解K近邻KNN)算法的相关信息,包括其介绍、原理和应用。用户已经提供了一些站内引用,我需要综合这些信息并结合之前的对话内容来组织回答。 首先,回顾之前的对话,用户之前询问了关于`imputer.transform`方法的使用,特别是处理CSV文件时的应用。我的回答中提到了KNNImputer,它基于KNN算法来填充缺失值。现在用户想更全面地了解KNN算法本身,包括其介绍、原理和应用。 接下来,我需要参考用户提供的四个引用内容: 1. **引用[1]** 提到KNN是基于实例的学习方法,根据最近邻的类别决定输入实例的类别,但处理大规模数据时可能有效率和准确性问题,并提到优化策略如特征选择和降维。 2. **引用[2]** 解释了KNN的基本思想,比如通过最密切的几个邻居来判断类别,可用于分类和回归,类似于决策树。 3. **引用[3]** 详细列出了改进KNN的策略,如数据结构优化(kd树等)、降维技术、近似方法、集成学习、动态调整K值和加权KNN。 4. **引用[4]** 描述了KNN的预测过程,包括分类和回归的具体方法,以及流程图。 我需要将这些信息整合到回答中,同时结合之前讨论的KNNImputer的应用场景。用户可能对KNN的基本原理、数学公式、核心要素、优化方法以及实际应用感兴趣。 首先,回答的结构应该包括以下几个部分: 1. **算法介绍**:简要说明KNN是什么,属于哪类算法,基本思想。 2. **核心原理**:详细解释工作原理,包括距离计算、K值选择、分类与回归的不同处理方式,以及数学公式。 3. **关键要素**:讨论K值的影响、距离度量方法、数据标准化的重要性。 4. **优化策略**:根据引用[3]提到的各种优化方法,如数据结构优化、降维、近似算法等。 5. **应用场景**:结合之前的KNNImputer例子,说明KNN在分类、回归、缺失值填充等方面的应用。 6. **优缺点分析**:总结KNN的优势和局限性,可能包括计算复杂度高、对数据规模敏感等。 在撰写过程中,需要确保使用正确的中文术语,数学公式用$$...$$格式,行内公式用$...$。同时,引用用户提供的引用来源,如[^1]、[^3]等。此外,生成相关问题时要考虑用户可能的后续疑问,比如参数选择、与其他算法的比较等。 需要特别注意用户之前的对话中提到的KNNImputer,这可能是一个实际应用的例子,可以在应用场景部分提及,说明KNN不仅用于分类/回归,也用于数据预处理中的缺失值填补。同时,结合引用[3]中的优化策略,可以解释如何提升KNN在实际应用中的效率,比如使用kd树加速邻居搜索。 可能存在的挑战是如何将多个引用内容有机地整合到回答中,避免信息重复,同时保持逻辑连贯。需要确保每个部分的信息都有对应的引用支持,并且在适当的位置添加引用标识,如、等。 最后,生成的相关问题需要引导用户深入探讨KNN的不同方面,比如参数调优、与其他算法的对比、处理高维数据的方法等,这些都应基于现有内容自然延伸。</think>### K近邻KNN)算法详解:原理、优化与应用 #### 一、算法概述 K近邻(K-Nearest Neighbors, KNN)是一种**基于实例的监督学习算法**,属于“惰性学习”(Lazy Learning)范畴。其核心思想是:**相似的数据样本在特征空间中彼此靠近**。KNN无需显式训练模型,而是直接通过计算样本间的距离进行分类或回归预测[^2]。 #### 二、核心原理 1. **工作原理** - **输入**:带标签的训练数据集$D = \{(x_1, y_1), (x_2, y_2), ..., (x_n, y_n)\}$,其中$x_i$为特征向量,$y_i$为标签。 - **预测流程**: 1. **计算距离**:对测试样本$x_{\text{test}}$,计算其与所有训练样本的**距离**(如欧氏距离$d(x_{\text{test}}, x_i) = \sqrt{\sum_{j=1}^m (x_{\text{test},j} - x_{i,j})^2}$)。 2. **选择邻居**:选取距离最近的$K$个样本($K$为超参数)。 3. **决策规则**: - **分类任务**:多数表决法(取$K$个邻居中出现最多的类别)。 - **回归任务**:均值法(取$K$个邻居标签的平均值),或加权均值(距离越近权重越高)。 **流程图**: ```mermaid graph TD A[训练数据集] --> B[计算测试样本与所有样本的距离] B --> C[选择K个最近邻] C --> D{任务类型} D -->|分类| E[多数表决] D -->|回归| F[均值/加权均值] E --> G[输出类别] F --> H[输出数值] ``` 2. **数学表达** - **加权分类**:若使用距离倒数作为权重,类别概率可表示为: $$ P(y=c|x_{\text{test}}) = \frac{\sum_{i \in N_K} \frac{1}{d(x_{\text{test}}, x_i)} \cdot I(y_i = c)}{\sum_{i \in N_K} \frac{1}{d(x_{\text{test}}, x_i)}} $$ 其中$N_K$为K个邻居集合,$I(\cdot)$为指示函数[^4]。 #### 三、关键要素与优化 1. **核心参数与问题** - **K值选择**: - 较小的$K$(如1)对噪声敏感,易过拟合;较大的$K$可能模糊类别边界。通常通过交叉验证选择最优$K$。 - **距离度量**: 除欧氏距离外,曼哈顿距离、余弦相似度等适用于不同场景(如文本分类常用余弦相似度)。 - **数据标准化**: 特征量纲差异会影响距离计算,需先进行归一化或标准化[^3]。 2. **优化策略** - **数据结构优化**: 使用**kd树**或**Ball Tree**加速近邻搜索,将时间复杂度从$O(n^2)$降至$O(n \log n)$[^3]。 - **降维技术**: 对高维数据应用PCA(主成分分析)或LDA(线性判别分析),减少“维度灾难”影响[^1]。 - **近似算法**: 如**HNSW**(层级可导航小世界图)或**LSH**(局部敏感哈希),以牺牲少量精度换取更高效率[^3]。 - **动态调整K值**: 根据样本密度或局部噪声水平自适应调整K值,例如在稀疏区域使用更大的K。 #### 四、应用场景 1. **分类与回归** - **分类**:医疗诊断(根据相似病例判断疾病)、图像识别(基于相似图像标签分类)。 - **回归**:房价预测(取相似房屋价格均值)、销量预估。 2. **数据预处理** - **缺失值填充**:如`KNNImputer`利用邻居特征均值填充缺失值(例如用户之前提到的`imputer.transform("P001.csv")`)[^2]。 3. **推荐系统** - 基于用户行为相似度(如协同过滤)推荐商品或内容。 #### 五、优缺点分析 | **优点** | **局限性** | |------------------------------|-------------------------------| | 无需训练,实现简单 | 计算复杂度高(需存储全部数据) | | 天然支持多分类与回归 | 对高维数据敏感(维度灾难) | | 解释性强(依赖直观距离关系) | 需要合理选择K值和距离度量 | --- ### 相关问题 1. 如何通过网格搜索(Grid Search)优化KNN的$K$值和距离度量参数? 2. KNN与支持向量机(SVM)在处理非线性分类问题上有何差异? 3. 在实时性要求高的场景中,如何对KNN算法进行部署优化? 4. 针对类别不平衡数据,KNN的分类效果会受哪些影响?如何改进?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~青萍之末~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值