Scikit-learn KNeighborsClassifier 实战:Iris 数据集 5 折交叉验证调参指南
2026/7/6 12:25:22 网站建设 项目流程

Scikit-learn KNeighborsClassifier 实战:Iris 数据集 5 折交叉验证调参指南

在机器学习领域,k近邻(k-Nearest Neighbors, kNN)算法以其直观性和有效性著称。本文将带您深入实战,使用Scikit-learn库对经典Iris数据集进行kNN模型调优,重点演示如何通过网格搜索和交叉验证找到最佳超参数组合。

1. 环境准备与数据加载

首先确保已安装必要的Python库。建议使用conda或pip安装scikit-learn、numpy、matplotlib和seaborn。以下是初始化代码:

import numpy as np import matplotlib.pyplot as plt from sklearn import datasets from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import GridSearchCV from sklearn.preprocessing import StandardScaler import seaborn as sns # 加载Iris数据集 iris = datasets.load_iris() X = iris.data y = iris.target feature_names = iris.feature_names target_names = iris.target_names

Iris数据集包含150个样本,每个样本有4个特征(萼片长度、萼片宽度、花瓣长度、花瓣宽度),分为3类鸢尾花。我们先进行简单的数据探索:

print(f"特征矩阵形状: {X.shape}") print(f"类别分布: {np.bincount(y)}") plt.figure(figsize=(10,6)) sns.pairplot(data=pd.DataFrame(X, columns=feature_names), diag_kind='kde', plot_kws={'alpha':0.6}) plt.suptitle('Iris数据集特征分布', y=1.02) plt.show()

2. 数据预处理与标准化

kNN算法对特征尺度敏感,因此标准化是必要步骤。我们使用StandardScaler将特征缩放到均值为0、方差为1的标准正态分布:

scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 标准化前后对比 fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,5)) sns.boxplot(data=X, ax=ax1).set_title('原始数据') sns.boxplot(data=X_scaled, ax=ax2).set_title('标准化后数据') plt.tight_layout()

标准化后的箱线图显示各特征已处于相同量纲,这将确保距离计算的公平性。

3. 超参数网格搜索设计

kNN有三个关键超参数需要优化:

  1. n_neighbors (k值):决定参与投票的邻居数量
  2. weights:距离权重策略(uniform或distance)
  3. p:距离度量参数(1为曼哈顿距离,2为欧氏距离)

我们使用GridSearchCV进行5折交叉验证搜索:

param_grid = { 'n_neighbors': range(1, 21), 'weights': ['uniform', 'distance'], 'p': [1, 2] } knn = KNeighborsClassifier() grid_search = GridSearchCV(knn, param_grid, cv=5, scoring='accuracy', n_jobs=-1) grid_search.fit(X_scaled, y)

4. 结果分析与可视化

获取最佳参数组合和交叉验证结果:

print(f"最佳参数: {grid_search.best_params_}") print(f"最佳准确率: {grid_search.best_score_:.3f}") # 提取所有参数组合结果 cv_results = pd.DataFrame(grid_search.cv_results_) top_results = cv_results.sort_values('rank_test_score').head(10)

为直观展示参数影响,我们绘制热力图:

# 筛选p=2的结果 p2_results = cv_results[cv_results['param_p']==2] heatmap_data = p2_results.pivot_table(index='param_n_neighbors', columns='param_weights', values='mean_test_score') plt.figure(figsize=(10,6)) sns.heatmap(heatmap_data, annot=True, fmt=".3f", cmap="YlGnBu") plt.title('不同k值和权重策略下的准确率热力图(p=2)') plt.xlabel('权重策略') plt.ylabel('k值') plt.show()

典型的热力图会显示:

  • 较小k值(1-3)时模型容易过拟合
  • 中等k值(5-10)通常表现最佳
  • distance权重策略在多数情况下优于uniform

5. 最佳模型验证与决策边界

使用最佳参数重新训练模型,并可视化决策边界:

best_knn = grid_search.best_estimator_ # 选择两个主要特征进行可视化 X_2d = X_scaled[:, :2] # 仅使用前两个特征 best_knn_2d = KNeighborsClassifier(**grid_search.best_params_) best_knn_2d.fit(X_2d, y) # 生成网格点 x_min, x_max = X_2d[:, 0].min() - 1, X_2d[:, 0].max() + 1 y_min, y_max = X_2d[:, 1].min() - 1, X_2d[:, 1].max() + 1 xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02)) # 预测每个网格点 Z = best_knn_2d.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) # 绘制决策边界 plt.figure(figsize=(10,6)) plt.contourf(xx, yy, Z, alpha=0.4, cmap='viridis') sns.scatterplot(x=X_2d[:,0], y=X_2d[:,1], hue=y, palette='viridis', edgecolor='k') plt.xlabel(feature_names[0]) plt.ylabel(feature_names[1]) plt.title('kNN决策边界可视化(基于前两个特征)') plt.legend(target_names) plt.show()

决策边界图清晰展示了kNN的分类逻辑——基于局部邻域进行决策。边界形状会随k值变化:

  • 小k值:边界复杂,可能过拟合
  • 大k值:边界平滑,可能欠拟合

6. 实际应用建议与注意事项

基于本次实验,我们总结以下工程实践要点:

  1. k值选择黄金法则

    • 对于小型数据集(n<100),k通常取3-5
    • 中型数据集(100<n<1000),k取5-10
    • 大型数据集(n>1000),k可取√n
  2. 距离加权策略对比

    策略优点缺点
    uniform计算简单忽略距离信息
    distance更精确对噪声敏感
  3. 常见陷阱与解决方案

    • 维度灾难:当特征数过多时,考虑特征选择或降维
    • 计算效率:使用KD树或Ball Tree加速近邻搜索
    • 类别不平衡:采用加权投票或调整类别权重
# 高效近邻搜索示例 from sklearn.neighbors import KDTree kdtree = KDTree(X_scaled) distances, indices = kdtree.query(X_scaled[:1], k=5) print(f"最近5个邻居的索引: {indices}")
  1. 扩展技巧
    • 尝试不同的距离度量(余弦相似度、马氏距离等)
    • 结合特征重要性进行加权距离计算
    • 对超参数搜索空间进行贝叶斯优化
# 特征加权距离计算示例 feature_weights = np.array([0.2, 0.1, 0.5, 0.2]) # 假设花瓣长度最重要 X_weighted = X_scaled * feature_weights

通过本指南,您已掌握使用Scikit-learn实现kNN分类的完整流程。实际项目中,建议将调参过程封装为可复用的Pipeline,并结合业务需求持续优化模型性能。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询