接上一篇《七天学完十大机器学习经典算法-04.随机森林:群众智慧的机器学习实践》
想象一下,你搬进了一个新小区。想知道这个小区整体氛围如何?最直接的方法就是看看你最近的几家邻居是什么样的人——如果邻居们都很安静、整洁,小区大概率不错;如果邻居们深夜喧哗、环境杂乱,你可能就得重新考虑了。
K近邻(K-Nearest Neighbors, KNN) 算法的核心思想,就如同这个观察邻居的过程。它是机器学习中最直观、最易于理解的算法之一,属于“懒惰学习”的代表——它不做显式的模型训练,而是将决策推迟到需要预测时才进行。
一、初识KNN:邻居决定你是谁
KNN的核心思想异常简单:“物以类聚,人以群分” 。它认为,一个数据点的类别或数值,应该由其周围最相似的邻居们(即特征空间中最接近的点)来决定。
-
核心概念:
-
邻居: 在特征空间中距离目标点最近的其他数据点。
-
K值: 你需要考虑的邻居数量。比如K=3,就是看最近的3个邻居。
-
距离度量: 如何计算两个数据点之间的“远近”?常用方法有欧氏距离(直线距离)、曼哈顿距离(城市街区距离)等。
-
决策规则: 邻居们如何决定新点的身份?
-
分类: 多数投票。哪个类别在K个邻居中占多数,新点就属于哪个类别。
-
回归: 取平均值。K个邻居的目标值的平均值作为新点的预测值。
-
-
-
“懒惰学习”的本质:
KNN没有传统意义上的“训练”阶段。它只是简单地将所有的训练数据存储起来。当需要预测一个新数据点时,它才临时去计算这个新点与存储的所有点的距离,找出最近的K个邻居,然后根据这些邻居的信息做出预测。因此,它的“训练”非常快(几乎就是保存数据),但预测相对较慢(需要计算大量距离)。
二、KNN算法原理详解:距离、投票与K的选择
-
距离度量:衡量相似度的尺子
距离度量是KNN的基础,它定义了数据点之间“相似”或“不相似”的数学表达。最常见的有:-
欧氏距离: 最直观的“直线距离”。
-
公式:
distance(A, B) = √(Σ(Ai - Bi)²)
(对每个特征维度i求差的平方和再开方) -
例子:点A(1, 2), 点B(4, 6) ->
√((1-4)² + (2-6)²) = √(9 + 16) = √25 = 5
-
-
曼哈顿距离: “城市街区距离”,想象你在只能横平竖直行走的曼哈顿街区。
-
公式:
distance(A, B) = Σ|Ai - Bi|
(对每个特征维度i求差的绝对值之和) -
例子:点A(1, 2), 点B(4, 6) ->
|1-4| + |2-6| = 3 + 4 = 7
-
-
闵可夫斯基距离: 欧氏距离和曼哈顿距离的泛化。
-
公式:
distance(A, B) = (Σ|Ai - Bi|^p)^(1/p)
-
当p=2时,就是欧氏距离;当p=1时,就是曼哈顿距离。
-
-
余弦相似度: 更适合文本或高维稀疏数据,衡量的是方向上的相似性而非绝对距离。
-
公式:
cos(θ) = (A·B) / (||A|| ||B||)
-
如何选择? 欧氏距离最常用。如果数据在不同维度上的尺度差异很大,或者你更关心整体模式的相似性,余弦相似度可能更好。
-
-
K值的选择:问几个邻居最可靠?
K是KNN中唯一的超参数(需要人为设定的参数),它的选择对结果影响巨大:-
K太小(如K=1):
-
优点: 模型非常敏感,能捕捉到细微的局部模式。
-
缺点: 极易受噪声点或异常值干扰,模型变得不稳定,容易过拟合(在训练集上表现好,在新数据上表现差)。想象只问一个邻居就决定小区档次,风险很高。
-
-
K太大(如K接近总样本数):
-
优点: 模型更稳定,受噪声影响小。
-
缺点: 忽略了数据的局部结构,模型过于简单,容易欠拟合(无法捕捉数据中的有效模式)。预测结果趋向于训练数据中的多数类(分类)或平均值(回归)。想象问遍小区所有人,得到的可能是整个城市的平均印象,失去了本小区的特色。
-
-
如何选择K?
-
经验法则: 通常取一个较小的奇数(避免分类投票平局),从K=3、5、7开始尝试。
-
交叉验证: 最可靠的方法。将训练数据分成若干份,轮流用其中一份作为验证集,其他作为训练集,用不同的K值训练模型并在验证集上评估效果(如分类准确率、回归的均方误差),选择平均效果最好的那个K值。
-
-
-
决策规则:邻居们如何做决定?
-
分类任务:多数投票
找出距离目标点最近的K个训练样本点。统计这K个点中每个类别出现的次数。将出现次数最多的类别作为目标点的预测类别。例如,K=5的邻居中,3个是“猫”,2个是“狗”,则预测新点是“猫”。 -
回归任务:平均值
找出距离目标点最近的K个训练样本点。计算这K个点的目标值(连续数值)的平均值,作为目标点的预测值。例如,预测房价,K=3的邻居房价分别是300万、320万、310万,则预测值为(300+320+310)/3 = 310万。 -
加权投票/平均(可选): 有时会考虑邻居的“话语权”不同。距离目标点更近的邻居被认为更相似,其意见应具有更大的权重。常见权重是距离的倒数(1/distance)或距离平方的倒数(1/distance²)。这样,近邻对结果的影响更大。
-
三、KNN算法步骤:一步步实现
假设我们有一个训练数据集(已知类别/数值的点),要预测一个新样本点X的类别或数值。
-
计算距离: 计算新样本点X到训练数据集中每一个点的距离(如欧氏距离)。
-
排序找邻居: 将所有计算出的距离按从小到大排序。
-
确定K邻: 选取距离最小的前K个点。这些点就是X的K个最近邻居。
-
统计决策:
-
分类: 统计K个邻居中每个类别出现的频率。频率最高的类别即为X的预测类别(多数投票)。
-
回归: 计算K个邻居目标值的平均值,作为X的预测值。
-
-
(可选)加权: 如果需要,在步骤4中根据邻居与X的距离赋予不同的权重,距离近的权重高。
四、案例实战:用KNN解决实际问题
案例1:水果分类(简单二维可视化)
-
问题: 根据水果的“甜度”和“酸度”两个特征,区分它是苹果还是橙子。
-
训练数据:
| 水果 | 甜度 | 酸度 | 类别 |
| :--- | :--- | :--- | :--- |
| A | 7 | 1 | 苹果 |
| B | 8 | 1 | 苹果 |
| C | 2 | 8 | 橙子 |
| D | 3 | 7 | 橙子 |
| E | 6 | 2 | 苹果 |
| F | 3 | 9 | 橙子 | -
新样本: X (甜度=5, 酸度=3)
-
任务: 预测X是苹果还是橙子?(假设K=3)
-
计算距离 (欧氏距离):
-
dist(X, A) = √((5-7)² + (3-1)²) = √(4 + 4) = √8 ≈ 2.83
-
dist(X, B) = √((5-8)² + (3-1)²) = √(9 + 4) = √13 ≈ 3.61
-
dist(X, C) = √((5-2)² + (3-8)²) = √(9 + 25) = √34 ≈ 5.83
-
dist(X, D) = √((5-3)² + (3-7)²) = √(4 + 16) = √20 ≈ 4.47
-
dist(X, E) = √((5-6)² + (3-2)²) = √(1 + 1) = √2 ≈ 1.41
-
dist(X, F) = √((5-3)² + (3-9)²) = √(4 + 36) = √40 ≈ 6.32
-
-
排序找邻居: 距离从小到大: E(1.41), A(2.83), B(3.61), D(4.47), C(5.83), F(6.32)
-
确定K邻 (K=3): X的最近3个邻居是: E(苹果), A(苹果), B(苹果)
-
多数投票: 3个邻居全是苹果。因此,预测新样本X是苹果。
案例2:电影类型预测
-
问题: 根据一部电影中“打斗镜头次数”和“亲吻镜头次数”,预测它是动作片还是爱情片。
-
训练数据:
电影 打斗镜头 亲吻镜头 类型 M1 100 5 动作 M2 90 10 动作 M3 5 95 爱情 M4 10 90 爱情 M5 85 15 动作 M6 15 80 爱情 -
新电影: X (打斗镜头=80, 亲吻镜头=10)
-
任务: 预测X的类型?(假设K=3)
-
计算距离 (曼哈顿距离):
-
dist(X, M1) = |80-100| + |10-5| = 20 + 5 = 25
-
dist(X, M2) = |80-90| + |10-10| = 10 + 0 = 10
-
dist(X, M3) = |80-5| + |10-95| = 75 + 85 = 160
-
dist(X, M4) = |80-10| + |10-90| = 70 + 80 = 150
-
dist(X, M5) = |80-85| + |10-15| = 5 + 5 = 10
-
dist(X, M6) = |80-15| + |10-80| = 65 + 70 = 135
-
-
排序找邻居: 距离从小到大: M2(10), M5(10), M1(25), M6(135), M4(150), M3(160) (注意:M2和M5距离相同)
-
确定K邻 (K=3): X的最近3个邻居是: M2(动作), M5(动作), M1(动作)
-
多数投票: 3个邻居全是动作片。因此,预测新电影X是动作片。
案例3:鸢尾花分类 (经典数据集)
-
问题: 根据鸢尾花的花萼长度、花萼宽度、花瓣长度、花瓣宽度4个特征,预测其种类(山鸢尾、变色鸢尾、维吉尼亚鸢尾)。
-
数据: 使用著名的
Iris
数据集(包含150个样本,3类,每类50个样本,每个样本4个特征)。 -
实现: 通常使用Python的
scikit-learn
库。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
# 1. 加载数据
iris = load_iris()
X = iris.data # 特征 (150 x 4)
y = iris.target # 目标标签 (0, 1, 2 代表三种花)
# 2. 划分训练集和测试集 (70%训练, 30%测试)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 3. 创建KNN模型 (选择K=5, 使用欧氏距离)
knn = KNeighborsClassifier(n_neighbors=5, metric='euclidean')
# 4. "训练"模型 (实际上只是保存数据)
knn.fit(X_train, y_train)
# 5. 在测试集上进行预测
y_pred = knn.predict(X_test)
# 6. 评估模型准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"测试集准确率: {accuracy:.2f}") # 通常能达到0.95以上
五、KNN的优缺点与优化之道
-
优点:
-
原理简单,易于理解: 核心思想直观,符合人类直觉。
-
实现容易: 算法逻辑清晰,编码实现不复杂。
-
无需训练: “懒惰学习”特性,训练阶段只是存储数据,速度快。
-
对数据分布无假设: 不像线性回归等需要假设数据线性可分或符合特定分布。它是一种非参数方法。
-
可用于分类和回归: 适用性较广。
-
新数据易更新: 加入新样本只需添加到训练集,无需重新训练整个模型(但预测速度会变慢)。
-
-
缺点:
-
预测速度慢: 预测时需要计算新点到所有训练点的距离,当训练集很大时非常耗时。
-
对高维数据敏感(维度灾难): 随着特征维度增加,数据点在高维空间中变得极其稀疏,距离度量会失去意义,导致效果下降。
-
对特征尺度敏感: 如果不同特征的数量级(尺度)差异很大(如身高以米为单位,体重以克为单位),数值大的特征会主导距离计算。解决方案:特征归一化/标准化(如MinMaxScaler, StandardScaler)。
-
对不相关特征敏感: 包含大量不相关或冗余特征会干扰距离计算,降低性能。解决方案:特征选择。
-
类别不平衡问题: 如果某个类别的样本数量远多于其他类别,多数投票时大类别占优势,小类别容易被忽略。解决方案: 调整K值(增大K可能缓解,但有限),使用加权投票(根据距离或类别频率加权),或对数据进行重采样(过采样小类或欠采样大类)。
-
需要大量内存: 必须存储整个训练数据集。
-
K值和距离度量选择敏感: 需要仔细调参。
-
-
优化策略:
-
特征工程:
-
归一化/标准化: 至关重要! 确保所有特征在相似尺度上。常用方法:
-
Min-Max Scaling (归一化):
X_new = (X - X_min) / (X_max - X_min)
(缩放到[0, 1]或[-1, 1])。 -
Standardization (标准化):
X_new = (X - μ) / σ
(缩放为均值为0,标准差为1)。
-
-
特征选择: 移除不相关或冗余的特征,降低维度,提升效率和效果(如使用卡方检验、互信息、基于模型的特征重要性)。
-
降维: 对于非常高维数据,可以使用PCA(主成分分析)、t-SNE等方法降低维度,同时尽量保留信息。
-
-
选择合适的K: 使用交叉验证仔细选择最优K值。
-
选择合适的距离度量: 根据数据类型和问题尝试不同的距离度量(欧氏、曼哈顿、余弦等)。
-
使用近似最近邻搜索: 当数据集非常大时,精确计算所有距离太慢。可以使用KD-Tree、Ball Tree或基于哈希的近似算法(如LSH)来加速邻居搜索,牺牲一点精度换取速度的大幅提升。
-
处理类别不平衡: 使用加权投票、代价敏感学习或数据重采样技术(SMOTE、ADASYN等过采样,或随机欠采样)。
-
六、KNN的实际应用场景
得益于其简单性和直观性,KNN在诸多领域找到了应用:
-
推荐系统:
-
协同过滤: 寻找与目标用户兴趣最相似的K个用户(基于他们过去的行为,如评分、购买记录),将这些相似用户喜欢而目标用户未接触过的物品推荐给目标用户(User-based CF)。反之,也可以寻找与目标物品最相似的K个物品(Item-based CF)。
-
-
模式识别:
-
手写数字识别: 将待识别的数字图像向量化,在存储了大量已知标签的手写数字向量库中寻找K个最相似的邻居,通过投票确定数字类别(MNIST数据集上的经典应用)。
-
图像分类: 虽然不如深度学习CNN主流,但在特定场景或作为基线模型仍有应用。将图像特征(如SIFT, SURF, 或深度特征)提取出来,使用KNN分类。
-
语音识别: 可用于简单的语音命令分类。
-
-
生物信息学:
-
基因表达数据分析: 根据基因表达谱的相似性(距离)对样本(如不同组织、不同病人)进行分类(如癌症亚型分类)。
-
蛋白质功能预测: 预测未知蛋白质的功能,基于其氨基酸序列特征与已知功能蛋白质的相似性。
-
-
金融:
-
信用评分: 根据客户的财务特征(收入、负债、历史信用记录等)与过去客户的相似性,预测新客户的信用风险等级(分类)或违约概率(回归)。
-
欺诈检测: 识别与已知欺诈交易模式相似的交易。
-
-
文本分类:
-
将文档表示为词袋模型(Bag-of-Words)或TF-IDF向量,使用KNN根据向量相似度对文档进行分类(如新闻分类、垃圾邮件识别)。余弦相似度在此类高维稀疏数据上常表现更好。
-
-
地理信息系统(GIS):
-
根据位置点的属性(如土壤类型、海拔、附近设施)进行空间分类或插值(回归)。
-
-
医疗诊断:
-
基于病人的症状、体征、化验指标等特征,寻找与历史相似病例(K个邻居),辅助医生进行疾病诊断。
-
结语:理解“邻居”的力量
K近邻算法以一种近乎哲学般的简单——“近朱者赤,近墨者黑” ——揭示了机器学习分类与回归的核心逻辑。它无需复杂的数学推导,只需计算距离与统计投票,即可完成预测任务,使其成为入门机器学习的最佳起点之一。
然而,正如我们所见,简单的表象下也隐藏着挑战:K值的选择如同把握邻里关系的尺度,特征归一化是公平对话的前提,维度灾难则是信息爆炸带来的必然困境。理解这些优缺点,并掌握特征工程、距离选择等优化技巧,才能真正释放KNN的潜力。
无论是辨别水果的滋味、预测电影的类别,还是在复杂的基因序列中寻找生命密码,KNN以其独特的“邻里互助”模式,在众多领域展现着实用价值。当你面对一个新问题时,不妨先问问:“它的邻居是谁?”——答案或许就在那些最相似的数据点之中。
创作不易,如有收获请点🌟收藏!下期预告:《七天学完十大机器学习经典算法-05.支持向量机(SVM):分类边界的艺术》