机器学习③【模型训练、K近邻算法(KNN)、贝叶斯算法(Navie Bayes)、模型调优】

发布于:2025-08-07 ⋅ 阅读:(17) ⋅ 点赞:(0)


先言

在机器学习的全流程中,模型训练与调优是决定最终效果的关键环节。优秀的特征工程为数据赋予了潜力,而选择合适的算法并优化其参数,才能真正释放数据的价值。本文将深入探讨 模型训练的基本流程,并重点介绍两种经典的机器学习算法——K近邻(KNN) 和 贝叶斯分类(Naive Bayes),帮助读者理解它们的原理、应用场景及调优技巧。

无论是分类、回归还是聚类问题,模型的选择与优化都直接影响预测的准确性和泛化能力。本文将从理论推导到代码实战,带你掌握如何训练、评估和优化模型,为实际业务问题提供可靠的解决方案。


一、机器学习模型训练的基本流程

在前面的章节机器学习的定义以及核心思想中有粗略地讲到过机器学习的基本流程,本次将结合模型的训练详细讲解一下模型机器学习中模型的训练以及调优的基本流程
在这里插入图片描述
这张图是否还熟悉在往期章节中我们对机器学习的每个步骤有过简单的了解,那我们该如何具体的探索每个步骤节点的具体含义呢,在这里你会得到答案。

1. 数据输入:数据是学习的基础

机器学习的第一步是数据收集。没有数据,机器学习模型无法进行训练。数据通常包括"输入特征"和"标签":
输入特征(Features): 这些是模型用来做预测或分类的信息。例如,在房价预测问题中,输入特征可以是房子的面积、地理位置、卧室数量等。
标签(Labels): 标签是我们想要预测或分类的结果,通常是一个数字或类别。例如,在房价预测问题中,标签是房子的价格。
机器学习模型的目标是从数据中找出输入特征与标签之间的关系,基于这些关系做出预测

2. 模型选择:选择合适的学习算法
机器学习模型(也叫做算法)是帮助计算机学习数据并进行预测的工具。根据数据的性质和任务的不同,常见的机器学习模型包括:
监督学习模型: 给定带有标签的数据,模型通过学习输入和标签之间的关系来做预测。例如,线性回归、逻辑回归、支持向量机(SVM) 和 决策树。
无监督学习模型: 没有标签的数据,模型通过探索数据中的结构或模式来进行学习。例如,K-means 聚类、主成分分析(PCA)。
强化学习模型: 模型在与环境互动的过程中,通过奖励和惩罚来学习最佳行为。例如,Q-learning、深度强化学习(Deep Q-Networks, DQN)。

3. 训练过程:让模型从数据中学习

在训练阶段,模型通过历史数据"学习"输入和标签之间的关系,通常通过最小化一个损失函数(Loss Function)来优化模型的参数。训练过程可以概括为以下步骤:

初始状态: 模型从随机值开始。比如,神经网络的权重是随机初始化的。
计算预测: 对于每个输入,模型会做出一个预测。这是通过将输入数据传递给模型,计算得到输出。
计算误差(损失): 误差是指模型预测的输出与实际标签之间的差异。例如,对于回归问题,误差可以通过均方误差(MSE)来衡量。
优化模型: 通过反向传播(在神经网络中)或梯度下降等优化算法,不断调整模型的参数(如神经网络的权重),使得误差最小化。这个过程就是训练,直到模型能够在训练数据上做出比较准确的预测。

4. 验证与评估:测试模型的性能
训练过程完成后,我们需要评估模型的性能。为了避免模型过度拟合训练数据,我们将数据分为训练集和测试集,其中:
训练集: 用于训练模型的部分数据。
测试集: 用于评估模型性能的部分数据,通常不参与训练过程。
常见的评估指标包括:
准确率(Accuracy): 分类问题中正确分类的比例。
均方误差(MSE): 回归问题中,预测值与真实值差的平方的平均值。
精确率(Precision)与召回率(Recall): 用于二分类问题,尤其是类别不平衡时。
F1分数: 精确率与召回率的调和平均数,综合考虑分类器的表现。
5. 优化与调整:提高模型的精度
如果模型在测试集上的表现不理想,可能需要进一步优化。这通常包括:
调整超参数(Hyperparameters): 比如学习率、正则化系数、树的深度等。这些超参数影响模型的学习能力。
模型选择与融合: 尝试不同的模型或模型融合(比如集成学习方法,如随机森林、XGBoost 等)来提高精度。
数据增强: 扩展训练数据集,比如对图像进行旋转、翻转等操作,帮助模型提高泛化能力。

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

再将算法之前我们需要了解一个东西就是向量距离的计算,在讲KNN算法之前我们相对“向量距离”做一些了解。

1.常见的距离算法:

1.1欧几里得(欧式)距离(Euclidean Distance)

image
Euclidean Distance是一个通常采用的距离定义,它是在m维空间中两个点之间的真实距离。

1.2 Earth Mover’s Distance (EMD距离)

和欧式距离一样,它们都是一种距离度量的定义、可以用来测量某两个分布之间的距离。EMD主要应用在图像处理和语音信号处理领域。
EMD问题通俗解释: Earth Move翻译过来是搬土,指把P位置的m个坑的土,用最小的代价搬到Q位置的n个坑中,dij是pi到qj两个坑的距离,fij是从pi搬到qj的土量,则WORK工作量就是要最小化的目标。线性规划求解出fij后,再用fij对WORK作个归一化,就得到了EMD。EMD 实际上是线性规划中运输问题的最优解。

1.3 曼哈顿距离(Manhattan Distance)

在这里插入图片描述
表示两个点在标准坐标系上的绝对轴距之和。也就是和象棋中的“車”一样横平竖直的走过的距离。曼哈顿距离是超凸度量。

1.4 杰卡德距离(Jaccard Distance)

在这里插入图片描述
用来衡量两个集合差异性的一种指标,它是杰卡德相似系数的补集,被定义为1减去Jaccard相似系数。适用于集合相似性度量,字符串相似性度量 。

1.5 马氏距离(Mahalanobis distance)

在这里插入图片描述
表示点与一个分布之间的距离。它是一种有效的计算两个未知样本集的相似度的方法。与欧氏距离不同的是,它考虑到各种特性之间的联系(例如:一条关于身高的信息会带来一条关于体重的信息,因为两者是有关联的),并且是尺度无关的(scale-invariant),即独立于测量尺度。修正了欧式距离中各个维度尺度不一致且相关的问题。

2.KNN算法原理核心思想

KNN 的全称是 K Nearest Neighbors,意思是 K 个最近的邻居。从这个名字我们就能看出一些 KNN 算法的蛛丝马迹了。K 个最近邻居,毫无疑问,K 的取值肯定是至关重要的,那么最近的邻居又是怎么回事呢?其实,KNN 的原理就是当预测一个新的值 x 的时候,根据它距离最近的 K 个点是什么类别来判断 x 属于哪个类别。

比如: 有10000个样本,选出7个到样本A的距离最近的,然后这7个样本中假设:类别1有2个,类别2有3个,类别3有2个.那么就认为A样本属于类别2,因为它的7个邻居中 类别2最多(近朱者赤近墨者黑)

3.KNN算法实现对红酒类别进行预测

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) 预测提供的数据,得到预测数据

代码如下:

from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
import numpy as np
import joblib
#获取数据集
wine = load_wine()
x = wine.data
y = wine.target
print('红酒类别',wine.target_names)
#对数据进行划分
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=33)
#数据标准化转化器
transfer = StandardScaler()
#转化器方法fit() 得到训练集的标准化参数
data_new = transfer.fit(x_train)
#转换方法transform() 获取训练集的转化数据
x_train = transfer.transform(x_train)
#创建模型对象
model = KNeighborsClassifier(n_neighbors=7)
#对模型进行训练
model.fit(x_train,y_train)
#保存模型
joblib.dump(model,'../src/model/KNeighborsClassifier.pkl')
#保存标准化转化器
joblib.dump(transfer,'../src/model/transfer.pkl')
#对测试集进行标准化转换
x_test = transfer.transform(x_test)
#对测试集进行预测
y_predict = model.predict(x_test)
print('预测结果为:',y_predict)
y = y_test==y_predict
print(y)
result = wine.target_names[y_predict]
print('预测结果为:',result)
#计算预测准确率
score = model.score(x_test,y_test)
print('准确率:',score)
print('准确率:',score)

运行结果如下:

红酒类别: ['class_0' 'class_1' 'class_2']
预测结果为: [0 0 1 0 2 0 0 0 2 2 0 2 0 1 2 1 1 1 0 2 2 1 0 1 1 1 1 2 2 1 1 2 2 0 0 2]
[ True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True False  True
  True  True  True  True  True  True  True  True  True False  True  True]
预测结果为: ['class_0' 'class_0' 'class_1' 'class_0' 'class_2' 'class_0' 'class_0'
 'class_0' 'class_2' 'class_2' 'class_0' 'class_2' 'class_0' 'class_1'
 'class_2' 'class_1' 'class_1' 'class_1' 'class_0' 'class_2' 'class_2'
 'class_1' 'class_0' 'class_1' 'class_1' 'class_1' 'class_1' 'class_2'
 'class_2' 'class_1' 'class_1' 'class_2' 'class_2' 'class_0' 'class_0'
 'class_2']
准确率: 0.9444444444444444
准确率: 0.9444444444444444

以上就是一个模型训练的基本步骤。

三、贝叶斯分类算法(Naive Bayes)

贝叶斯算法(Bayesian Algorithm)的核心是贝叶斯定理,它描述了在已知某些条件下,事件发生的概率如何更新。

1.算法原理:数学本质

1.1贝叶斯定理公式

贝叶斯定理的数学表达式为:
在这里插入图片描述

1.2全概率公式

在这里插入图片描述

1.3贝叶斯推理步骤

在这里插入图片描述

2.朴素贝叶斯:基于贝叶斯定理的特征条件独立性假设

理解了贝叶斯推断,那么让我们继续看看朴素贝叶斯。贝叶斯和朴素贝叶斯的概念是不同的,区别就在于“朴素”二字,朴素贝叶斯对条件概率分布做了条件独立性的假设。

根据贝叶斯定理,后验概率 P(a|X) 可以表示为:

P ( a ∣ X ) = P ( X ∣ a ) P ( a ) P ( X ) P(a|X) = \frac{P(X|a)P(a)}{P(X)} P(aX)=P(X)P(Xa)P(a)

其中:

  • P(X|a) 是给定类别 ( a ) 下观测到特征向量 $X=(x_1, x_2, …, x_n) $的概率;
  • P(a) 是类别 a 的先验概率;
  • P(X) 是观测到特征向量 X 的边缘概率,通常作为归一化常数处理。
    在这里插入图片描述

3.案例实战(通过朴素贝叶斯对红酒数据分类)

在这里插入图片描述
代码实现:

from sklearn.naive_bayes import MultinomialNB
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
x,y = load_wine(return_X_y=True)
data = load_wine()
print(data.feature_names)
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=42)
#创建模型对象
model = MultinomialNB()
#对模型对象进行训练(记录先验概率)
model.fit(x_train,y_train)
#获取预测结果
y_predict = model.predict(x_test)
print(y_predict==y_test)
print("预测结果为:",data.target_names[y_predict])
score = model.score(x_test,y_test)
print("准确率:",score)

注意事项:
在这里插入图片描述

四、对KNN算法进行调优(GridSearchCV)

1.分层k-折交叉验证Stratified k-fold

Stratified k-fold cross validation,

K-折交叉验证的变种, 分层的意思是说在每一折中都保持着原始数据中各个类别的比例关系,比如说:原始数据有3类,比例为1:2:1,采用3折分层交叉验证,那么划分的3折中,每一折中的数据类别保持着1:2:1的比例,这样的验证结果更加可信。
API说明

sklearn.model_selection.StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

​ n_splits划分为几个折叠
​ shuffle是否在拆分之前被打乱(随机化),False则按照顺序拆分
​ random_state随机因子

indexs=strat_k_fold.split(X,y)

​ 返回一个可迭代对象,一共有5个折叠,每个折叠对应的是训练集和测试集的下标

​ 然后可以用for循环取出每一个折叠对应的X和y下标来访问到对应的测试数据集和训练数据集 以及测试目标集和训练目标集
代码示例:
这里的模型我们直接用保存的KNN模型

from sklearn.model_selection import StratifiedKFold
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.model_selection import KFold
import joblib
model = joblib.load('../src/model/KNeighborsClassifier.pkl')
transfer = joblib.load('../src/model/transfer.pkl')
x,y = load_wine(return_X_y=True)
skf  = StratifiedKFold(n_splits=5,shuffle=True,random_state=42)
#获取5折交叉验证的索引
index = skf.split(x,y)
print(len(x),len(y))
print(next(index))#next访问迭代器数据
print(next(index))
for train_index,test_index in index:
    x_train,x_test = x[train_index],x[test_index]
    y_train,y_test = y[train_index],y[test_index]
    assert x_train.shape[1]==x_test.shape[1],'训练集和测试集的列数不一致'
    #对训练集进行标准化转换
    x_train = transfer.transform(x_train)
    # #对模型进行训练
    # model.fit(x_train,y_train)
    #对测试集进行标准化转换
    x_test = transfer.transform(x_test)
    #对测试数据进行预测
    y_predict = model.predict(x_test)
    #打印准确率
    print(model.score(x_test,y_test))

2.超参数搜索调优

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

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.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
import joblib
# model = joblib.load("../src/model/KNeighborsClassifier.pkl")
transfer = joblib.load("../src/model/transfer.pkl")
# 获取数据集
x,y = load_wine(return_X_y=True)
#数据集切分
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=42)
#对数据进行标准化
x_train = transfer.transform(x_train)
x_test = transfer.transform(x_test)
#创建模型对象
model= KNeighborsClassifier(n_neighbors=5)
#通过GridSearchCV创建新的评估器
model1 = GridSearchCV(estimator=model,param_grid={"n_neighbors":[1,2,3,4,5,6,7,8]},cv=None)
#执行模型训练
model1.fit(x_train,y_train)
#准确度最大的参数
print(model1.best_params_)
#最大准确度
print(model1.best_score_)
#最佳K参数的索引
print(model1.best_index_)
#GridSearchCV对象返回的就是一个模型对象可以对测试数据进行预测
y_predict = model1.predict(x_test)
print(y_predict==y_test)
print(model1.score(x_test,y_test))

结语

模型训练是机器学习从理论走向实践的核心步骤,而KNN和朴素贝叶斯作为经典算法,至今仍在许多场景中表现出色。本文从理论到代码,系统讲解了它们的原理、实现和优化方法,希望能帮助你建立扎实的算法基础。

🔧 动手挑战:

使用 scikit-learn 实现KNN分类,并通过交叉验证选择最优K值。

用朴素贝叶斯构建一个简单的垃圾邮件分类器,并测试不同变体的效果。

🚀 下期预告:我们将深入探讨 决策树与随机森林,解锁更强大的集成学习方法!


网站公告

今日签到

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