机器学习进阶(8):KNN
第八篇:KNN 到底是怎么分类的?最容易理解的机器学习算法之一
如果让我选一个最适合刚入门时理解“机器学习到底在干嘛”的算法,KNN 一定排得很靠前。
原因很简单:
它的核心思路几乎不需要什么复杂公式,你靠直觉就能先理解个大概。
KNN 的想法特别朴素:
一个新样本属于哪一类,可以看看它附近最像它的那些老样本,大多数是什么类。
说得更接地气一点,就是:
看邻居。
这也是它名字的由来:
K-Nearest Neighbors,K 近邻。
1. 先别看公式,先看一个很生活化的例子
假设你要根据“学习时长”和“作业完成率”,判断一个学生这次考试更可能通过还是不通过。
你已经有一批历史学生数据了。
每个学生都有两个特征:
- 每天学习多久
- 作业完成得怎么样
同时你也知道他们最终有没有通过考试。
现在来了一个新学生,你不知道他的结果,但你知道:
- 他每天学 4 小时
- 作业完成率 80%
那怎么判断他更可能通过还是不通过?
KNN 的做法是:
- 先在历史数据里找出“和他最像的几个学生”
- 看看这些学生最后大多数通过了还是没通过
- 用多数结果给新学生投票
如果最近的 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=(x1−x1′)2+(x2−x2′)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=1 和 K=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 更像是在说“你像谁”
- 决策树更像是在说“你满足哪些条件”
更多推荐


所有评论(0)