Bootstrap

KNN算法

一、KNN算法核心原理

K近邻(K-Nearest Neighbors) 是一种基于实例的监督学习算法,主要用于分类回归任务。其核心思想是:相似样本在特征空间中彼此接近

1️⃣ 算法步骤
  1. 计算距离:测试样本与所有训练样本的距离
  2. 选择邻居:选取距离最近的K个样本
  3. 投票决策
    • 分类:统计K个邻居中最多类别
    • 回归:取K个邻居的平均值
2️⃣ 关键公式
  • 欧式距离(默认)
    d ( x , y ) = ∑ i = 1 n ( x i − y i ) 2 d(x,y) = \sqrt{\sum_{i=1}^n (x_i - y_i)^2} d(x,y)=i=1n(xiyi)2
  • 多数表决分类
    y ^ = arg ⁡ max ⁡ c ∑ i = 1 k I ( y i = c ) \hat{y} = \arg\max_{c} \sum_{i=1}^k \mathbb{I}(y_i = c) y^=argcmaxi=1kI(yi=c)

二、核心参数解析

参数作用推荐设置方法
n_neighbors选择邻居数量K交叉验证选择(通常3-15)
weights邻居权重(uniform/distance)特征差异大时用distance
metric距离度量(欧式/曼哈顿/余弦)根据数据分布选择
algorithm搜索算法(brute/kd_tree等)数据量大时用kd_tree

三、Python代码实战

1️⃣ 手动实现(理解原理)
import numpy as np
from collections import Counter

class MyKNN:
    def __init__(self, k=5):
        self.k = k
        
    def fit(self, X, y):
        self.X_train = X
        self.y_train = y
        
    def predict(self, X):
        y_pred = [self._predict(x) for x in X]
        return np.array(y_pred)
        
    def _predict(self, x):
        # 计算欧式距离
        distances = np.sqrt(np.sum((self.X_train - x)**2, axis=1))
        # 取前k个邻居
        k_indices = np.argsort(distances)[:self.k]
        k_labels = self.y_train[k_indices]
        # 多数表决
        return Counter(k_labels).most_common(1)[0][0]
2️⃣ Scikit-learn生产级实现
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline

# 创建包含标准化的流水线
knn_pipeline = make_pipeline(
    StandardScaler(),  # 关键!消除量纲影响
    KNeighborsClassifier(
        n_neighbors=7,
        weights='distance',
        metric='euclidean'
    )
)
knn_pipeline.fit(X_train, y_train)

四、KNN优缺点分析

优点
  • 直观易理解:符合人类直觉
  • 无需训练:惰性学习(Lazy Learning)
  • 适应非线性:适合复杂决策边界
缺点
  • 计算成本高:预测时需计算全部样本距离
  • 维度灾难:高维数据效果显著下降
  • 类别不平衡敏感:少数类易被忽略

五、工业级优化策略

1️⃣ 加速查询
  • KD-Tree:适用于低维数据(D < 20)
  • Ball-Tree:适合高维数据
  • LSH(局部敏感哈希):近似最近邻搜索
2️⃣ 处理高维数据
from sklearn.decomposition import PCA

# 保留95%方差
pca = PCA(n_components=0.95)
X_reduced = pca.fit_transform(X)
knn.fit(X_reduced, y)
3️⃣ 类别不平衡处理
# 调整类别权重
knn = KNeighborsClassifier(
    weights='distance',
    class_weight='balanced'  # 关键参数
)

六、实战案例:手写数字识别

1️⃣ 数据准备
from sklearn.datasets import load_digits
digits = load_digits()
X, y = digits.data, digits.target
2️⃣ 性能评估
from sklearn.model_selection import cross_val_score

scores = cross_val_score(knn_pipeline, X, y, cv=5)
print(f"平均准确率:{scores.mean():.2%}")
# 典型输出:平均准确率:97.33%
3️⃣ 可视化决策边界
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

# 降维可视化
pca = PCA(n_components=2)
X_vis = pca.fit_transform(X)
knn.fit(X_vis, y)

# 绘制决策边界
x_min, x_max = X_vis[:,0].min()-1, X_vis[:,0].max()+1
y_min, y_max = X_vis[:,1].min()-1, X_vis[:,1].max()+1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
                     np.arange(y_min, y_max, 0.1))
Z = knn.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

plt.contourf(xx, yy, Z, alpha=0.4)
plt.scatter(X_vis[:,0], X_vis[:,1], c=y, s=20, edgecolor='k')
plt.title('KNN决策边界可视化')
plt.show()

七、KNN常见面试题

  1. 如何选择最佳K值?

    • 使用交叉验证,观察不同K值的准确率变化曲线
  2. KNN为什么需要归一化?

    • 避免量纲大的特征主导距离计算
  3. KNN与K-Means的区别?

    • KNN是监督学习,K-Means是无监督聚类
  4. 如何处理KNN的时间复杂度?

    • 使用KD-Tree/Ball-Tree优化,或采样减少训练集规模
;