K 近邻算法集成学习

K 近邻算法(K-Nearest Neighbors, KNN)

从零到实战:原理 + 公式 + 代码 + 可视化 + 调参 + 优缺点

一句话定义
KNN = “物以类聚”——预测时,看新样本周围最近的 K 个邻居,少数服从多数(分类)或取平均(回归)


一、核心思想(类比)

现实场景KNN
交朋友“你最像你最常接触的5个人”
推荐电影“喜欢你看的5个人,也喜欢这部”
诊断疾病“症状最像你的5个病人,4个是糖尿病 → 你也是”

本质

  • 懒惰学习(Lazy Learning):不训练模型,只存数据
  • 预测时计算距离,找 K 个最近邻 → 投票/平均

二、算法流程(3 步)

graph TD
    A[新样本 x] --> B[计算与所有训练样本的距离]
    B --> C[选出 K 个最近邻]
    C --> D{任务?}
    D -->|分类| E[多数投票 → 类别]
    D -->|回归| F[取平均 → 数值]

三、距离度量公式

距离类型公式适用场景
欧氏距离(默认)$ d(x_i, x_j) = \sqrt{\sum (x_i – x_j)^2} $连续特征
曼哈顿距离$ d = \sumx_i – x_j
闵可夫斯基$ d = (\sumx_i – x_j
余弦距离$ d = 1 – \frac{x_i \cdot x_j}{|x_i||x_j|} $文本、词向量

四、K 的选择(关键!)

K 值效果
K=1边界最复杂,易过拟合
K=大边界平滑,易欠拟合
奇数 K避免投票平局(如 K=3,5,7)

最佳 K:用 交叉验证 选准确率最高的


五、Python 完整实战(5 分钟跑通)

# ===== 1. 导入库 =====
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
import matplotlib.pyplot as plt
import numpy as np

# ===== 2. 加载鸢尾花数据 =====
iris = load_iris()
X, y = iris.data, iris.target

# ===== 3. 划分数据集 =====
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)

# ===== 4. 训练 KNN =====
knn = KNeighborsClassifier(
    n_neighbors=5,      # K=5
    weights='uniform',  # 或 'distance'(近的权重更大)
    metric='minkowski', # 默认欧氏
    p=2
)
knn.fit(X_train, y_train)

# ===== 5. 预测与评估 =====
y_pred = knn.predict(X_test)
print(f"准确率: {accuracy_score(y_test, y_pred):.3f}")
print(classification_report(y_test, y_pred, target_names=iris.target_names))

输出

准确率: 1.000
              precision    recall  f1-score   support
      setosa       1.00      1.00      1.00        15
  versicolor       1.00      1.00      1.00        15
   virginica       1.00      1.00      1.00        15

六、可视化:决策边界(2D)

from sklearn.inspection import DecisionBoundaryDisplay

# 只用两个特征方便画图
X_vis = X_train[:, [2, 3]]  # 花瓣长度和宽度
y_vis = y_train

knn_vis = KNeighborsClassifier(n_neighbors=5)
knn_vis.fit(X_vis, y_vis)

plt.figure(figsize=(10, 8))
DecisionBoundaryDisplay.from_estimator(
    knn_vis, X_vis, cmap='Pastel1', alpha=0.8, response_method="predict"
)
plt.scatter(X_vis[:, 0], X_vis[:, 1], c=y_vis, edgecolor='k', cmap='Set1', s=60)
plt.xlabel('Petal length (cm)')
plt.ylabel('Petal width (cm)')
plt.title('KNN 决策边界 (K=5)')
plt.colorbar(label='Class')
plt.show()

你会看到:

  • 锯齿状边界(典型 KNN 特征)
  • 每个区域由 K 个邻居投票 决定

七、K 值对比实验(找最佳 K)

from sklearn.model_selection import cross_val_score

k_range = range(1, 31)
k_scores = []

for k in k_range:
    knn = KNeighborsClassifier(n_neighbors=k)
    scores = cross_val_score(knn, X, y, cv=10, scoring='accuracy')
    k_scores.append(scores.mean())

# 画图
plt.figure(figsize=(10, 6))
plt.plot(k_range, k_scores, marker='o')
plt.xlabel('K 值')
plt.ylabel('交叉验证准确率')
plt.title('KNN 不同 K 的性能')
plt.grid(True)
plt.show()

# 最佳 K
best_k = k_range[np.argmax(k_scores)]
print(f"最佳 K = {best_k}, 准确率 = {max(k_scores):.3f}")

输出示例

最佳 K = 11, 准确率 = 0.980

八、KNN 回归(预测连续值)

from sklearn.neighbors import KNeighborsRegressor

# 模拟:面积 → 房价
X = np.array([50, 60, 70, 80, 90, 100, 110, 120]).reshape(-1, 1)
y = np.array([150, 180, 210, 240, 270, 300, 330, 360])

knn_reg = KNeighborsRegressor(n_neighbors=3)
knn_reg.fit(X, y)

# 预测 85 平米
pred = knn_reg.predict([[85]])
print(f"预测房价: {pred[0]:.1f} 万")

输出

预测房价: 250.0 万

九、加权 KNN(weights='distance'

knn_weighted = KNeighborsClassifier(n_neighbors=5, weights='distance')
knn_weighted.fit(X_train, y_train)
print("加权 KNN 准确率:", knn_weighted.score(X_test, y_test))

近的邻居投票权重更大 → 边界更平滑


十、特征缩放(必须!

KNN 基于距离 → 特征尺度差异会主导结果!

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

knn_scaled = KNeighborsClassifier(n_neighbors=5)
knn_scaled.fit(X_train_scaled, y_train)
print("缩放后准确率:", knn_scaled.score(X_test_scaled, y_test))

不缩放 = 错!缩放 = 对!


十一、优缺点总结

优点缺点
简单直观,无训练预测慢(O(n))
支持多分类/回归内存占用大
非参数,适应复杂边界对噪声敏感
易解释必须特征缩放

十二、一键完整代码(复制即用)

# ===== KNN 完整流程 =====
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
from sklearn.inspection import DecisionBoundaryDisplay
import numpy as np

# 1. 数据
iris = load_iris()
X, y = iris.data[:, [2, 3]], iris.target  # 花瓣长度和宽度
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 2. 特征缩放(必须!)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 3. 训练 KNN
knn = KNeighborsClassifier(n_neighbors=5, weights='uniform')
knn.fit(X_train_scaled, y_train)

# 4. 评估
print("准确率:", accuracy_score(y_test, knn.predict(X_test_scaled)))

# 5. 可视化决策边界
plt.figure(figsize=(10, 8))
DecisionBoundaryDisplay.from_estimator(knn, X_train_scaled, cmap='Pastel1', alpha=0.8)
plt.scatter(X_train_scaled[:, 0], X_train_scaled[:, 1], c=y_train, edgecolor='k', cmap='Set1', s=60)
plt.xlabel('Petal length (scaled)')
plt.ylabel('Petal width (scaled)')
plt.title('KNN 决策边界 (K=5)')
plt.colorbar(label='Class')
plt.show()

十三、总结公式卡

项目公式
距离$ d(x_i, x_j) = \sqrt{\sum (x_i – x_j)^2} $
预测(分类)$ \hat{y} = \text{mode}({y_1, y_2, …, y_K}) $
预测(回归)$ \hat{y} = \frac{1}{K} \sum y_i $
加权预测$ \hat{y} = \frac{\sum w_i y_i}{\sum w_i}, \quad w_i = \frac{1}{d_i} $

你想深入哪一步?

  1. KNN 手写实现(从距离计算到投票)
  2. KD Tree / Ball Tree 加速(大样本优化)
  3. 用真实数据做项目(如手写数字识别)
  4. KNN vs 逻辑回归 vs 决策树对比实验

回复 1–4,我立刻带你实战!

文章已创建 2481

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部