跳到主要内容

K 近邻分类

一、直观理解:听最近邻居的投票​

K 近邻(K-Nearest Neighbors, KNN)几乎不“训练”参数模型:新样本到来时,在训练集中找距离最近的 KK 个点,按多数表决(或距离加权表决)决定类别。

好比搬到一个陌生小区,想知道“这里适不适合开咖啡馆”。你不会先建复杂方程,而是看看最近几家店的类型和人流——邻居的构成就是你的判断依据。

KNN 是基于实例的懒惰学习:计算主要发生在预测阶段。决策边界可以非常曲折,因为边界由局部样本几何决定,而不是一条全局直线。

二、适用场景与优缺点​

类型说明
适用场景类别由局部相似性决定;特征维数不太高;需要简单强基线;决策边界可能高度非线性;样本量中等、可承受预测时距离计算。
核心优点原理直观;几乎无训练阶段;天然支持多分类;可做回归(邻域平均);非参数,不预设全局线性形式。
局限与缺点预测慢、占内存;对量纲与无关特征敏感;高维时距离集中,“远近”失真;K 与距离度量需调;类别不平衡时多数类易主导投票。

使用前检查:

  1. 数值特征是否已标准化或按业务加权;
  2. 是否存在大量无关/噪声维;
  3. 类别是否严重不平衡;
  4. 是否有足够近邻(稀疏区域 KNN 不可靠);
  5. 预测时延与存储是否可接受。

三、核心原理​

给定训练集 {(xi,yi)}i=1n\{(x_i,y_i)\}_{i=1}^n,距离 d(⋅,⋅)d(\cdot,\cdot)(常用欧氏、曼哈顿、闵可夫斯基)。对查询点 xx,取邻域

NK(x)={与 x 距离最小的 K 个训练点}N_K(x)=\{\text{与 }x\text{ 距离最小的 }K\text{ 个训练点}\}

硬投票预测:

y^(x)=arg⁡max⁡c∑i∈NK(x)1(yi=c)\hat y(x)=\arg\max_c\sum_{i\in N_K(x)}\mathbf{1}(y_i=c)

距离加权投票(近者权重大):

y^(x)=arg⁡max⁡c∑i∈NK(x)wi1(yi=c),wi=1d(x,xi)+ε\hat y(x)=\arg\max_c\sum_{i\in N_K(x)}w_i\mathbf{1}(y_i=c),\quad w_i=\frac{1}{d(x,x_i)+\varepsilon}

概率可近似为邻域内各类频率。K=1K=1 时边界最曲折、方差大;KK 增大则边界更平滑、偏差上升。

维数灾难:在高维空间,最近邻与最远邻距离趋于接近,邻域“局部性”被削弱。此时应降维、特征选择,或换模型。

四、关键决策​

决策点建议
KK奇数可减少两类平票;用交叉验证扫 K=1,3,5,…K=1,3,5,\ldots
距离连续特征默认欧氏;坐标型/稀疏可试曼哈顿;相关性强可试马氏距离
标准化必须(除非特征已同量纲且同等重要)
权重squaredinverse 或 inverse 常优于均匀投票
不平衡过采样、加权投票或评价改用宏平均 F1
高维先 PCA/筛选特征,或改用树模型/线性模型
划分按实体分层划分,KNN 对泄漏极敏感

五、MATLAB 示例​

% 二维玩具数据:两类
X = [
1.0 1.1;
1.2 0.9;
0.8 1.0;
3.0 3.1;
3.2 2.9;
2.8 3.0;
1.5 1.4;
2.7 2.8
];
y = [1; 1; 1; 2; 2; 2; 1; 2];

% 标准化(用训练集均值方差)
mu = mean(X);
sigma = std(X);
Xz = (X - mu) ./ sigma;

% 拟合 KNN:K=3,距离加权
Mdl = fitcknn(Xz, y, ...
"NumNeighbors", 3, ...
"Distance", "euclidean", ...
"DistanceWeight", "squaredinverse", ...
"Standardize", false); % 已手动标准化

% 交叉验证选择 K
ks = 1:2:7;
cvLoss = zeros(size(ks));
for i = 1:numel(ks)
mdl = fitcknn(Xz, y, "NumNeighbors", ks(i), ...
"DistanceWeight", "squaredinverse");
cvLoss(i) = kfoldLoss(crossval(mdl, "KFold", 4));
end
[~, bestIdx] = min(cvLoss);
bestK = ks(bestIdx);
fprintf("CV 最优 K = %d, loss = %.3f\n", bestK, cvLoss(bestIdx));

Mdl = fitcknn(Xz, y, "NumNeighbors", bestK, ...
"DistanceWeight", "squaredinverse");

% 新样本预测(必须用同一 mu, sigma)
xnew = [1.1, 1.0];
xnewz = (xnew - mu) ./ sigma;
[label, score, cost] = predict(Mdl, xnewz);
fprintf("预测类别 = %d\n", label);
disp("各类得分:"); disp(score);

% 训练集表现(演示用;正式应看 hold-out)
yhat = predict(Mdl, Xz);
disp(confusionmat(y, yhat));

大规模数据可考虑 KD 树/K 维搜索(NSMethod)或近似最近邻;赛题样本量通常可直接穷举距离。

六、如何解释结果​

  1. 邻域构成:列出对某预测贡献最大的邻居及其标签,增强可解释性;
  2. KK 与边界:较小 KK 贴合训练噪声,较大 KK 更平滑;
  3. 距离权重:说明是否因“更近样本”改变了投票结果;
  4. 错误模式:边界样本、离群点、少数类是否系统性被吞没;
  5. 报告内容:KK、距离、是否标准化、CV 方式、各类精确率/召回率。

KNN 没有“系数表”,解释应落在局部案例对比上,而不是全局公式。

七、常见误区​

1. 不标准化就算欧氏距离​

“收入(万元)”与“年龄”混用时,距离几乎只由数值大的特征决定。

2. 固定 K=1K=1 或 K=nK=\sqrt{n} 而不验证​

经验公式不能代替交叉验证。

3. 在高维稀疏特征上硬用 KNN​

文本 bag-of-words 等场景通常余弦+线性模型或朴素贝叶斯更合适。

4. 先全数据 SMOTE 再划分训练测试​

泄漏会导致虚高准确率;重采样只在训练折内进行。

5. 把训练误差当泛化能力​

KNN 在 K=1K=1 时训练误差可到 0,完全没有参考价值。

八、小结​

KNN 用“与谁最像”做分类:标准化特征空间中取 KK 个近邻,投票或加权投票得到标签与近似概率。

它是最干净的非线性基线之一,适合中小样本、局部结构清晰的问题。维数一高、噪声一多,就要配合特征工程或换模型;调参焦点永远是 KK、距离、标准化与验证协议。