当前位置: 首页 > news >正文

【人工智能-17】机器学习:KNN算法、模型选择和调优、朴素贝叶斯分类

上一期【人工智能-16】机器学习:概念、工具介绍、数据集、特征工程

文章目录

  • 一 、KNN算法
    • 1. 应用理由
    • 2. 原理核心:距离度量 + 多数投票/平均
    • 3. 优点和缺点
  • 二、模型选择和调优
    • 1.使用理由
    • 2.原理核心:数据划分与性能平均
    • 3.超参数搜索
    • 4. 应用场景总结
  • 三、朴素贝叶斯分类
    • 1.使用理由
    • 2.原理核心:贝叶斯定理 + 条件独立假设
    • 3.优点和缺点

一 、KNN算法

  • KNN 是一种基本的、惰性学习 (Lazy Learning)监督学习算法,主要用于分类回归任务。
  • 核心思想: “物以类聚,人以群分”。对于一个待预测的新样本,在特征空间中找出与它最相似的 K 个训练样本(即“最近邻”),然后根据这 K 个邻居的信息来预测新样本的类别(分类)或值(回归)。
  • 惰性学习: KNN 在训练阶段仅存储训练数据集,不进行任何显式的模型构建。所有的计算(主要是距离计算)都推迟到预测阶段进行。

1. 应用理由

  • 简单直观,易于理解和实现: 算法原理非常直接,没有复杂的数学推导。
  • 无需显式训练: 节省了训练时间(但预测时间可能较长)。
  • 非参数方法: 不对数据的基础分布做任何假设,适用于各种形状的数据分布。
  • 天然支持多分类: 处理多类别问题非常自然。
  • 对新的训练样本增量更新友好: 只需将新样本加入存储的训练集即可,无需重新训练整个模型。
  • 适用于特征间关系复杂的情况: 只要定义了合适的距离度量,就能工作。

2. 原理核心:距离度量 + 多数投票/平均

  1. 选择距离度量: 衡量特征空间中样本间“相似度”或“距离”。常用距离包括:
    • 欧氏距离 (Euclidean Distance): 最常用,计算多维空间中的直线距离。公式核心:各维度差值的平方和再开方。
      将x和x1的差值平方加上x和x2的差值的平方,然后对结果开方
    • 曼哈顿距离 (Manhattan Distance): 计算各维度绝对差值的总和。对异常值比欧氏距离稍鲁棒。
      x和x1相减的差的绝对值加上x和x2相减的差的绝对值,最后的和就是曼哈顿距离。
    • 闵可夫斯基距离 (Minkowski Distance): 欧氏距离和曼哈顿距离的泛化。
    • 余弦相似度 (Cosine Similarity): 衡量向量方向的一致性,常用于文本分类。
  2. 选择 K 值: 需要人为指定的超参数,表示要考虑的最近邻的数量。
  3. 预测阶段:
    • 分类:
      1. 计算待预测样本与训练集中所有样本的距离。
      2. 找出距离最近的 K 个训练样本
      3. 统计这 K 个邻居中出现次数最多的类别
      4. 将该类别作为待预测样本的类别(多数投票法)。
    • 回归:
      1. 计算待预测样本与训练集中所有样本的距离。
      2. 找出距离最近的 K 个训练样本。
      3. 计算这 K 个邻居目标值的平均值
      4. 将该平均值作为待预测样本的预测值。
import joblib
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
x_train,x_test,y_train,y_test = train_test_split(X,y,train_size=0.8,random_state=22)# 特征工程:标准化
# 之所以只对x进行标准化,是因为要取消x的单位,并使x中过大的特征值不会影响训练结果
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 模型训练
model = KNeighborsClassifier(n_neighbors=7)
model.fit(x_train,y_train)# 模型评估
y_predict = model.predict(x_test)
print(y_predict)
print(y_test)
print(y_predict == y_test)
# score = np.sum(y_predict == y_test) / len(y_test)
score = model.score(x_test,y_test)
print(score)
# 模型保存
joblib.dump(model,'../src/model/KNN.pkl')
joblib.dump(transfer,'../src/model/transfer.pkl')
# 预测
x_new = [[4.2,2.6,1.8,0.9],[5.2,3.6,1.8,0.9],[1.2,1.6,1.8,2.9]]
x_new = transfer.transform(x_new)
y_new = model.predict(x_new)
print(y_new)
result = iris.target_names[y_new]
print(result)

3. 优点和缺点

  • 优点:
    • 简单直观,易于理解和实现。
    • 无需训练阶段(惰性学习)。
    • 非参数,对数据分布无假设。
    • 天然支持多分类。
    • 对新的训练样本增量更新友好。
  • 缺点:
    • 预测阶段计算量大,速度慢: 需要计算待测样本与所有训练样本的距离,时间复杂度高。不适合大数据集或实时预测。
    • 对特征尺度和相关性敏感: 不同特征的量纲(单位)差异大或特征高度相关时,距离度量会失真。必须进行特征标准化/归一化。
    • 对高维数据效果差(维数灾难): 在高维空间中,数据点趋于稀疏,距离度量变得不那么有意义且计算效率更低。
    • 需要选择合适的 K 值和距离度量: K 值选择对结果影响很大:
      • K 太小:模型复杂,对噪声敏感,容易过拟合(决策边界崎岖)。
      • K 太大:模型简单,可能忽略数据局部特征,容易欠拟合(决策边界平滑)。
    • 对不平衡数据集敏感: 多数类容易主导投票结果。
    • 存储开销大: 需要存储整个训练数据集。
      所以基本不使用了

二、模型选择和调优

  • 这些是用于评估机器学习模型性能比较不同模型或算法以及调整模型超参数(如 KNN 中的 K,决策树的最大深度,SVM 的 C 和 gamma)的关键技术。它们的目标是在未见过的数据上获得对模型泛化能力的可靠估计,避免仅依赖训练数据评估导致的过度乐观(过拟合)。
  • 核心问题: 如何充分利用有限的数据,既训练模型又可靠地评估其泛化能力?
  • 基本流程: 将数据集划分为训练集 (Training Set) 用于模型训练/参数学习,验证集 (Validation Set) 用于模型选择和超参数调优,测试集 (Test Set) 用于最终评估选定模型的泛化能力。交叉验证方法通过多次划分来更充分地利用数据。

1.使用理由

  • 获得可靠的泛化性能估计: 防止模型在训练集上过拟合,评估其在真实未知数据上的表现。
  • 模型选择: 比较不同模型(如逻辑回归 vs 随机森林 vs SVM)在相同数据集上的性能,选择最优模型。
  • 超参数调优: 为选定的模型算法,系统地搜索最佳超参数组合(如网格搜索、随机搜索),避免手动试错。
  • 充分利用有限数据: 特别是在数据集较小时,交叉验证方法通过多次划分和平均,比单次留出法提供更稳定、偏差更小的性能估计。
  • 减少评估结果的方差: 单次随机划分训练/测试集可能导致评估结果波动较大。交叉验证通过多次评估取平均来降低这种方差。

2.原理核心:数据划分与性能平均

  1. 保留交叉验证 (Hold-Out Validation / Train-Validation-Test Split):
    • 原理: 将原始数据集 一次性 随机划分为三个互斥的子集:
      • 训练集 (Training Set): 用于训练模型(学习模型参数)。
      • 验证集 (Validation Set): 用于在训练过程中评估模型性能,指导模型选择或超参数调优。调整模型行为(如选择超参数)就是基于在验证集上的表现。
      • 测试集 (Test Set): 用于在模型选择和超参数调优过程完全结束后,对最终选定的模型进行一次性的、无偏的性能评估。测试集在调优过程中绝对不能使用。
    • 关键点:
      • 划分比例常见如:训练 60-80%,验证 10-20%,测试 10-20%。
      • 优点: 简单、快速、计算开销小。
      • 缺点:
        • 评估结果高度依赖于单次随机划分。如果划分“不幸运”,评估结果可能不能代表模型真实性能(高方差)。
        • 数据利用率低: 用于训练/调优的数据量减少了(被验证集和测试集占用)。
        • 在小数据集上,验证集/测试集样本可能太少,导致评估不稳定。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_splitx,y = load_iris(return_X_y=True)
# 划分为训练集和测试集 stratify=y 表示训练集和测试集的标签分布要一致
x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.8,random_state=22,stratify=y)
# 将测试集划分为测试集和验证集
x_test,x_val,y_test,y_val = train_test_split(x_test,y_test,train_size=0.5,random_state=22,stratify=y)
print(y_test)
  1. k 折交叉验证 (k-Fold Cross-Validation):
    • 原理: 解决留出法评估方差大和数据利用率低的问题。
      1. 将原始数据集随机划分为 k 个大小基本相等的互斥子集(称为“折”或“份”,Folds)。
      2. 依次进行 k 次训练和验证:
        • 每次使用 k-1 个折的数据作为训练集
        • 使用剩下的 1 个折的数据作为验证集
      3. 计算模型在每次验证集上的性能指标(如准确率、F1)。
      4. 计算这 k 次性能指标的平均值,作为模型泛化性能的估计。
      5. 可选: 使用全部数据(k 折都用上了)重新训练最终模型(使用通过交叉验证确定的最佳超参数)。
      6. 独立的测试集仍然需要用于最终评估(如果可用)。
    • 关键点:
      • k 是超参数,常用值为 5 或 10。
      • 优点:
        • 显著降低评估结果的方差(相比单次留出法),结果更稳定可靠。
        • 数据利用率高: 每个样本都被用作验证集恰好一次,同时有 (k-1)/k 的数据用于训练。特别适合数据集较小的情况。
      • 缺点:
        • 计算开销大: 需要训练 k 个模型。当 k 很大或模型训练很慢时,代价高昂。
        • 划分仍是随机的,如果数据分布有特殊结构(如严重类别不平衡),随机 k 折可能导致某些折中某些类别的样本极少或缺失。
# KFold 
from sklearn.model_selection import KFoldx,y = load_iris(return_X_y=True)
# KFold(n_splits,shuffle,random_state)
# n_splits:要划分的折数默认为5 shuffle:是否打乱数据,默认为False  random_state:随机数种子
k = KFold(n_splits=5,shuffle=True,random_state=22)
re = k.split(x,y)
print(next(re))
print(next(re))
  1. 分层 k 折交叉验证 (Stratified k-Fold Cross-Validation):
    • 原理: 针对分类问题中随机 k 折可能破坏类别分布的问题。它是 k 折交叉验证的变体。
      • 在划分每一折时,确保每个折中各个类别的样本比例与原始数据集中的整体比例尽可能保持一致
    • 关键点:
      • 优点:
        • 保留了 k 折交叉验证降低方差、高数据利用率的优点。
        • 尤其适用于类别不平衡的数据集。能保证每个折都包含所有类别的代表样本(即使数量很少),使性能评估更公平、更稳定、偏差更小。
      • 缺点: 计算开销同 k 折交叉验证。主要应用于分类问题,回归问题有时也可用(保持目标值分布)。
from sklearn.model_selection import StratifiedKFoldx,y = load_iris(return_X_y=True)
# StratifiedKFold(n_splits,shuffle,random_state)
k = StratifiedKFold(n_splits=5,shuffle=True,random_state=22)
re = k.split(x,y)
print(next(re))
print(next(re))

3.超参数搜索

超参数搜索也叫网格搜索(Grid Search)

比如在KNN算法中,k是一个可以人为设置的参数,所以就是一个超参数。网格搜索能自动的帮助我们找到最好的超参数值。

class sklearn.model_selection.GridSearchCV(estimator, param_grid)说明:
同时进行交叉验证(CV)、和网格搜索(GridSearch),GridSearchCV实际上也是一个估计器(estimator),同时它有几个重要属性:best_params_  最佳参数best_score_ 在训练集中的准确率best_estimator_ 最佳估计器cv_results_ 交叉验证过程描述best_index_最佳k在列表中的下标
参数:estimator: scikit-learn估计器实例param_grid:以参数名称(str)作为键,将参数设置列表尝试作为值的字典示例: {"n_neighbors": [1, 3, 5, 7, 9, 11]}cv: 确定交叉验证切分策略,值为:(1)None  默认5(2)integer  设置多少折如果估计器是分类器,使用"分层k-折交叉验证(StratifiedKFold)"。在所有其他情况下,使用KFold。
from sklearn.model_selection import GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
x,y = load_iris(return_X_y=True)knn = KNeighborsClassifier(n_neighbors=6)
# GridSearchCV(estimator,param_grid,cv)
# estimator: 模型 param_grid: 参数字典 cv: 确定交叉验证切分策略,默认5折
model = GridSearchCV(knn,param_grid={'n_neighbors':[1,2,3,4,5,6,7,8,9,10]},cv=5)model.fit(x,y)
print(model.best_params_)
print(model.best_score_)
print(model.best_estimator_ == knn)# 使用模型print(model.predict(x))

4. 应用场景总结

  • 保留交叉验证: 数据集非常大、训练模型速度慢时,追求快速评估和调优。初步实验。
    实际使用时,一般都用这个方法。至于为什么用,因为数据量太大了,使用这个方法可能都要花费很长的时间,别说k折和分层k折(时间成本和计算资源的花费太大)。跟保留交叉验证的缺点一对比,还是保留交叉验证好。
  • k 折交叉验证: 数据集大小适中,需要更稳定、偏差更小的性能评估和超参数调优。
  • 分层 k 折交叉验证: 分类问题,特别是数据集较小或存在明显类别不平衡时。确

三、朴素贝叶斯分类

  • 朴素贝叶斯是一系列基于贝叶斯定理特征条件独立假设的简单概率分类器。
  • 核心思想: 计算给定样本特征条件下,该样本属于各个类别的后验概率,并将样本分到后验概率最大的那个类别。
  • “朴素 (Naive)” 源于其一个关键假设:所有特征在给定类别标签的条件下是相互独立的。这个假设在现实中往往不成立,但即使如此,朴素贝叶斯在实践中常常表现得出乎意料的好。

1.使用理由

  • 计算效率极高,训练和预测速度快: 训练阶段主要计算各种先验概率和条件概率(计数或估计密度),预测阶段只需计算少量概率乘积。非常适合大规模数据集和实时预测。
  • 易于实现且效果往往不错: 算法相对简单,实现容易。尽管条件独立假设很强,但在许多实际应用(尤其是文本分类、垃圾邮件过滤)中表现优异。
  • 对小规模数据表现良好: 即使训练数据量较少也能工作,不容易过拟合。
  • 能处理多分类问题。
  • 提供概率预测: 不仅能给出分类结果,还能给出样本属于每个类别的概率估计,这在需要不确定性度量的场景中很有用。

2.原理核心:贝叶斯定理 + 条件独立假设

  1. 贝叶斯定理: 核心公式是 P(Y|X) = [P(X|Y) * P(Y)] / P(X)
    • Y:类别变量。
    • X = (X1, X2, ..., Xn):特征向量(n 个特征)。
    • P(Y|X)后验概率。即在观察到特征 X 的条件下,样本属于类别 Y 的概率(我们想求的)。
    • P(Y)先验概率。即在未观察到任何特征时,样本属于类别 Y 的概率(根据训练数据中各类别的频率估计)。
    • P(X|Y)似然 (Likelihood)。即在样本属于类别 Y 的条件下,观察到特征 X 的概率。
    • P(X)证据 (Evidence)。即观察到特征 X 的概率(对所有类别是相同的,在比较不同 Y 的后验概率时可忽略)。
  2. 目标: 对于给定的样本特征 X,找到使其后验概率 P(Y|X) 最大的那个类别 Y(最大后验估计 - MAP)。
  3. “朴素”条件独立假设: 假设所有特征 X1, X2, ..., Xn 在给定类别 Y 的条件下相互独立。这使得复杂的联合似然 P(X1, X2, ..., Xn | Y) 的计算变得简单:
    • P(X∣Y)=P(x1,x2,...,xn∣Y)=P(x1∣Y)P(x2∣Y)...P(xn∣Y)P(X|Y) = P(x_1, x_2, ..., x_n|Y) = P(x_1|Y)P(x_2|Y)...P(x_n|Y)P(XY)=P(x1,x2,...,xnY)=P(x1Y)P(x2Y)...P(xnY)
    • 即:联合似然 = 每个特征条件概率的乘积。
  4. 分类决策:
    • 将贝叶斯定理和条件独立假设结合:
      P(Y∣X)=P(x1∣Y)P(x2∣Y)...P(xn∣Y)P(Y)P(X)P(Y|X) = \frac{P(x_1|Y)P(x_2|Y)...P(x_n|Y)P(Y)}{P(X)}P(YX)=P(X)P(x1Y)P(x2Y)...P(xnY)P(Y)
    • 例:Y是好人,X是高富帅(x1x2x3就分别是高、富、帅)。想要得知高富帅中好人的概率,就要用好人中长得高的概率乘以好人中有钱的概率乘以好人中长得帅的概率乘以是好人的概率再除以是高富帅的概率,这个结果就是在高富帅中是好人的概率。
    • 这里只是举了一个高富帅中好人的例子,当然也可以算坏人的概率,或者在某种纹理某种颜色某种声音下是好西瓜的概率。我们都知道了这些概率,那么再有新的数据时根据这些概率选择计算结果最大的那个类别 Y 作为预测类别。
  5. 估计概率:
    • 先验概率 P(Y) 用训练数据中类别 Y 出现的频率估计:P(Y) = count(Y) / N (N 是总样本数)。
    • 条件概率 P(Xi | Y)
      • 离散特征: 用类别 Y 的样本中,特征 Xi 取特定值 x_i 的频率估计:P(Xi=x_i | Y) = count(Xi=x_i and Y) / count(Y)
      • 连续特征: 通常假设特征在给定类别下服从某种分布(如高斯分布),然后使用该类别下的样本估计分布的参数(如均值和方差),再用概率密度函数计算 P(Xi=x_i | Y)。常见的是高斯朴素贝叶斯 (Gaussian Naive Bayes)
from sklearn.naive_bayes import MultinomialNB
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_splitx,y = load_iris(return_X_y=True)x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.8,random_state=22)
# 由于贝叶斯模型是统计概率来进行预测的,所以不是固定的标签数据,预测不准确
model = MultinomialNB()
model.fit(x_train,y_train) # 统计先验概率
print(model.score(x_test,y_test))  # 0.6666666666666666

3.优点和缺点

  • 优点:
    • 训练和预测速度极快,计算效率高。
    • 实现简单,易于理解。
    • 对小规模数据有效,对缺失数据不太敏感。
    • 在多分类问题中表现良好。
    • 能够输出分类的概率估计。
    • 文本分类(如垃圾邮件检测、情感分析)等特征维度高且特征独立假设相对合理的领域表现尤为出色。
  • 缺点:
    • 核心缺点:“朴素”的条件独立假设在现实中往往不成立。 特征之间通常存在相关性。违反此假设会降低模型的准确性。
    • 概率估计可能不够准确: 虽然能输出概率,但基于强独立性假设得到的概率值可能不太可靠(尤其在特征相关性强时)。
    • 零概率问题: 如果测试数据中出现了一个在训练数据中某个类别下从未出现过的特征值,会导致该特征的条件概率为 0,从而使整个后验概率为 0。需要使用平滑技术(如拉普拉斯平滑 / Laplace Smoothing / Additive Smoothing)来解决:在计数时给每个特征值的出现次数加一个小的正数(通常为 1)。
    • 对输入数据的分布假设敏感: 对于连续特征,如果选择的分布(如高斯分布)与真实分布差异很大,会影响性能。
    • 特征重要性: 不如决策树或随机森林那样直观地提供特征重要性排序。
http://www.dtcms.com/a/310638.html

相关文章:

  • JS核心语法与实战技巧
  • 如何实现长时间录音的自动分段与文本生成?
  • 自定义View学习记录之 折线图View
  • 栈与队列的泛型实现
  • gcc g++ makefile CMakeLists.txt cmake make 的关系
  • [lvgl_player] 用户界面(LVGL) | 播放器核心设计
  • 桌面端界面设计 |货物 TMS 系统 - SaaS UI UX 设计:审美积累之境
  • 图像处理拉普拉斯算子
  • 进阶08:Winform编写与SQL Server通信范例
  • 【OD机试题解法笔记】考古学家考古问题
  • SOLIDWORKS材料明细表设置,属于自己的BOM表模板
  • 【数据结构】-----排序的艺术画卷
  • 上海月赛kk
  • 1.2.6 装配式混凝土建筑设计构造要求
  • LOVON——面向足式Open-Vocabulary的物体导航:LLM做任务分解、YOLO11做目标检测,最后L2MM将指令和视觉映射为动作(且解决动态模糊)
  • RAGFLOW~knowledge graph
  • JavaScript 中的对象继承:从浅入深
  • 2025牛客多校第六场D题解
  • Object对象中的常用方法
  • 当10米精度遇上64维AI大脑——Google全球卫星嵌入数据集(Satellite Embedding V1)全解析
  • 【华为机试】34. 在排序数组中查找元素的第一个和最后一个位置
  • 移动端 WebView 内存泄漏与性能退化问题如何排查 实战调试方法汇总
  • 文章发布Typecho网站技巧
  • Squid服务配置代理
  • SystemVerilog的系统函数和任务
  • Python 项目路径配置完全指南
  • C语言-字符串(定义)、字符串函数(strlen、strcat、strcpy、strcmp、strlwr、strupr)
  • 航天器VHF/UHF/L频段弱电磁信号兼容性设计
  • 【3】交互式图表制作及应用方法
  • Spring Cloud 和服务拆分:微服务落地的第一步