机器学习5
十、模型选择与调优
模型性能的验证:使用交叉验证实现
10.1、保留交叉验证
保留交叉验证:把数据集按照一定的比例进行划分,比如8:2、7:3,然后大量的数据集用来做训练,少部分数据集做模型性能测试,这样的验证方法存在一定的问题:假设二分类问题,其中一个类别占总数据集的80%,那么在数据集划分的时候,有可能把80%占比的类别全部会分到训练集,导致训练过程中没有第二个类别,但是测试中只有第二个类别
10.2、k-折交叉验证
k-折交叉验证:就是把数据集换分为k-flod(k个折子),比如我们把数据集划分为10flod,第一训练就把第一个flod作为验证集,剩余的2-10作为训练集,第二次训练把第2个flod作为验证集,剩余的1,3-10作为训练集,以此类推,直到每一个flod都用于训练和验证。最终就是把10次验证结果的平均值作为模型性能输出指标。存在问题:如果数据集存在极端的情况下,比如某一个类别数据比较少,那么可能会导致某一个flod里面只有这个类别的全部信息,而没有其他类别信息,也会导致模型验证不准确
cross_val_score
是 scikit-learn 中的一个函数,用于执行交叉验证并返回模型在不同折叠上的得分,cross_val_score
函数的主要参数如下:
参数名 | 类型/说明 |
---|---|
estimator | 模型对象,必须实现了 fit 方法的估计器(如 LogisticRegression , RandomForestClassifier 等) |
X | 特征数据,形状为 (n_samples, n_features) |
y | 目标变量(标签),形状为 (n_samples,) ,可选(对于无监督模型可以不传) |
scoring | 评分方式,字符串或可调用对象,如 'accuracy' , 'f1' , 'roc_auc' 等;默认使用 estimator 的 score() 方法 |
cv | 交叉验证的折数,默认是 5 ,也可以传入一个 CV 对象(如 KFold , StratifiedKFold ) |
n_jobs | 并行执行的作业数,-1 表示使用所有 CPU 核心 |
verbose | 输出详细信息的程度,整数,值越大输出越多 |
fit_params | 传递给 fit 方法的参数(可选) |
pre_dispatch | 控制并行任务的调度数量,默认 '2*n_jobs' |
返回值 | scores : 一个 NumPy 数组,包含每一折的评分结果 |
"""api:from sklearn.model_selection import cross_val_score交叉验证不需要你去fit操作,他会自己做这个事情参数:estimator:估计器对象X:数据集信息y=None:标签信息cv=None:分成多少个flod,默认5
"""
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
iris = load_iris()
data, target = iris.data, iris.target
# knn --- n_neighbors 就是 k 值,属于超参数,默认是5,手动直接设置可能不准确
knn = KNeighborsClassifier(n_neighbors=5)
# 使用 k-flod 交叉验证
result = cross_val_score(knn, data, target, cv=5)
print("每一次的交叉验证结果:", result)
print("平均交叉验证的结果:", result.mean())
10.3、分层K-折交叉验证
分层k-折交叉验证:就是k-折交叉验证加了一个方案,就是保证原始数据集中如果A:B:C=1:2:1,那么在划分为k-flod之后,每个flod中也保证数据集的比例是A:B:C=1:2:1
StratifiedKFold
是scikit-learn
库中的一个类,用于实现分层 K 折交叉验证(Stratified K-Fold Cross Validation),构造函数StratifiedKFold
的参数如下:
类别 | 说明 |
---|---|
类名 | StratifiedKFold (分层K折交叉验证) |
构造函数参数 | |
n_splits (int, default=5) | 定义折叠数量(默认为5折) |
shuffle (bool, default=False) | 是否在划分前打乱数据(提高随机性) |
random_state (int/RandomState/None, default=None) | 随机种子(确保可复现性,仅在shuffle=True 时生效) |
核心方法 | skf.split(X, y) 方法是 StratifiedKFold 类的一个重要方法,用于生成训练集和测试集的索引 |
方法参数 | |
X | 特征数据(NumPy数组/列表/DataFrame等) |
y | 标签数据(一维数组,表示类别) |
返回值 | 迭代器(每次迭代生成一个元组) |
元组内容 | (train_index, test_index) |
train_index | NumPy数组(训练集样本索引) |
test_index | NumPy数组(测试集样本索引) |
"""api:from sklearn.model_selection import StratifiedKFold参数:n_splits:默认值5,fold数量,至少为2shuffle:默认值False,是否在分批之前对每个类的样本进行打乱数据random_state:随机数种子重要方法:split 方法:参数:数据集X,和标签 y返回值:训练数据集的索引值、测试数据集的索引值
"""
from sklearn.model_selection import StratifiedKFold
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
iris = load_iris()
X, y = iris.data, iris.target
# knn
knn = KNeighborsClassifier(n_neighbors=3)
# 创建分层k折交叉验证对象
skf = StratifiedKFold(n_splits=5, shuffle=False, random_state=None)
total = 0
# 调用 split 方法,得到每一批次的训练数据集和验证数据集的索引值 --- 批次的思想,把数据换分成多少分,分成几次完成
for i, (train_index, test_index) in enumerate(skf.split(X, y)):# 得到每一批次中的训练集数据和验证集数据内容x_train, x_test, y_train, y_test = X[train_index], X[test_index], y[train_index], y[test_index]print(y_train)print(y_test)
# # 获取每一次验证的得分
# knn.fit(x_train, y_train)
# # 模型得分 ---- 每一个小批次的得分,并不可以使用一个小批次的结果来代表最终的结果
# score = knn.score(x_test, y_test)
# print(f"第{i+1}次准确率:", score)
# total += score
# print("平均每一次的准确率:", total/skf.get_n_splits(X, y))
10.4、模型超参数的选择和设置
比如我们的knn模型,需要设置一个参数,k 值,如果我们没有经验,啥也不知道,数据集的情况也不了解,那么我们就好像碰运气一样,需要不断的去测试 k 值,找到最合适的 k 值。问题:每一次设置 k 值,我们是不是都需要运行一次代码。那么有没有一种办法,我们只要设置 k 值的范围区间,运行一次代码,让他自己去找到设置 k 值范围区间模型效果最好的 k 值。
提供的方案叫做网格搜索,就是把需要设置的超参数的数据内容,提供给网格搜索对象,它会自动的去帮我们找到最佳的
GridSearchCV
是scikit-learn
库提供的一个用于执行网格搜索的类,它可以在给定的超参数网格中自动寻找最佳的超参数组合。GridSearchCV
通过交叉验证来评估每种超参数组合的效果,并最终返回性能最好的模型GridSearchCV
的构造函数的参数如下:
参数名 | 类型与说明 |
---|---|
estimator | scikit-learn 的估计器实例(如 KNeighborsClassifier() 、SVC() 等) |
param_grid | 字典类型,键为参数名称(字符串),值为该参数尝试的取值列表。例如:{'n_neighbors': [3, 5, 7]} |
cv | 整数或交叉验证生成器,默认为 None (即默认使用 5 折交叉验证)。也可以传入如 KFold , StratifiedKFold |
scoring | 指定评分方式,字符串(如 'accuracy' , 'f1' , 'roc_auc' )或可调用对象 |
n_jobs | 并行执行的作业数,-1 表示使用所有 CPU 核心 |
verbose | 控制输出信息详细程度的整数,值越大输出越多 |
GridSearchCV
的对象中,有如下几个重要的属性:
属性名 | 类型与说明 |
---|---|
best_params_ | 字典类型,表示在网格搜索中找到的最佳超参数组合 |
best_score_ | 浮点数类型,最佳模型在交叉验证中的平均得分(注意:这是在训练集上的交叉验证结果) |
best_estimator_ | 最佳超参数对应的完整训练好的模型(可以直接用于预测) |
cv_results_ | 字典类型,包含所有参数组合的交叉验证结果,可用于分析不同参数对性能的影响 |
refit_time_ | 在整个数据集上重新拟合最佳模型所花费的时间 |
n_splits_ | 实际使用的交叉验证折数 |
"""我们可以通过网格搜索来实现,选择估计器中最适配【你自己的设置的值中】的超参数api:from sklearn.model_selection import GridSearchCV参数:estimator:估计器param_grid:字典类型字典的key就是估计器中超参数的名字字典的key对应的value就是超参数可选择的值(一般是多个值)
"""
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
iris = load_iris()
data, target = iris.data, iris.target
# 做鸢尾花的分类 --- knn 模型 --- 不设置超参数k值,让网格搜索帮我们设置
knn = KNeighborsClassifier()
# 超参数可选择的情况设置
param_grid = {"n_neighbors": [1, 3, 5, 7, 9]
}
# 网格搜索对象
gsc = GridSearchCV(estimator=knn, param_grid=param_grid, cv=5)
# fit --- 投喂、训练、拟合数据
gsc.fit(data, target)
print(gsc.cv_results_)
# 获取最佳的参数设置情况
print(gsc.best_params_)
# 最佳估计器
print(gsc.best_estimator_)
# 获取最佳的得分情况
print(gsc.best_score_)
10.5、模型保存与加载
joblib
是一个 Python 库,主要用于并行计算和持久化存储(即保存和加载)大型 NumPy 数组和模型。joblib
提供了dump
和load
两个函数,用于保存和恢复 Python 对象,特别是机器学习模型
函数名 | 参数 | 说明 |
---|---|---|
joblib.dump() | obj:要保存的对象 filename:保存文件的路径 | 将 Python 对象保存到磁盘文件中。它可以有效地压缩数据,并且支持并行写入,适合用于保存大型数据集或模型 |
joblib.load() | filename:保存对象的文件路径 | 从磁盘文件中恢复之前保存的对象 |
十一、阶段复习
这个阶段不需要你去写一个自己的算法,然后去拟合数据,得到模型,我们主要就是使用别人写好了的算法,这个算法就在 sklearn 库里面
调用别人的 API 之前,需要知道这个 API 的作用,是如何计算的【原理】
数据集划分:train_test_split
训练:
测试(验证):
预测(推理)
数据集分割
如果有的数据不是数值类型,我们需要使用特征提取把非数值的数据集转为数值类型
对于数据集而言,有的数据集内容存在较大的差异,比如单位问题、有的特征信息没有用的问题:我们就可以采取特征工程里面的方法,对数据集进行处理
加载数据集
数据集是否需要数值转换
是否需要降维处理
划分数据集
是否需要归一化、标准化。。。。
加载估计器
估计器调用 fit 方法拟合训练数据集数据---训练模型---得到的就是模型
模型性能指标检测---score、混淆矩阵。。。。【提供给开发者查看模型好坏的】
模型ok的情况下,保存起来
------------------------------------------------
模型的应用 --- 比如推理一个未知的数据是属于哪一个类别
交叉验证:就是如何划分数据集,进行模型的训练和性能测试
网格搜索:类似于一个循环操作,筛选设置的值中最佳的超参数