跳到主要内容
K-近邻算法(KNN)原理、流程与 Python 实战案例 | 极客日志
Python AI 算法
K-近邻算法(KNN)原理、流程与 Python 实战案例 综述由AI生成 K-近邻算法(KNN)是一种非参数化、懒惰学习的监督学习算法,适用于分类和回归任务。核心思想是通过计算样本间距离找到最近的 K 个邻居进行预测。 KNN 的距离度量方法(欧氏、曼哈顿等)、数学表达、算法流程及 Python 代码实现。内容涵盖 K 值选择策略(交叉验证、肘部法则)、距离度量影响、加权 KNN 以及回归任务的具体应用。最后总结了 KNN 的优缺点及工程实践建议,如特征归一化和 KD 树优化。
全栈工匠 发布于 2026/4/5 更新于 2026/5/24 28 浏览K-近邻算法(KNN)详细全流程详解与案例
一、KNN 算法简介
K-近邻算法(K-Nearest Neighbors, KNN)是一种非参数化 、懒惰学习 的监督学习算法,可用于分类和回归任务。KNN 的核心思想是:对一个新样本,找到训练集中距离最近的 K 个邻居,根据这些邻居的类别或数值来预测新样本的类别或数值 。
分类任务(Classification) :采用多数投票原则,K 个邻居中出现最多的类别为预测类别。
回归任务(Regression) :取 K 个邻居的均值作为预测值。
二、KNN 算法原理与数学表达
1. 距离度量
KNN 的关键在于如何度量样本间的距离。常用距离有:
其他:汉明距离(Hamming)、余弦距离(Cosine)等
闵可夫斯基距离(Minkowski Distance):
曼哈顿距离(Manhattan Distance):
欧氏距离(Euclidean Distance):
2. KNN 分类数学表达
对一个新样本 $x$,KNN 的预测类别 $\hat{y}$ 为:
其中 $y_{(i)}$ 为距离 $x$ 最近的第 $i$ 个训练样本的类别。
3. KNN 回归数学表达
对一个新样本 $x$,KNN 的预测值 $\hat{y}$ 为:
其中 $y_{(i)}$ 为最近 K 个邻居的真实数值。
三、KNN 算法详细流程
Step 1:准备数据
收集并整理训练数据集,包含特征和标签。
对特征进行归一化或标准化(KNN 对尺度敏感)。
Step 2:选择距离度量方式
Step 3:确定 K 值
K 是超参数,需通过交叉验证或'肘部法则'选择。
K 太小易受噪声影响,K 太大则可能欠拟合。
Step 4:预测新样本
对于每个新样本,计算其与所有训练样本的距离。
选出距离最近的 K 个邻居。
分类任务:统计 K 个邻居中出现最多的类别作为预测结果。
回归任务:取 K 个邻居的均值作为预测结果。
Step 5:评估与调优
用测试集评估模型准确率或均方误差。
调整 K 值、距离度量方式等参数优化模型。
四、KNN 案例流程与完整代码演示 我们用一组二维点(2D Points)作为训练集,类别用颜色区分。新样本点用 KNN 算法预测其类别,并可视化决策边界。
1. 数据准备与可视化 import matplotlib.pyplot as plt
import numpy as np
X_train = np.array([[1 ,2 ],[2 ,3 ],[3 ,1 ],[6 ,5 ],[7 ,7 ],[8 ,6 ]])
y_train = np.array([0 ,0 ,0 ,1 ,1 ,1 ])
plt.scatter(X_train[y_train==0 ,0 ], X_train[y_train==0 ,1 ], color='blue' , label='Class 0' )
plt.scatter(X_train[y_train==1 ,0 ], X_train[y_train==1 ,1 ], color='red' , label='Class 1' )
plt.xlabel('X1' )
plt.ylabel('X2' )
plt.title('KNN Training Data' )
plt.legend()
plt.show()
2. 用 KNN 预测新样本 import matplotlib.pyplot as plt
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
X_train = np.array([[1 ,2 ],[2 ,3 ],[3 ,1 ],[6 ,5 ],[7 ,7 ],[8 ,6 ]])
y_train = np.array([0 ,0 ,0 ,1 ,1 ,1 ])
knn = KNeighborsClassifier(n_neighbors=3 )
knn.fit(X_train, y_train)
X_test = np.array([[3 ,4 ],[7 ,5 ]])
y_pred = knn.predict(X_test)
print ("Predicted classes:" , y_pred)
3. 可视化决策边界 import matplotlib.pyplot as plt
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
X_train = np.array([[1 ,2 ],[2 ,3 ],[3 ,1 ],[6 ,5 ],[7 ,7 ],[8 ,6 ]])
y_train = np.array([0 ,0 ,0 ,1 ,1 ,1 ])
knn = KNeighborsClassifier(n_neighbors=3 )
knn.fit(X_train, y_train)
X_test = np.array([[3 ,4 ],[7 ,5 ]])
y_pred = knn.predict(X_test)
print ("Predicted classes:" , y_pred)
h = .02
x_min, x_max = X_train[:, 0 ].min () - 1 , X_train[:, 0 ].max () + 1
y_min, y_max = X_train[:, 1 ].min () - 1 , X_train[:, 1 ].max () + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = knn.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3 , cmap=plt.cm.RdBu)
plt.scatter(X_train[y_train==0 ,0 ], X_train[y_train==0 ,1 ], color='blue' , label='Class 0' )
plt.scatter(X_train[y_train==1 ,0 ], X_train[y_train==1 ,1 ], color='red' , label='Class 1' )
plt.scatter(X_test[:,0 ], X_test[:,1 ], color='green' , marker='*' , s=200 , label='Test Points' )
plt.xlabel('X1' )
plt.ylabel('X2' )
plt.title('KNN Decision Boundary (K=3)' )
plt.legend()
plt.show()
五、KNN 进阶内容与工程实践
1. K 值选择与模型表现
K 太小(如 K=1) :模型对噪声敏感,容易过拟合(Overfitting) ,决策边界复杂。
K 太大 :模型过于平滑,容易欠拟合(Underfitting),决策边界简单。
交叉验证(Cross Validation) :在训练集上用不同 K 值测试,选择准确率最高的 K 。
'肘部法则' :画出 K 与错误率的关系曲线,选择拐点处的 K 。
KNN 在'月牙形'数据集上的 K 值交叉验证 的示例代码(K 值交叉验证):
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score
X, y = make_moons(n_samples=60 , noise=0.5 , random_state=42 )
plt.scatter(X[y==0 ,0 ], X[y==0 ,1 ], color='blue' , label='Class 0' , alpha=0.6 )
plt.scatter(X[y==1 ,0 ], X[y==1 ,1 ], color='red' , label='Class 1' , alpha=0.6 )
plt.title('Noisy Moons Dataset (n=60, noise=0.5)' )
plt.legend()
plt.show()
cv = 5
max_k = 20
k_range = range (1 , max_k+1 )
scores = []
for k in k_range:
knn = KNeighborsClassifier(n_neighbors=k)
score = cross_val_score(knn, X, y, cv=cv, scoring='accuracy' ).mean()
scores.append(score)
plt.plot(k_range, scores, marker='o' )
plt.xlabel('K' )
plt.ylabel('Cross-validated Accuracy' )
plt.title('K Selection for KNN on Noisy Moons (n=60, noise=0.5)' )
plt.grid(True )
plt.show()
best_k = k_range[np.argmax(scores)]
print (f"Best K: {best_k} , Best CV Accuracy: {max (scores):.3 f} " )
print ("All scores:" , scores)
make_moons 生成了一个有噪声、非线性可分的二分类数据集,非常适合演示 KNN 的 K 值选择。
cross_val_score 对每个 K 进行 5 折交叉验证,记录平均准确率。
scores 曲线 显示不同 K 值下模型的泛化能力。
K=1 时 ,模型容易过拟合噪声点,准确率较低。
K 变大后 ,模型对噪声不敏感,准确率提升,达到一个峰值(通常在 K=5~10)。
K 再变大 ,模型变得过于平滑,欠拟合,准确率下降。
最佳 K 值 就是准确率最高处,对应的 K 值就是你应该选择的 K。
你会看到一条**'先上升后下降'**的曲线,这就是 K 值选择的意义所在。
注:有时候,K 值到很大的情况 Acc 依然很高,那是因为噪声(Noise)太少了。而现实情况中,噪声是一定会出现的。因此 K 值不是越高越好,而是能适配最大部分情况为佳!
KNN 的 K 值选择在数据量小、噪声大、类别分布不均时作用最明显。
真实业务 中,务必用交叉验证和多 K 对比来选择最优 K,避免模型过拟合或欠拟合。
2. 距离度量的选择与影响
欧氏距离 :适合连续型、尺度一致的特征。
曼哈顿距离 :对异常值更鲁棒,适合稀疏特征。
闵可夫斯基距离 :p 参数可调节距离的'敏感度'。
余弦距离 :适合文本、方向型特征。
汉明距离 :适合离散/二值特征。
在 sklearn 中可通过 metric 参数设置:
knn = KNeighborsClassifier(n_neighbors=3 , metric='manhattan' )
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
X_train = np.array([[1 ,2 ],[2 ,3 ],[3 ,1 ],[6 ,5 ],[7 ,7 ],[8 ,6 ]])
y_train = np.array([0 ,0 ,0 ,1 ,1 ,1 ])
knn = KNeighborsClassifier(n_neighbors=3 , metric='manhattan' )
knn.fit(X_train, y_train)
X_test = np.array([[3 ,4 ],[7 ,5 ]])
y_pred = knn.predict(X_test)
print ("Manhattan KNN Predicted classes:" , y_pred)
3. 加权 KNN 加权 KNN 会根据距离远近给邻居不同权重,距离越近权重越高,常用权重函数为倒数权重:
knn = KNeighborsClassifier(n_neighbors=3 , weights='distance' )
这样,预测时距离近的邻居影响更大,模型对边界点更敏感。
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
import matplotlib.pyplot as plt
X_train = np.array([[1 ,2 ],[2 ,3 ],[3 ,1 ],[6 ,5 ],[7 ,7 ],[8 ,6 ]])
y_train = np.array([0 ,0 ,0 ,1 ,1 ,1 ])
knn = KNeighborsClassifier(n_neighbors=3 , weights='distance' )
knn.fit(X_train, y_train)
X_test = np.array([[3 ,4 ],[7 ,5 ]])
y_pred = knn.predict(X_test)
print ("Weighted KNN Predicted classes:" , y_pred)
h = .02
x_min, x_max = X_train[:, 0 ].min () - 1 , X_train[:, 0 ].max () + 1
y_min, y_max = X_train[:, 1 ].min () - 1 , X_train[:, 1 ].max () + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = knn.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3 , cmap=plt.cm.RdBu)
plt.scatter(X_train[y_train==0 ,0 ], X_train[y_train==0 ,1 ], color='blue' , label='Class 0' )
plt.scatter(X_train[y_train==1 ,0 ], X_train[y_train==1 ,1 ], color='red' , label='Class 1' )
plt.scatter(X_test[:,0 ], X_test[:,1 ], color='green' , marker='*' , s=200 , label='Test Points' )
plt.xlabel('X1' )
plt.ylabel('X2' )
plt.title('Weighted KNN Decision Boundary (K=3)' )
plt.legend()
plt.show()
4. KNN 回归 KNN 不仅能做分类,也能做回归。KNN 回归的预测值为 K 个邻居的均值或加权均值。
下面是一个更复杂的 KNN 回归案例 ,包括带噪声的非线性数据、不同权重的 KNN 回归曲线、可视化和详细流程解释,非常适合理解 KNN 回归的行为和调参意义。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsRegressor
np.random.seed(42 )
X_train = np.sort(5 * np.random.rand(40 , 1 ), axis=0 )
y_train = np.sin(X_train).ravel() + 0.3 * np.random.randn(40 )
X_test = np.linspace(0 , 5 , 500 )[:, np.newaxis]
knn_uniform = KNeighborsRegressor(n_neighbors=5 , weights='uniform' )
knn_distance = KNeighborsRegressor(n_neighbors=5 , weights='distance' )
knn_uniform.fit(X_train, y_train)
knn_distance.fit(X_train, y_train)
y_pred_uniform = knn_uniform.predict(X_test)
y_pred_distance = knn_distance.predict(X_test)
plt.figure(figsize=(10 , 6 ))
plt.scatter(X_train, y_train, color='darkorange' , label='Training data' )
plt.plot(X_test, y_pred_uniform, color='navy' , label='Uniform weights' )
plt.plot(X_test, y_pred_distance, color='c' , label='Distance weights' )
plt.title('KNN Regression with Uniform and Distance Weights' )
plt.xlabel('X' )
plt.ylabel('y' )
plt.legend()
plt.show()
1. 数据生成
用正弦函数加高斯噪声生成 40 个训练点,模拟现实中非线性、带噪声的回归问题。
2. 测试点
用 np.linspace 生成 0~5 区间的 500 个点,便于画出平滑的 KNN 回归曲线。
3. KNN 回归模型
weights='uniform':每个邻居权重相同,预测值为 K 个邻居的简单平均。(普通的 KNN 算法)
weights='distance':距离越近的邻居权重越高,预测值为加权平均,更贴近局部数据。(权重和距离成反比)
4. 训练与预测
5. 可视化解析
橙色散点为训练样本。
蓝色曲线(uniform)和青色曲线(distance)分别为两种 KNN 回归预测结果。
可以看到 distance 权重的预测曲线在训练点附近更贴近真实数据,尤其在边界和噪声点多的地方。
6. 小结
KNN 回归示例:带噪声的正弦数据上,使用 uniform 和 distance 权重的预测曲线对比
KNN 回归可以拟合非线性关系,但 K 值和权重对结果影响很大。
距离加权的 KNN 回归在边界或噪声多时表现更好。
你可以调整 n_neighbors、weights、噪声大小等参数 ,观察模型拟合能力和泛化能力的变化。
5. KNN 的优缺点与工程建议
实现简单,无需训练过程,易于理解和可解释。
适用于多分类、多回归问题。
对异常值不敏感(K 较大时)。
预测时计算量大,需遍历全部训练集(可用 KD 树等优化)。
对特征尺度敏感,需标准化或归一化。
对高维数据效果差(维度灾难)。
K 值和距离度量需调优。
特征需归一化/标准化,避免尺度影响距离计算。
可用交叉验证选 K 和距离度量。
大数据集可用 KD 树、球树等加速查找。
适合特征维度较低、样本量中等的场景。
六、KNN 算法总结 K-近邻算法(KNN)是最经典的**'懒惰学习'**方法之一,凭借简单直观、无模型假设、易于实现等优点,广泛应用于分类、回归、推荐、异常检测等领域。KNN 的核心思想是'以邻为师',通过距离度量和多数投票实现预测。实际应用中,建议合理选择 K 值、距离度量和特征预处理方法,并结合数据规模和业务需求优化模型。
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
随机西班牙地址生成器 随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online