【机器学习】KNN算法与模型评估调优

发布于:2025-08-01 ⋅ 阅读:(22) ⋅ 点赞:(0)

目录

一、写在前面的话

二、KNN(K-Nearest Neighbor)

2.1 KNN算法介绍

2.1.1 概念介绍

2.1.2 算法特点

2.1.3 API 讲解

2.2 样本距离计算

2.2.1 距离的类型

(1)欧几里得距离(Euclidean Distance)

(2)曼哈顿距离(Manhattan Distance)

(3)切比雪夫距离(Chebyshev Distance)

(4)余弦相似度(Cosine Similarity)

(5)汉明距离(Hamming Distance)

2.2.2 举例讲解计算过程

(1)计算欧几里得距离

(2)选取K个邻居

(3)投票预测

2.3 算法的缺陷

(1)计算复杂度高

(2)内存开销大

(3)对噪声敏感

(4)维度灾难

(5)选择K值困难

三、模型的评估

3.1 评估指标

3.1.1 对于分类

(1)准确率(Accuracy)

(2)精确度(Precision)

(3)召回率(Recall)

(4)F1-score

3.1.2 对于回归

(1)均方误差(MSE, Mean Squared Error)

(2)均方根误差(RMSE, Root Mean Squared Error)

(3)平均绝对误差(MAE, Mean Absolute Error)

3.2 交叉验证

3.2.1 K折交叉验证(K-Fold Cross-Validation)

(1)介绍

(2)步骤讲解

(3)举例演示

(4)优缺点

3.2.2 留一交叉验证(Leave-One-Out Cross-Validation,LOO)

3.2.3 分层K折交叉验证(Stratified K-Fold Cross-Validation)

3.2.4 随机交叉验证(Shuffle Split)

四、模型的优化

4.1 优化方法

(1)超参数调优

(2)集成学习(Ensemble Learning)

(3)偏差-方差权衡(Bias-Variance Tradeoff)

(4)正则化技术

4.2 超参数调优

4.2.1 概念介绍

4.2.2 方法分类

4.2.3 网格搜索法介绍

(1)方法步骤

(2)优缺点分析

(3)代码案例


一、写在前面的话

        本篇文章将以scikit-learn学习库使用KNN算法进行分类的介绍与演示,通过对KNN的学习进而引出关于模型的评估与优化的概念,重点介绍交叉验证网格搜索方法。

        机器学习零基础的读者可以先去学习一下上一篇文章“新手入门”:

【机器学习】机器学习新手入门概述-CSDN博客

二、KNN(K-Nearest Neighbor)

2.1 KNN算法介绍

2.1.1 概念介绍

  • KNN(K-Nearest Neighbor)(也称为K-近邻算法)是一种简单的监督学习算法,主要用于分类和回归问题。
  • 其基于一个非常直观的原则:对于一个新的样本,KNN算法通过找到距离它最近的K个已知样本,根据这些K个样本的标签(在分类问题中是类别,在回归问题中是数值)来进行预测。

2.1.2 算法特点

  • KNN算法没有真正的训练过程(距离计算的预处理不算入真正训练),其只是保存所有训练样本及其标签。

2.1.3 API 讲解

class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, algorithm='auto')

参数:                                             
(1)n_neighbors: 
        int, default=5, 默认情况下用于kneighbors查询的近邻数,就是K
(2)algorithm:
    {‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, default=’auto’。找到近邻的方式,注意不是计算距离的方式,与机器学习算法没有什么关系,开发中请使用默认值'auto'

方法:
 (1) fit(x, y) 
        使用X作为训练数据和y作为目标数据  
 (2) predict(X)    预测提供的数据,得到预测数据  

2.2 样本距离计算

        KNN算法依赖于距离度量进行相似度判断。根据选择的距离计算方式,KNN的预测结果将会有所不同。一般来说,欧几里得距离常用于连续型数据的分类和回归问题,而对于文本数据,可能会使用余弦相似度来判断相似度。

2.2.1 距离的类型

(1)欧几里得距离(Euclidean Distance)

最常见的距离度量方法,适用于连续型变量

  • 其中,x = (x1,x2,…,xn) 和 y = (y1,y2,…,yn) 分别是两个样本的特征向量,n是特征的维数。
(2)曼哈顿距离(Manhattan Distance)

曼哈顿距离也叫做城市街区距离,表示两点在坐标轴上的绝对距离之和。

(3)切比雪夫距离(Chebyshev Distance)

切比雪夫距离是两点在任一坐标轴上的最大距离。

(4)余弦相似度(Cosine Similarity)

用于衡量两个向量的夹角,适用于文本分类等场景,余弦相似度越大表示两个样本越相似。

两个向量越接近,它们之间的夹角越小,余弦值越接近 1,表示它们的相似度越高。

  • 其中x * y为两个向量的点积,∥x∥2 和 ∥y∥2 分别是两个向量的 L2 范数。
  • L1范数:各元素绝对值之和,用于稀疏表示。
  • L2范数:各个元素的平方和的平方根,常用于度量向量的“大小”。

(5)汉明距离(Hamming Distance)

汉明距离用于衡量两个等长字符串之间的不同位置的个数。

  • 例如,对于二进制字符串 x = 10101 y = 10011,它们的汉明距离为2。

2.2.2 举例讲解计算过程

假设我们根据X1和X2特征可以预测出标签Label,即苹果或是橘子。

现在我们有一个待分类的点 X =(4, 4),要预测它是苹果还是橘子。

X1 X2 Label
1 1 苹果
2 1 苹果
3 2 苹果
6 5 橘子
7 5 橘子
8 6 橘子
(1)计算欧几里得距离

(2)选取K个邻居

超参数设置,这里我们选择 K = 3,距离最小的三个点是:(3, 2),  (6, 5),  (7, 5),它们的标签分别是:苹果、橘子、橘子。

(3)投票预测

根据K个最近邻的标签(苹果、橘子、橘子),投票结果是橘子。

2.3 算法的缺陷

(1)计算复杂度高

KNN在测试阶段需要计算所有训练样本与测试样本之间的距离,因此当训练数据集非常大时,KNN的预测速度会非常慢。

(2)内存开销大

由于KNN需要保存所有训练数据来进行预测,它的内存消耗也相对较大。

(3)对噪声敏感

KNN对噪声数据非常敏感,尤其是在K值较小的时候,噪声点可能会对最终的分类结果产生很大的影响。

(4)维度灾难

当数据集的特征维度过高时,样本间的距离趋于相似,KNN算法会变得不那么有效。这是因为高维空间的“稀疏性”使得所有样本的距离差异变得不明显,导致分类效果下降。

(5)选择K值困难

选择合适的K值对于KNN算法的性能至关重要。若K值过小,模型容易过拟合;若K值过大,可能会出现欠拟合。

三、模型的评估

        模型评估是机器学习过程中的一个重要环节,目的是衡量模型的性能和预测准确性,并通过不同的评估指标来比较和选择最佳模型。评估的目的是评估模型在未见数据上的表现,确保其不仅仅在训练集上有良好的效果,而是在实际应用中也能稳定表现。

3.1 评估指标

3.1.1 对于分类

(1)准确率(Accuracy)

最直观的评估指标,指的是模型正确预测的样本占总样本的比例

(2)精确度(Precision)

衡量正类预测准确度,定义为正类预测中实际为正的比例。

(3)召回率(Recall)

衡量模型识别正类的能力,定义为所有实际为正类样本中被正确预测为正的比例。

(4)F1-score

精确度和召回率的调和平均值,兼顾了二者的表现,特别适用于类别不平衡的情况。

参数解析:

  • TP(True Positives)真阳性:指的是模型正确地将正类样本预测为正类的数量
  • FP(False Positives)假阳性:指的是模型错误地将负类样本预测为正类的数量
  • FN(False Negatives)假阴性:指的是模型错误地将正类样本预测为负类的数量 

3.1.2 对于回归

(1)均方误差(MSE, Mean Squared Error)

衡量预测值与真实值之间差异的平方平均值,越小表示模型越好。

(2)均方根误差(RMSE, Root Mean Squared Error)

MSE的平方根,具有与原数据相同的单位,便于理解。

(3)平均绝对误差(MAE, Mean Absolute Error)

计算预测值与实际值之间的绝对差的平均值,越小越好。

3.2 交叉验证

交叉验证(Cross-Validation,简称CV),主要目的是为了更稳健地评估模型的性能,避免模型在某一特定训练集上的过拟合或欠拟合,从而提高模型的泛化能力。现在将其放在评估这里来讲解。

3.2.1 K折交叉验证(K-Fold Cross-Validation)

(1)介绍

最常用的交叉验证方法,其基本思想是将数据集分成K个互不重叠的子集(折叠),然后进行K次训练和验证。每次训练时,选择一个子集作为验证集,其余K-1个子集作为训练集。

(2)步骤讲解
  • 将数据集随机分成K个大小相同的子集。
  • 选择其中一个子集作为验证集,剩余的K-1个子集作为训练集,训练模型并评估在验证集上的表现。
  • 重复步骤2,直到每个子集都做过一次验证集。
  • 最终的评估结果是所有K次验证结果的平均值。
(3)举例演示

假设有一个数据集,随机划分成5个子集,用5折交叉验证来评估一个分类模型的性能:

  • 第1轮:用子集1、2、3、4作为训练集,用子集5作为验证集,训练模型并评估其性能。

  • 第2轮:用子集1、2、3、5作为训练集,用子集4作为验证集,训练模型并评估其性能。

  • 第3轮:用子集1、2、4、5作为训练集,用子集3作为验证集,训练模型并评估其性能。

  • 第4轮:用子集1、3、4、5作为训练集,用子集2作为验证集,训练模型并评估其性能。

  • 第5轮:用子集2、3、4、5作为训练集,用子集1作为验证集,训练模型并评估其性能。

对于每一轮的评估,我们可以得到一个评估指标(如准确率、精确度、召回率等),最后计算5轮评估结果的平均值,作为模型的最终评估结果。

(4)优缺点

优点

  • 更高的可靠性:相比单一的训练/测试划分,K折交叉验证能更稳定地评估模型性能。
  • 每个样本都有机会成为验证集:每个数据点都可以参与训练和测试,提高了评估结果的泛化能力。

缺点

  • 计算开销大:K折交叉验证需要进行K次训练和验证,如果数据集非常大,计算量和时间开销也会增加。

3.2.2 留一交叉验证(Leave-One-Out Cross-Validation,LOO)

(1)介绍

留一交叉验证是K折交叉验证的极端情况,其中K等于数据集的大小(即每次训练时,只用一个样本作为验证集,其余的样本用来训练模型)。这意味着对于数据集中的每一个样本,都需要训练和验证一次模型。

(2)优缺点

  • 优点:每个样本都能单独作为验证集,评估结果非常可靠。

  • 缺点计算成本高:对于非常大的数据集,LOO需要进行大量的训练和验证,计算量巨大。

3.2.3 分层K折交叉验证(Stratified K-Fold Cross-Validation)

(1)介绍

        在K折交叉验证中,如果数据集的标签分布不均衡,某些类别可能在某些折叠中没有足够的样本,导致模型评估不准确。分层K折交叉验证就是在进行数据集划分时,保持每个子集中的类别分布尽可能和原始数据集相似。即每个折叠中各类别样本的比例与整个数据集中的比例一致。

(2)分析

  • K-Fold交叉验证技术中,整个数据集被划分为K个大小相同的部分。每个分区被称为 一个”Fold”。所以我们有K个部分,我们称之为K-Fold。一个Fold被用作验证集,其余的K-1个Fold被用作训练集。
  • 该技术重复K次,直到每个Fold都被用作验证集,其余的作为训练集。
  • 模型的最终准确度是通过取k个模型验证数据的平均准确度来计算的。

3.2.4 随机交叉验证(Shuffle Split)

(1)介绍

随机交叉验证是一种简单的交叉验证方法。它随机地将数据集分成训练集和验证集,并在多次重复中进行评估。每次划分训练集和验证集时,都是随机的,因此每次划分的验证集和训练集都不同。

(2)优缺点

  • 优点:计算量相对较小,且可以任意选择训练集和验证集的比例。

  • 缺点:数据划分可能不稳定,尤其是在类别不平衡时,可能会造成某些类别的数据在验证集中没有出现。

四、模型的优化

主要目标是通过调整模型的超参数、改进模型结构处理数据的方式,来提高模型的预测精度和泛化能力。

4.1 优化方法

这里先简单列一下优化模型的常见方法:

(1)超参数调优

常见方法:

  • 网格搜索(Grid Search):对所有可能的超参数组合进行穷举式搜索,找到最优的超参数组合。

  • 随机搜索(Random Search):从所有可能的超参数中随机采样一部分进行测试。

  • 贝叶斯优化(Bayesian Optimization):利用贝叶斯推断的思想,通过先前的尝试结果预测最有可能的最优超参数。

  • 遗传算法(Genetic Algorithm):模拟自然选择的过程,用于优化超参数。

(2)集成学习(Ensemble Learning)

通过将多个模型的预测结果结合起来,来提升模型的整体性能。

常见方法有:

  • Bagging(如随机森林)

  • Boosting(如XGBoost、LightGBM、CatBoost)

  • Stacking:将不同模型的预测作为输入,使用另一种模型进行预测。

(3)偏差-方差权衡(Bias-Variance Tradeoff)

通过调整模型复杂度,找到偏差和方差之间的平衡,避免过拟合或欠拟合。

(4)正则化技术

  • L1 正则化(Lasso):通过加入L1惩罚项,强迫某些特征的权重变为零,从而起到特征选择的作用。

  • L2 正则化(Ridge):通过加入L2惩罚项,减小权重的大小,避免某些特征过度影响模型。

  • Dropout:常用于深度学习中,在训练过程中随机丢弃部分神经元,减少过拟合。

4.2 超参数调优

4.2.1 概念介绍

        超参数调优是机器学习中的一个关键步骤,它通过寻找最优的超参数来提高模型的性能。超参数是指那些在训练过程中不能通过学习算法自动获得的参数,它们通常需要由人工设定,比如决策树的最大深度、SVM的核函数类型、神经网络的学习率等。其目标是找到一组最优的超参数,使得模型在给定的任务和数据集上表现最好。

4.2.2 方法分类

(1)手动调优:基于经验和直觉选择超参数。

(2)网格搜索(Grid Search):系统地遍历超参数空间,最常用的一种方法。

(3)随机搜索(Random Search):在超参数空间中随机选择参数组合进行尝试

(4)贝叶斯优化(Bayesian Optimization):基于贝叶斯推理模型,逐步调整超参数。

4.2.3 网格搜索法介绍

网格搜索是一种暴力穷举法,它通过指定一组超参数的候选值,在这些候选值中进行遍历,测试每一组超参数组合,选出最优组合。

(1)方法步骤
  • 定义超参数空间:为每个超参数选择一个范围或集合,通常是多个可能的值。

  • 创建所有可能的超参数组合:将每个超参数的可能值组合成一个“网格”。如果有多个超参数,每个超参数的值都会与其它超参数的值组合。

  • 模型训练与评估:对每一组超参数组合,都训练一个模型,并通过交叉验证(或其他评估方法)评估模型的性能。

  • 选择最优超参数组合:根据模型的性能指标(如准确率、F1分数等)选择最优的超参数组合。

(2)优缺点分析

1、优点:

  • 简单直观:易于实现,理解和应用。
  • 确保找到最优解:如果给定的参数空间足够全面,可以确保找到最优超参数。

2、缺点:

  • 计算开销大:随着超参数数量和每个超参数的取值范围增加,网格搜索的计算量呈指数增长。例如,如果有3个超参数,每个有3个候选值,那么需要尝试27种组合。
  • 可能错过最佳组合:如果超参数空间过于粗糙,可能错过最佳的超参数组合。
(3)代码案例

使用KNN算法对scikit-learn的鸢尾花数据集进行分类,使用网格搜索交叉验证进行优化。

PS:网格搜索通常会与交叉验证一起使用,尤其是在数据较少的情况下。交叉验证通过将数据集分成多个子集,并进行多次训练和评估,能够避免过拟合问题,提供更可靠的性能评估。

# 用KNN算法对鸢尾花进行分类,添加网格搜索和交叉验证
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV

def knn_iris_gscv():
    # 1)获取数据
    iris = load_iris()
    
    # 2)划分数据集
    x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)
    
    # 3)特征工程:标准化
    transfer = StandardScaler()
    x_train = transfer.fit_transform(x_train)
    x_test = transfer.transform(x_test)
   
    # 4)KNN算法预估器, 这里就不传参数n_neighbors了,交给GridSearchCV来传递
    estimator = KNeighborsClassifier()
    # 加入网格搜索与交叉验证, GridSearchCV会让k分别等于1,2,5,7,9,11进行网格搜索偿试。cv=10表示进行10次交叉验证
    estimator = GridSearchCV(estimator, param_grid={"n_neighbors": [1, 3, 5, 7, 9, 11]}, cv=10)
    estimator.fit(x_train, y_train)

    # 5)模型评估
    # 方法1:直接比对真实值和预测值
    y_predict = estimator.predict(x_test)
    print("y_predict:\n", y_predict)
    print("直接比对真实值和预测值:\n", y_test == y_predict)

    # 方法2:计算准确率
    score = estimator.score(x_test, y_test)
    print("在测试集中的准确率为:\n", score)  #0.9736842105263158

    # 最佳参数:best_params_
    print("最佳参数:\n", estimator.best_params_) #{'n_neighbors': 3}, 说明k=3时最好
    # 最佳结果:best_score_
    print("在训练集中的准确率:\n", estimator.best_score_)  #0.9553030303030303
    # 最佳估计器:best_estimator_
    print("最佳估计器:\n", estimator.best_estimator_) # KNeighborsClassifier(n_neighbors=3)
    # 交叉验证结果:cv_results_
    print("交叉验证过程描述:\n", estimator.cv_results_)
    #最佳参数组合的索引:最佳k在列表中的下标
    print("最佳参数组合的索引:\n",estimator.best_index_)
    
    #通常情况下,直接使用best_params_更为方便
    return None

knn_iris_gscv()


网站公告

今日签到

点亮在社区的每一天
去签到