第八篇:KNN 到底是怎么分类的?最容易理解的机器学习算法之一

如果让我选一个最适合刚入门时理解“机器学习到底在干嘛”的算法,KNN 一定排得很靠前。

原因很简单:
它的核心思路几乎不需要什么复杂公式,你靠直觉就能先理解个大概。

KNN 的想法特别朴素:

一个新样本属于哪一类,可以看看它附近最像它的那些老样本,大多数是什么类。

说得更接地气一点,就是:

看邻居。

这也是它名字的由来:
K-Nearest Neighbors,K 近邻。


1. 先别看公式,先看一个很生活化的例子

假设你要根据“学习时长”和“作业完成率”,判断一个学生这次考试更可能通过还是不通过。

你已经有一批历史学生数据了。
每个学生都有两个特征:

  • 每天学习多久
  • 作业完成得怎么样

同时你也知道他们最终有没有通过考试。

现在来了一个新学生,你不知道他的结果,但你知道:

  • 他每天学 4 小时
  • 作业完成率 80%

那怎么判断他更可能通过还是不通过?

KNN 的做法是:

  1. 先在历史数据里找出“和他最像的几个学生”
  2. 看看这些学生最后大多数通过了还是没通过
  3. 用多数结果给新学生投票

如果最近的 5 个学生里,4 个都通过了,那这个新学生大概率也会被判成“通过”。

你看,这个思路是不是很直观?

它不像线性回归那样要去拟合一条线,也不像逻辑回归那样要输出概率。
它直接做一件事:

找相似的老样本,借它们的结果来判断新样本。


2. KNN 里的 K 到底是什么

KNN 里的 K,指的就是“看几个邻居”。

比如:

  • K=1K=1K=1:只看最近的那 1 个样本
  • K=3K=3K=3:看最近的 3 个样本
  • K=5K=5K=5:看最近的 5 个样本

K 的选择会直接影响模型表现。

K 太小,会怎么样

比如 K=1K=1K=1,模型就只看最近的一个邻居。

这样做的好处是非常灵敏,局部变化能很快反映出来。
但问题是,它也特别容易受噪声影响。

比如有一个样本刚好标错了,或者本身就是个很怪的离群点,K=1K=1K=1 就可能直接被它带偏。

K 太大,会怎么样

如果 K 取特别大,比如整个数据里有 100 个点,你取 K=50K=50K=50,那每次投票时“远处那些其实没那么像的样本”也被拉进来了。

这会让模型变得很平滑,但也可能过于迟钝。
局部真正有用的信息,反而被稀释掉了。

所以 K 的选择,本质上是在平衡两件事:

  • 要不要更敏感地看局部
  • 还是更稳一点,不要太容易被单个噪声点影响

3. “近”到底怎么定义:距离怎么计算

KNN 的关键不只是“看邻居”,还包括:

你怎么判断谁更近。

最常见的做法是算距离。

比如两个样本各有两个特征:

  • 样本 A:(x1,x2)(x_1, x_2)(x1,x2)
  • 样本 B:(x1′,x2′)(x_1', x_2')(x1,x2)

最常见的欧氏距离公式是:

d=(x1−x1′)2+(x2−x2′)2 d = \sqrt{(x_1 - x_1')^2 + (x_2 - x_2')^2} d=(x1x1)2+(x2x2)2

这其实就是平面几何里两点之间的直线距离。

如果特征更多,公式会推广到更高维空间,但本质一样:
就是看两个点在特征空间里隔得有多远。

除了欧氏距离,还有曼哈顿距离之类的定义。
不过对入门来说,先把“距离越小,样本越像”这个概念抓住就够了。


4. KNN 为什么特别依赖特征缩放

这一点很重要,而且和你前面第五篇的数据预处理刚好能接上。

假设你现在有两个特征:

  • 年龄:20 到 60
  • 年收入:3000 到 50000

如果你直接拿这两个特征去算距离,会发生什么?

因为收入数值范围远大于年龄,距离计算时“收入”这个维度就会占很大权重。
结果模型可能主要是在根据收入找邻居,而年龄几乎没什么存在感。

但这未必是你想要的。

所以 KNN 通常很依赖标准化或归一化,让不同特征处在相近尺度上。
不然“谁更近”这件事本身就可能被数值范围带偏。

这也是为什么 KNN 一般不太适合完全不做预处理就直接上。


5. KNN 到底算不算“训练”

这是 KNN 一个很有意思的地方。

大多数模型,比如线性回归、逻辑回归,训练时会做一件很明确的事:
从数据里学出参数。

比如:

  • 学出一个斜率和截距
  • 学出一组权重
  • 学出一个决策边界

但 KNN 不太一样。

它几乎没有那种典型意义上的“训练过程”。
它做的事情更像是:

把训练数据先记下来。

真正的计算压力,不是在训练阶段,而是在预测阶段。

因为每来一个新样本,KNN 都要去遍历训练集,算它和所有训练样本的距离,再找最近的 K 个。

所以很多人会说:

KNN 是一种“懒惰学习”算法。

意思不是它差,而是说:
它不急着在训练时总结规律,而是把“怎么判断”这件事留到预测时再做。


6. 这也决定了 KNN 的优缺点

优点:直观,几乎不需要复杂训练

KNN 特别适合入门,因为它很符合人的直觉。

你甚至可以把它理解成一种非常朴素的判断逻辑:
“和谁像,就更可能属于谁那一类。”

优点:对边界不规则的问题有时也能处理

有些数据并不是一条直线就能分开。
KNN 因为看的是局部邻居,所以有时候能适应比较弯曲、比较复杂的分类边界。

缺点:预测慢

训练时轻松,预测时费劲。
训练数据一多,每次都要算很多距离,速度会明显变慢。

缺点:对噪声敏感

尤其 K 取很小时,个别异常样本很容易影响判断。

缺点:对高维数据不太友好

维度一高,距离这个概念本身会变得没那么好用。
很多点之间的距离会越来越接近,邻居关系不再那么明显。


7. 先看一个最简单的 Python 例子

下面用 scikit-learn 写一个非常基础的 KNN 分类。

import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler

# 训练数据:两个特征 [学习时长, 作业完成率]
X_train = np.array([
    [1, 50],
    [2, 55],
    [3, 60],
    [4, 65],
    [5, 70],
    [6, 75],
    [7, 80],
    [8, 85]
])

# 标签:0=没通过,1=通过
y_train = np.array([0, 0, 0, 0, 1, 1, 1, 1])

# 新样本
X_test = np.array([
    [3.5, 62],
    [6.5, 78]
])

# 先做标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 建立 KNN 模型
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train_scaled, y_train)

# 预测
y_pred = knn.predict(X_test_scaled)

print("预测结果:", y_pred)

这段代码里最值得注意的不是 fit() 这一步,而是前面的标准化。

因为对 KNN 来说,距离怎么计算非常关键。
如果特征尺度差很多,最后“最近的邻居”就可能找得不合理。


8. 同样的数据,K 不一样,结果可能也会不一样

再看一个更能体现 K 影响的例子。

for k in [1, 3, 5]:
    knn = KNeighborsClassifier(n_neighbors=k)
    knn.fit(X_train_scaled, y_train)
    y_pred = knn.predict(X_test_scaled)
    print(f"K={k}, 预测结果={y_pred}")

你会发现,有时候:

  • K=1K=1K=1K=3K=3K=3 的结果一样
  • 但换成 K=5K=5K=5 以后,某些样本的预测会变

这就是 KNN 的一个很典型特点:
它的行为对 K 值非常敏感。

所以 K 不是随便拍脑袋定的。
在实际任务里,常常会用验证集或者交叉验证来挑一个更合适的 K。

这刚好也把第六篇和第七篇的内容串起来了:

  • 你需要验证集,来比较不同 K 的效果
  • 你需要合适的评估指标,来判断哪个 K 更值得选

9. KNN 为什么很适合初学者理解“分类边界”

你后面会学到很多更复杂的算法,比如:

  • 决策树
  • 随机森林
  • SVM
  • 神经网络

这些模型都在某种意义上“学一个边界”,把不同类别分开。

KNN 虽然简单,但它特别适合帮助你先建立对“分类边界”的直觉。

因为它不是先学一个固定公式,而是:

某个位置到底判成什么类,要看它附近是谁。

这意味着 KNN 的分类边界往往不是一条很硬的直线,而可能是弯弯曲曲的。
这会让你更容易理解:

不是所有分类问题都能靠一条直线搞定。

这一点对后面理解非线性模型很有帮助。


10. KNN 适合什么场景,不适合什么场景

比较适合

  • 数据量不算太大
  • 特征意义比较明确
  • 你想先做一个简单、直观的基线模型
  • 你希望比较容易解释“为什么是这个结果”

不太适合

  • 训练数据特别大,预测速度会受不了
  • 特征维度特别高,距离关系会变得不太可靠
  • 数据里噪声很多,或者类别边界特别混乱
  • 你不能接受预测时每次都要遍历训练集

所以 KNN 虽然不是什么“工业界万金油”,但它有自己的价值:
它很适合做入门理解,也很适合做某些小型问题的简单基线。


11. 这一篇真正值得留下来的直觉是什么

到这里,KNN 最重要的东西其实已经不是代码本身,而是这个直觉:

相似的样本,往往会有相似的结果。

这句话听起来很朴素,但其实很多机器学习方法背后,多少都带着这个思想。

KNN 是把这件事说得最直接的一个算法。
它几乎不绕弯,直接拿“邻居关系”来做判断。

也正因为它足够直白,所以特别适合放在机器学习前期去讲。

讲到这里,读者基本已经能接受一个事实:
模型不一定非要拟合一条线,也不一定非要输出一个概率。
它也可以通过“局部相似性”来解决问题。

接下来再往后走,就很适合讲决策树了。
因为决策树会把模型从“看邻居”推进到“按条件一步步分”。

也就是说:

  • KNN 更像是在说“你像谁”
  • 决策树更像是在说“你满足哪些条件”

更多推荐