11-1 几何与空间距离(一):K-最近邻 (KNN)——物以类聚

🎯 教学目标与重难点…

【三维目标】

  • 📚 知识目标
    1. 理解 KNN 的核心思想:物以类聚,人以群分——一个样本的类别由其最近的 K 个邻居投票决定。
    2. 掌握欧氏距离的计算公式(二维空间)。
    3. 理解 K 值对模型的影响:K 太小容易过拟合,K 太大容易欠拟合。
    4. 掌握 KNeighborsClassifier 的基本使用。
  • ⚙️ 能力目标
    1. 能使用 sklearn.neighbors.KNeighborsClassifier 训练分类模型。
    2. 能通过调整 n_neighbors 参数观察决策边界的变化。
    3. 能理解为什么 KNN 必须配合标准化(StandardScaler) 使用。
  • 💡 素养目标
    1. 建立“距离”在机器学习中的重要性认知。
    2. 强化“数据预处理直接影响模型效果”的工程意识(联动第6章)。

【重点与难点】

  • 🟢 教学重点
    1. KNN 的“投票”机制——少数服从多数。
    2. KNN 的代码实现与 K 值调参。
    3. 标准化对 KNN 的关键影响(联动 6.1.3 归一化)。
  • 🟡 教学难点
    1. 理解 KNN 是“懒惰学习”(Lazy Learning)——没有显式的训练过程,而是记住所有数据。
    2. 理解“距离”在高维空间中的局限性(维度灾难的直观感受)。

📌 一、 课程导入(5 分钟)

情景模拟:如何判断一个人的“圈子”?

假设你刚转到一所新学校,谁也不认识。现在有人告诉你:“想知道一个人是‘学霸’还是‘学渣’,看他身边最常一起玩的 5 个朋友就知道了!”

  • 如果他身边的 5 个朋友全是年级前 10 名 → 他大概率也是学霸。
  • 如果他身边的 5 个朋友全是经常不及格的 → 他大概率也是学渣。

这就是 KNN 的核心思想:一个人的“标签”(类别),由他最近的 K 个“邻居”投票决定。

引申

  • “最近的邻居”就是距离最近的人。
  • “K”就是看几个邻居(比如 K=5)。
  • “投票”就是少数服从多数。

一句话总结:KNN 是机器学习里最贴近人类直觉的算法——“近朱者赤,近墨者黑”

  • 👨‍🏫 教师活动:用 PPT 展示一张散点图,红色点代表“学霸”,蓝色点代表“学渣”,然后问:“如果来了一个新同学(绿色问号),你觉得他属于哪一类?”
  • 🧑‍🎓 学生活动:学生凭直觉回答“看离谁近”。老师顺势引出“距离”和“投票”两个核心概念。

用“转学生判断圈子”的场景,将抽象的 KNN 算法转化为学生生活中可感知的经验——近朱者赤、近墨者黑,瞬间建立直觉。

📖 二、 解决问题过程(一):KNN 的核心三要素

1. KNN 的三个核心要素

要素 说明 生活类比
距离度量 如何计算两个样本之间的“远近” 用“物理距离”衡量两个人关系远近
K 值 参考多少个最近邻 看“最近的 K 个朋友”
投票规则 如何根据邻居做决策 少数服从多数

2. 最常用的距离——欧氏距离(Euclidean Distance)

这就是我们初中就学过的两点间距离公式

二维空间:点 A=(x₁, y₁),点 B=(x₂, y₂)

\[ \text{距离} = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2} \]

多维空间(推广):点 A=(a₁, a₂, …, aₙ),点 B=(b₁, b₂, …, bₙ)

\[ \text{距离} = \sqrt{\sum_{i=1}^{n} (a_i - b_i)^2} \]

3. 投票机制

  • K=3:看最近的 3 个邻居,统计它们属于哪个类别最多。
  • K=5:看最近的 5 个邻居,少数服从多数。
  • K 通常取奇数:避免出现平局(2:2 无法决定)。

4. KNN 的“懒惰”本质

KNN 是**“懒惰学习”(Lazy Learning)**的典型代表。

  • 训练阶段:什么都不做,只是把数据存起来。
  • 预测阶段:来了一个新样本,才去计算它和所有训练样本的距离,找最近的 K 个。

优点:训练极快(几乎零耗时)。 缺点:预测极慢(每次都要算所有距离),数据量大时效率低。

  • 👨‍🏫 教师活动
    1. 在黑板上画两个点 A(1,2) 和 B(4,6),带着学生一起算欧氏距离:\(\sqrt{(1-4)^2 + (2-6)^2} = \sqrt{9+16} = 5\)。
    2. 画一个 3 分类的简单示意图,演示 K=3 时投票如何决策。
  • 🧑‍🎓 学生活动
    1. 学生在笔记本上手动计算两个点的距离。
    2. 参与“投票”互动:老师给 5 个邻居的类别,学生数票数,宣布结果。

通过手动计算欧氏距离,让学生从“感受距离”升维到“计算距离”。投票环节让学生亲身体验“少数服从多数”的决策过程。

💻 三、 解决问题过程(二):代码实战——用 KNN 分类鸢尾花

1. 最简 KNN 代码(三步走)

 1from sklearn.datasets import load_iris
 2from sklearn.model_selection import train_test_split
 3from sklearn.neighbors import KNeighborsClassifier
 4from sklearn.preprocessing import StandardScaler
 5
 6# 1. 加载数据
 7X, y = load_iris(return_X_y=True)
 8X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
 9
10# 2. ⚠️ KNN 必做:标准化(联动第6章!)
11scaler = StandardScaler()
12X_train_scaled = scaler.fit_transform(X_train)
13X_test_scaled = scaler.transform(X_test)
14
15# 3. 创建 KNN 模型(K=3)并训练
16knn = KNeighborsClassifier(n_neighbors=3)
17knn.fit(X_train_scaled, y_train)
18
19# 4. 评估
20print(f"训练集准确率: {knn.score(X_train_scaled, y_train):.4f}")
21print(f"测试集准确率: {knn.score(X_test_scaled, y_test):.4f}")

2. 对比实验:不做标准化会怎样?

1# 故意不用标准化
2knn_bad = KNeighborsClassifier(n_neighbors=3)
3knn_bad.fit(X_train, y_train)
4print(f"未标准化测试集准确率: {knn_bad.score(X_test, y_test):.4f}")

实验结果

  • 标准化后:准确率 ≈ 0.97
  • 未标准化:准确率 ≈ 0.73

结论:KNN 对特征尺度极其敏感!不做标准化,KNN 就废了。 这正是第 6 章预处理知识的最佳实践验证。

3. 可视化决策边界(理解 K 值影响)

make_classification 生成二维数据,看不同 K 值的决策边界:

 1import numpy as np
 2import matplotlib.pyplot as plt
 3from sklearn.datasets import make_classification
 4from sklearn.neighbors import KNeighborsClassifier
 5from sklearn.preprocessing import StandardScaler
 6
 7# 生成二维数据(方便画图)
 8X, y = make_classification(n_samples=200, n_features=2, n_redundant=0,
 9                           n_clusters_per_class=1, random_state=42)
10
11# 标准化
12X = StandardScaler().fit_transform(X)
13X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
14
15# 不同 K 值
16fig, axes = plt.subplots(1, 3, figsize=(15, 4))
17K_values = [1, 5, 20]
18
19for i, k in enumerate(K_values):
20    knn = KNeighborsClassifier(n_neighbors=k)
21    knn.fit(X_train, y_train)
22    
23    # 画决策边界
24    xx, yy = np.meshgrid(np.linspace(-3, 3, 200), np.linspace(-3, 3, 200))
25    Z = knn.predict(np.c_[xx.ravel(), yy.ravel()])
26    Z = Z.reshape(xx.shape)
27    
28    axes[i].contourf(xx, yy, Z, alpha=0.3)
29    axes[i].scatter(X_train[:, 0], X_train[:, 1], c=y_train, edgecolors='k')
30    axes[i].set_title(f'K={k}')
31    axes[i].set_xlim(-3, 3)
32    axes[i].set_ylim(-3, 3)
33
34plt.tight_layout()
35plt.show()

三张图解读

K 值 决策边界特点 现象
K=1 极度破碎,每个点周围都有小区域 过拟合——太关注个别点
K=5 平滑合理,边界清晰 刚好——泛化能力强
K=20 过于平滑,几乎成直线 欠拟合——看了太多邻居,忽视局部信息
  • 👨‍🏫 教师活动
    1. 先运行“标准化 vs 未标准化”对比实验,让学生亲眼看到预处理的重要性。
    2. 运行三张决策边界图,指着 K=1 的破碎边界说“这就是过拟合”,指着 K=20 的直线说“这就是欠拟合”。
  • 🧑‍🎓 学生活动
    1. 修改 n_neighbors 的值,观察准确率的变化,找出当前数据的最佳 K 值。
    2. 讨论:“K=1 时训练集准确率可能 100%,但为什么不好?”(答案:太敏感,容易受噪声影响)。

通过“标准化对比实验”,让学生深刻理解第6章“预处理”不是纸上谈兵,而是直接决定模型生死的关键步骤。通过决策边界可视化,让“过拟合/欠拟合”不再是抽象概念。

✍️ 四、 解决问题过程(三):课堂练习——找最佳 K 值

📝 任务一:K 值调参实验(网格搜索手写版)…

背景与题目: 使用鸢尾花数据集,手动循环不同的 K 值(1 到 20),记录每个 K 值对应的测试集准确率,画出“K 值 vs 准确率”的折线图,找到最佳 K 值。

 1from sklearn.datasets import load_iris
 2from sklearn.model_selection import train_test_split
 3from sklearn.neighbors import KNeighborsClassifier
 4from sklearn.preprocessing import StandardScaler
 5import matplotlib.pyplot as plt
 6
 7# 加载数据
 8X, y = load_iris(return_X_y=True)
 9X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
10
11# 标准化
12scaler = StandardScaler()
13X_train = scaler.fit_transform(X_train)
14X_test = scaler.transform(X_test)
15
16# 请完成:循环 K=1 到 20,记录每个 K 的测试集准确率
17k_values = range(1, 21)
18test_scores = []
19
20for k in k_values:
21    # 创建 KNN 模型并训练
22    knn = KNeighborsClassifier(n_neighbors=k)
23    knn.fit(X_train, y_train)
24    test_scores.append(knn.score(X_test, y_test))
25
26# 画出折线图
27plt.figure(figsize=(10, 6))
28plt.plot(k_values, test_scores, 'bo-')
29plt.xlabel('K 值')
30plt.ylabel('测试集准确率')
31plt.title('K 值对 KNN 准确率的影响')
32plt.grid(True)
33plt.xticks(k_values)
34plt.show()
35
36# 找到最佳 K 值
37best_k = k_values[test_scores.index(max(test_scores))]
38print(f"最佳 K 值: {best_k}, 最高准确率: {max(test_scores):.4f}")
🔍 查看参考结果与解析…

运行结果

  • K=1 时准确率可能为 0.93,K=5 时达到 0.97,K=15 后开始下降。
  • 最佳 K 通常在 3~8 之间(鸢尾花数据集较小,K 不宜太大)。

解析

  • K 太小(如 1):模型太敏感,容易受噪声影响(过拟合)。
  • K 太大(如 20):模型太“从众”,忽略了局部模式(欠拟合)。
  • 最佳 K 是“刚刚好”的那个值。

📝 五、 课堂小结(5 分钟)

flowchart LR
    root["📊 K-最近邻 (KNN)"]

    subgraph C1 ["💡 核心思想"]
        direction TB
        A1["物以类聚,人以群分"]
        A2["近朱者赤,近墨者黑"]
    end

    subgraph C2 ["📐 三要素"]
        direction TB
        B1["距离度量(欧氏距离)"]
        B2["K 值(参考邻居数)"]
        B3["投票规则(少数服从多数)"]
    end

    subgraph C3 ["⚙️ 关键要点"]
        direction TB
        C1_node["⚠️ 必须标准化!"]
        C2_node["K 小 → 过拟合"]
        C3_node["K 大 → 欠拟合"]
    end

    root --> C1
    root --> C2
    root --> C3

    style root fill:#4b6cb7,stroke:#253b6e,color:#fff
    style C1 fill:#e3f2fd,stroke:#2196f3
    style C2 fill:#fff3e0,stroke:#ff9800
    style C3 fill:#ffebee,stroke:#ef5350

✏️ 随堂检测与互动练习

点击展开:随堂测试题(带解析)

一、 单选题

  1. KNN 算法中,“K”代表什么意思?
  • A. 数据集的维度数
  • B. 参考的最近邻数量
  • C. 模型的训练轮数
  • D. 特征的数量
【答案】

【解析】B。K 是超参数,表示投票时参考多少个最近的邻居。

  1. 以下哪个操作对 KNN 算法影响最大
  • A. 对特征进行标准化/归一化
  • B. 增加训练数据量
  • C. 调整学习率
  • D. 增加神经网络的层数
【答案】

【解析】A。KNN 基于距离计算,如果特征尺度不同,大数值特征会主导距离,导致模型失效。学习率和神经网络与 KNN 无关。

  1. KNN 被归类为“懒惰学习”(Lazy Learning),原因是?
  • A. 它训练速度很快,因为只是存储数据,不做任何计算
  • B. 它不调用任何库函数
  • C. 它的代码行数很少
  • D. 它不需要调参
【答案】

【解析】A。KNN 在训练阶段只是“记住”所有数据,真正的计算发生在预测阶段。

二、 代码填空题

题目:请补全代码,创建 KNN 分类器,设置 K=7。

1from sklearn.neighbors import KNeighborsClassifier
2
3knn = _________________________________
4knn.fit(X_train, y_train)
【答案】

KNeighborsClassifier(n_neighbors=7)

📮 六、 课后作业与拓展

📮 课后作业…
  1. 基础代码题:使用 sklearn 自带的 load_wine 葡萄酒数据集,用 KNN 进行分类,找到最佳 K 值,并报告最佳准确率。
  2. 思考题:KNN 中如果 K 取偶数(如 K=4),投票可能出现 2:2 平局。你猜 sklearn 会怎么处理这种平局?(提示:可以查文档或自己实验,答案见下节课)。
  3. 对比实验题:在同一个数据集上,分别用 KNN(K=5) 和逻辑回归进行训练,对比两者的测试集准确率,谁更好?
  4. 预习任务:KNN 基于“距离”来做分类,那如果我们不仅能分类,还能在分类之前把数据“投影”到一个更有利于分类的空间,是不是效果更好?预习下一节课:线性判别分析 (LDA)
  5. 职高衔接拓展:你在做电商“用户复购预测”,特征有“消费金额(0-10000)”、“登录天数(0-30)”、“浏览时长(0-500)”。请列出预处理步骤,并说明为什么 KNN 需要这些步骤。

📋 七、 板书设计

🛠️ 板书设计…
 1第十一章 几何与空间距离
 2第一课时:K-最近邻 (KNN)
 3
 4一、核心思想
 5   "近朱者赤,近墨者黑"
 6   一个样本的类别 = 最近的 K 个邻居投票决定
 7
 8二、三要素
 9   1. 距离度量:欧氏距离
10      d = √(Σ(aᵢ - bᵢ)²)
11   2. K 值:参考邻居个数(通常取奇数)
12   3. 投票规则:少数服从多数
13
14三、关键注意事项
15   ⚠️ KNN 必须做标准化!(联动第6章)
16   - 不做标准化 → 大数吃小数
17   - K=1 → 过拟合(太敏感)
18   - K=20 → 欠拟合(太平滑)
19
20四、代码三步走
21   1. scaler = StandardScaler()
22   2. knn = KNeighborsClassifier(n_neighbors=5)
23   3. knn.fit(X_train_scaled, y_train)
24
25五、优缺点
26   优点:训练快,简单直观
27   缺点:预测慢(要算所有距离)

本课用到的单词

单词 发音 专业英语解释(中文)
K-Nearest Neighbors (KNN) /keɪ ˈnɪrəst ˈneɪbərz/ K-最近邻。一种基于距离度量的惰性学习分类/回归算法。
Euclidean Distance /juːˈklɪdiən ˈdɪstəns/ 欧氏距离。两点之间的直线距离,是最常用的距离度量方式。
Lazy Learning /ˈleɪzi ˈlɜːrnɪŋ/ 惰性学习。训练阶段只存储数据,预测阶段才进行计算的学习方式。
Decision Boundary /dɪˈsɪʒən ˈbaʊndəri/ 决策边界。分类模型将不同类别分开的分界线/面。
Voting /ˈvoʊtɪŋ/ 投票。KNN 中根据邻居类别进行少数服从多数的决策方式。
Hyperparameter /ˌhaɪpərpəˈræmɪtər/ 超参数。训练前需要手动设定的参数,如 KNN 中的 K 值。