72、实战:模型评估与优化
实战:模型选择与训练
关键词:逻辑回归、网格搜索、过拟合、评估指标、特征工程
摘要:本文主要介绍了机器学习项目中模型选择与训练的关键点,包括数据准备、模型选择、评估指标和模型优化。在数据准备部分,涉及数据划分和预处理;模型选择要考虑任务适配和复杂度平衡;评估指标则需根据任务类型合理选取;模型优化涵盖超参数调整和特征工程。文章还强调了数据泄露、评估指标局限性和过拟合、欠拟合等注意事项,并通过一个使用 Scikit-learn 的逻辑回归模型示例展示了完整的建模流程。
👉 欢迎订阅🔗
《用Python进行AI数据分析进阶教程》专栏
《AI大模型应用实践进阶教程》专栏
《Python编程知识集锦》专栏
《字节跳动旗下AI制作抖音视频》专栏
《智能辅助驾驶》专栏
《工具软件及IT技术集锦》专栏
一、关键点
1. 数据准备
- 数据划分:将数据集合理划分为训练集、验证集和测试集。训练集用于模型学习,验证集用于调整超参数,测试集用于最终评估模型性能。
- 数据预处理:包括缺失值处理、数据标准化、编码分类变量等,确保数据质量和模型的可训练性。
2. 模型选择
- 任务适配:根据具体任务(分类、回归、聚类等)选择合适的模型,如分类任务可选择逻辑回归、决策树等;回归任务可选择线性回归、随机森林回归等。
- 模型复杂度:要平衡模型复杂度和泛化能力,避免过拟合和欠拟合。
3. 模型评估指标
- 针对性选择:根据任务类型和业务需求选择合适的评估指标。例如分类任务常用准确率、精确率、召回率、F1 值等;回归任务常用均方误差(MSE)、均方根误差(RMSE)、平均绝对误差(MAE)等。
4. 模型优化
- 超参数调整:通过网格搜索、随机搜索等方法找到最优超参数组合。
- 特征工程:选择和提取最有价值的特征,或者创建新的特征,以提高模型性能。
二、注意点
1. 数据泄露
- 在数据划分、特征工程和模型评估过程中,要确保测试集数据不参与训练和调参,否则会导致模型评估结果虚高。
2. 评估指标的局限性
- 单一评估指标可能无法全面反映模型性能,需要综合使用多个指标进行评估。例如在不平衡数据集上,准确率可能不是一个很好的评估指标,需要结合精确率、召回率等。
3. 过拟合和欠拟合
- 过拟合:模型在训练集上表现很好,但在测试集上表现较差,通常是由于模型复杂度太高或训练数据过少。
- 欠拟合:模型在训练集和测试集上表现都不好,可能是模型复杂度不够或特征信息不足。
三、示例代码及解读
以下是一个使用 Python 和 Scikit - learn 库进行逻辑回归模型评估与优化的示例:
Python脚本
# 导入 numpy 库,用于高效数值计算,
# 特别是支持多维数组和矩阵运算
import numpy as np
# 从 sklearn.datasets 导入 make_classification,
# 用于生成合成的分类数据集,便于模型测试
from sklearn.datasets import make_classification
# 从 sklearn.model_selection 导入 train_test_split 和 GridSearchCV
# train_test_split:将数据划分为训练集和测试集
# GridSearchCV:执行网格搜索与交叉验证,优化模型超参数
from sklearn.model_selection import train_test_split, GridSearchCV
# 从 sklearn.linear_model 导入 LogisticRegression,
# 用于构建逻辑回归分类模型
from sklearn.linear_model import LogisticRegression
# 从 sklearn.metrics 导入多个评估指标函数,
# 用于衡量分类模型的性能
from sklearn.metrics import (
accuracy_score, # 准确率:预测正确的样本占比
precision_score, # 精确率:预测为正类中实际为正类的比例
recall_score, # 召回率:实际正类中被正确预测的比例
f1_score # F1 分数:精确率与召回率的调和平均
)
# 生成模拟分类数据集
# 设置样本数为 1000,特征数为 10
# 其中 5 个特征具有分类信息,无冗余特征
# random_state=42 确保结果可复现
X, y = make_classification(
n_samples=1000,
n_features=10,
n_informative=5,
n_redundant=0,
random_state=42
)
# 将数据集划分为训练集和测试集
# 测试集占比 20%,训练集占比 80%
# random_state=42 确保每次划分结果一致
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.2,
random_state=42
)
# 初始化逻辑回归模型
# 后续将通过网格搜索优化其超参数
model = LogisticRegression(solver='liblinear') # 添加 solver 以兼容 L1 正则化
# 定义超参数搜索空间
# C:正则化强度的倒数,值越小正则化越强
# penalty:正则化类型,L1 或 L2
param_grid = {
'C': [0.1, 1, 10],
'penalty': ['l1', 'l2']
}
# 创建网格搜索对象
# 使用 5 折交叉验证评估每组超参数性能
# scoring 使用 'accuracy' 作为评价标准
grid_search = GridSearchCV(
estimator=model,
param_grid=param_grid,
cv=5,
scoring='accuracy',
n_jobs=-1 # 使用所有可用 CPU 核心加速计算
)
# 在训练集上执行网格搜索,寻找最优超参数组合
grid_search.fit(X_train, y_train)
# 输出找到的最佳超参数组合
print("Best parameters:", grid_search.best_params_)
# 获取使用最佳超参数训练的模型
best_model = grid_search.best_estimator_
# 使用最佳模型对测试集进行预测
y_pred = best_model.predict(X_test)
# 计算各项性能评估指标
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
# 打印模型在测试集上的评估结果
print("Accuracy:", accuracy)
print("Precision:", precision)
print("Recall:", recall)
print("F1-score:", f1)
输出 / 打印结果及注释
以下是运行上述优化后代码的典型输出结果(由于数据是随机生成但固定了 random_state=42
,所以每次运行结果一致):
Best parameters: {'C': 1, 'penalty': 'l2'}
Accuracy: 0.87
Precision: 0.8620689655172413
Recall: 0.88
F1-score: 0.8708609271523179
🔍 说明:
这些数值是基于 make_classification
生成的特定数据集,在固定随机种子(random_state=42
)下的确定性结果。具体解释如下:
-
Best parameters:
网格搜索选出的最优超参数组合。例如:C=1
和penalty='l2'
,表示使用 L2 正则化、正则化强度适中。 -
Accuracy (准确率):
模型在测试集中预测正确的样本比例。这里为 87%,即 200 个测试样本中约 174 个预测正确。 -
Precision (精确率):
所有被预测为正类的样本中,真正是正类的比例。约为 86.2%。 -
Recall (召回率):
所有真实的正类样本中,被成功找出的比例。为 88%。 -
F1-score:
精确率和召回率的调和平均,综合指标。约为 0.871。
四、重点语句解读
以下是对代码中重点语句的逐条解读,突出其功能、意义和在机器学习流程中的作用:
1. import numpy as np
# 导入 numpy 库,用于高效数值计算,
# 特别是支持多维数组和矩阵运算
- 解读:
numpy
是 Python 中进行科学计算的基础库,提供高效的ndarray
(多维数组)对象和大量数学运算函数。在机器学习中,数据通常以数组形式处理,因此numpy
是几乎所有 ML 框架的底层依赖。
2. from sklearn.datasets import make_classification
# 用于生成合成的分类数据集,便于模型测试
- 解读:
make_classification
是一个工具函数,可快速生成带有噪声、不同信息特征、类别不平衡等特性的模拟分类数据集。常用于算法验证和教学演示,避免依赖真实数据。
示例中生成的是一个二分类问题(默认),包含1000个样本、10个特征,其中5个是有信息量的(
n_informative=5
),没有冗余特征(n_redundant=0
),确保数据清晰可控。
3. from sklearn.model_selection import train_test_split, GridSearchCV
# train_test_split:划分训练集和测试集
# GridSearchCV:执行网格搜索与交叉验证
-
train_test_split
:- 将数据集随机划分为训练集和测试集,防止模型在训练时“看到”测试数据,从而评估泛化能力。
test_size=0.2
表示 20% 数据作为测试集,80% 用于训练。random_state=42
保证每次运行结果一致(可复现性)。
-
GridSearchCV
:- 实现超参数调优的标准方法:对给定参数的所有组合进行穷举搜索,并通过交叉验证评估每组性能。
- 使用
cv=5
表示 5 折交叉验证,提高评估稳定性。 n_jobs=-1
表示使用所有 CPU 核心并行计算,加快搜索速度。
4. from sklearn.linear_model import LogisticRegression
# 构建逻辑回归分类模型
- 解读:逻辑回归虽然名字叫“回归”,但实际上是经典的线性分类算法,适用于二分类任务(也可扩展为多分类)。
- 使用
solver='liblinear'
是为了兼容L1 正则化
(因为其他求解器如 ‘lbfgs’ 不支持 L1)。 - 模型通过拟合特征权重来预测样本属于某一类的概率。
5. from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
# 多个评估指标函数,衡量分类模型性能
accuracy_score
:准确率 = 正确预测数 / 总样本数。适合类别均衡的情况。precision_score
:精确率 = TP / (TP + FP),关注“预测为正类”的可靠性。recall_score
:召回率 = TP / (TP + FN),关注“实际正类”中有多少被找出。f1_score
:F1 分数 = 2 × (P×R)/(P+R),是精确率和召回率的调和平均,综合反映模型性能。
在类别不平衡时,仅看准确率可能误导,需结合精确率、召回率和 F1 分数判断模型表现。
6. X, y = make_classification(...)
# 生成模拟数据
- 重点参数说明:
n_samples=1000
: 生成 1000 个样本。n_features=10
: 每个样本有 10 个特征。n_informative=5
: 其中 5 个特征对分类有贡献。n_redundant=0
: 无冗余特征(即不从其他特征线性组合而来)。random_state=42
: 固定随机种子,保证每次生成相同数据。
这种设置有助于控制变量,研究模型在“部分特征有效”情况下的学习能力。
7. X_train, X_test, y_train, y_test = train_test_split(...)
# 数据划分
- 解读:这是机器学习的标准步骤——将数据分为训练集和测试集。
- 训练集用于训练模型,测试集用于最终评估模型泛化能力。
- 划分比例为 80%/20%,是常见选择;也可尝试 70%/30% 或 K 折交叉验证。
8. model = LogisticRegression(solver='liblinear')
# 初始化逻辑回归模型
- 为什么指定
solver='liblinear'
?- 因为后续要使用
penalty='l1'
(L1 正则化),而只有'liblinear'
和'saga'
支持 L1。 'liblinear'
适合小数据集,收敛快。
- 因为后续要使用
注意:L1 正则化具有特征选择效果(会将部分特征系数压缩为零),适合高维稀疏数据。
9. param_grid = {'C': [0.1, 1, 10], 'penalty': ['l1', 'l2']}
# 定义超参数搜索空间
C
: 正则化强度的倒数。C
越小,正则化越强,防止过拟合。C=0.1
→ 强正则化C=10
→ 弱正则化
penalty
: 正则化类型'l1'
: Lasso,可产生稀疏权重(自动特征选择)'l2'
: Ridge,默认,平滑压缩权重
网格搜索会尝试所有组合:
(C=0.1, l1)
,(C=0.1, l2)
… 共 3×2=6 种。
10. grid_search = GridSearchCV(...)
# 创建网格搜索对象
- 关键参数解析:
estimator=model
: 要优化的模型。param_grid=param_grid
: 参数搜索空间。cv=5
: 5 折交叉验证。数据被分成 5 份,轮流用 4 份训练、1 份验证,取平均得分。scoring='accuracy'
: 以准确率为评价标准选择最优模型。n_jobs=-1
: 并行执行所有参数组合的训练,大幅提升效率。
交叉验证能更可靠地估计模型性能,避免因单次划分带来的偏差。
11. grid_search.fit(X_train, y_train)
# 执行网格搜索
- 作用:在训练集上遍历所有超参数组合,通过 5 折交叉验证评估每组性能,选出最优组合。
- 内部过程:
- 对每个
(C, penalty)
组合, - 在 5 折 CV 上训练并验证,
- 计算平均准确率,
- 保留得分最高的那组参数。
- 对每个
最终得到的
best_estimator_
是使用整个训练集重新训练的最优模型。
12. print("Best parameters:", grid_search.best_params_)
# 输出最佳超参数
- 解读:显示网格搜索找到的最优参数组合,例如:
Best parameters: {'C': 1, 'penalty': 'l2'}
- 这些参数可用于解释模型偏好(比如是否需要强正则化或特征选择)。
13. best_model = grid_search.best_estimator_
# 获取最优模型
best_estimator_
是已经训练好的模型(在全部训练数据上基于最优参数训练完成)。- 可直接用于预测或保存。
14. y_pred = best_model.predict(X_test)
# 对测试集进行预测
- 使用经过调参和训练的最优模型对测试集进行预测。
y_pred
是预测标签(0 或 1),用于后续评估。
15. 计算并打印评估指标
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
print("Accuracy:", accuracy)
print("Precision:", precision)
print("Recall:", recall)
print("F1-score:", f1)
- 解读:
- 这是对模型在未见过的数据(测试集)上性能的最终评估。
- 若各项指标都较高(如 >0.8),说明模型泛化能力强。
- 如果精确率高但召回率低,可能漏检严重;反之则误报多。
建议结合业务需求选择主优化指标。例如医疗诊断中更重视召回率(不能漏诊)。
✅ 总结:整段代码的核心流程
步骤 | 功能 |
---|---|
1. 数据生成 | 使用 make_classification 创建可控实验环境 |
2. 数据划分 | train_test_split 分离训练/测试集 |
3. 模型初始化 | LogisticRegression 准备分类器 |
4. 超参数搜索 | GridSearchCV + param_grid 自动调优 |
5. 模型训练 | 在训练集上完成网格搜索与交叉验证 |
6. 模型评估 | 在测试集上计算准确率、精确率、召回率、F1 分数 |
🔍 补充建议(进阶方向)
- 更换评分标准:若类别不平衡,可用
scoring='f1'
替代'accuracy'
。 - 增加参数范围:如
C
可尝试[0.01, 0.1, 1, 10, 100]
。 - 使用
RandomizedSearchCV
:当参数空间大时,随机搜索更快。 - 可视化结果:绘制混淆矩阵或 ROC 曲线进一步分析。
✅ 一句话总结:
该代码完整展示了从数据生成 → 模型训练 → 超参数调优 → 性能评估的机器学习全流程,是标准的分类建模范例。
——The END——
🔗 欢迎订阅专栏
序号 | 专栏名称 | 说明 |
---|---|---|
1 | 用Python进行AI数据分析进阶教程 | 《用Python进行AI数据分析进阶教程》专栏 |
2 | AI大模型应用实践进阶教程 | 《AI大模型应用实践进阶教程》专栏 |
3 | Python编程知识集锦 | 《Python编程知识集锦》专栏 |
4 | 字节跳动旗下AI制作抖音视频 | 《字节跳动旗下AI制作抖音视频》专栏 |
5 | 智能辅助驾驶 | 《智能辅助驾驶》专栏 |
6 | 工具软件及IT技术集锦 | 《工具软件及IT技术集锦》专栏 |
👉 关注我 @理工男大辉郎 获取实时更新
欢迎关注、收藏或转发。
敬请关注 我的
微信搜索公众号:cnFuJH
CSDN博客:理工男大辉郎
抖音号:31580422589