机器学习模型调优实战指南

文章目录

  • 模型选择与调优:从理论到实战
    • 1. 引言
    • 2. 模型评估:为选择提供依据
      • 2.1 偏差-方差权衡
      • 2.2 数据集划分与分层抽样
      • 2.3 交叉验证(Cross-Validation)
      • 2.4 信息准则(AIC / BIC)
    • 3. 超参数调优:让模型更好
      • 3.1 网格搜索 (Grid Search)
      • 3.2 随机搜索 (Randomized Search)
      • 3.3 贝叶斯优化 (Bayesian Optimization)
    • 4. 模型选择:如何最终定夺
      • 4.1 集成学习的思路
      • 4.2 评估指标(详细公式)
        • 分类任务:
        • 回归任务:
    • 5. 实战案例:以 KNN 和随机森林为例
    • 6. 总结与建议

模型选择与调优:从理论到实战

1. 引言

在机器学习中,模型选择与调优是决定模型性能的关键步骤。一个好的算法如果参数配置不当,可能表现不如一个简单模型;而错误的评估方法也可能导致“看似很准”,实则泛化能力极差。本文将从模型评估超参数调优模型比较三个维度展开,并结合公式、代码和图示给出系统性理解。


2. 模型评估:为选择提供依据

2.1 偏差-方差权衡

模型预测误差可分解为:
E[(y−f^(x))2]=Bias2+Variance+σ2\mathbb{E}[(y-\hat{f}(x))^2] = \text{Bias}^2 + \text{Variance} + \sigma^2 E[(yf^(x))2]=Bias2+Variance+σ2

  • Bias(偏差):模型假设与真实分布的差异。
  • Variance(方差):模型对训练数据波动的敏感性。
  • σ2\sigma^2:不可约误差。

图示通常表现为:模型复杂度增加 → 偏差下降、方差上升。最佳点是两者平衡的位置。

bc1ba08ac606fbc862436f903688e246_720

什么是偏差(Bias)? 什么是方差(Variance)?
其实可以套到生活中"准" 跟"确" 这两个概念,如果用高中军训课打靶的经验来说,那就是:
如果说你打靶打得很精"准",意味你子弹射中的地方离靶心很近,即Low Bias;
如果说你打靶打得很精"确",意味你在发射数枪之后这几枪彼此之间在靶上的距离很近,即Low Variance。
接着下面用一张图来说明,应该就一目了然了!

b28b8719957f468d32ef8eda579ec006


2.2 数据集划分与分层抽样

保留交叉验证Hold-Out(留出法)是最简单的评估方式:将数据分为训练集和测试集。但对于类别不平衡问题,普通划分可能导致训练或测试集中类别分布偏移。此时应使用 train_test_split 的分层参数:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42
)
  • stratify=y:确保分割后各数据集的类别比例与原始数据一致,减少评估偏差。

2.3 交叉验证(Cross-Validation)

不同交叉验证方法的对比:

  1. K-Fold

    • K 折交叉验证将数据集分割为 K 个互斥的子集(折叠,fold),每次用 K-1 个子集作为训练集,剩下的 1 个子集作为验证集,重复 K 次,最终得到 K 个模型的评估结果(如准确率、MSE 等),取平均值作为模型的最终性能指标。

    • 实现:

      from sklearn.model_selection import KFold
      
    • 公式:
      CV Error=1K∑i=1KEi\text{CV Error} = \frac{1}{K} \sum_{i=1}^K E_i CV Error=K1i=1KEi

    • 适用于数据量较大、类别分布均衡的情况。

  2. Stratified K-Fold

    • Stratified K-Fold(分层 K 折交叉验证) 是 K 折交叉验证的一种改进版本,专门用于分类问题,其核心特点是在划分数据集时保持每个折中类别比例与原始数据集一致,避免因随机划分导致的类别分布失衡,从而更稳健地评估模型性能。

    • 实现:

      from sklearn.model_selection import StratifiedKFold
      
  3. Leave-One-Out (LOO)

    • 每次只留一个样本作为验证,其余样本作为训练。
    • 优点:几乎无偏估计。
    • 缺点:计算量大、方差高。
  4. Hold-Out

    • 单次划分,计算效率高,但结果波动较大。

K 折交叉验证的作用不是“提高泛化性”,而是更稳定、无偏地估计泛化误差。调参过程中,它帮助选择在新数据上表现最好的模型。

代码示例:

from sklearn.datasets import load_wine
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score
import numpy as np# 1. 加载数据
X, y = load_wine(return_X_y=True)# 2. 标准化数据
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)# 3. 创建KFold对象
kfold = KFold(n_splits=5, shuffle=True, random_state=42)# 4. 进行交叉验证
scores = []
for train_idx, test_idx in kfold.split(X_scaled):X_train, X_test = X_scaled[train_idx], X_scaled[test_idx]y_train, y_test = y[train_idx], y[test_idx]# 训练模型knn = KNeighborsClassifier(n_neighbors=5)knn.fit(X_train, y_train)# 预测并计算准确率y_pred = knn.predict(X_test)score = accuracy_score(y_test, y_pred)scores.append(score)# 5. 输出结果
print("每折的准确率:", scores)
print("平均准确率:", np.mean(scores))
print("标准差:", np.std(scores))

输出结果如下:

每折的准确率: [0.9444444444444444, 0.9444444444444444, 0.9722222222222222, 0.9142857142857143, 0.9714285714285714]
平均准确率: 0.9493650793650794
标准差: 0.02139268011280184

2.4 信息准则(AIC / BIC)

对于概率模型,可使用信息准则进行模型选择:

  • AIC(Akaike Information Criterion)
    AIC=2k−2ln⁡(L)\text{AIC} = 2k - 2\ln(L) AIC=2k2ln(L)

    • kkk:模型参数数量
    • LLL:似然函数最大值
    • 目标:惩罚参数数量,鼓励较好拟合。
  • BIC(Bayesian Information Criterion)
    BIC=kln⁡(n)−2ln⁡(L)\text{BIC} = k\ln(n) - 2\ln(L) BIC=kln(n)2ln(L)

    • nnn:样本数量
    • 与 AIC 区别:BIC 对模型复杂度惩罚更强,更倾向选择简单模型。

功能总结

  • AIC 偏好泛化能力强的模型。
  • BIC 偏好更简单、更保守的模型。
  • 二者都基于最大似然估计,适用于概率模型(如回归、时间序列)。

3. 超参数调优:让模型更好

3.1 网格搜索 (Grid Search)

穷举所有组合,计算成本高但适合小搜索空间:

from sklearn.model_selection import GridSearchCV
param_grid = {'n_neighbors': [3,5,7], 'weights': ['uniform','distance']}
grid = GridSearchCV(KNeighborsClassifier(), param_grid, cv=5)
grid.fit(X_train, y_train)
print(grid.best_params_, grid.best_score_)

weights='uniform'(默认值):等权重

  • 含义:所有 K 个邻居的投票权重相同,预测结果由 “多数邻居的类别” 决定(简单多数投票)。

weights='distance':距离加权

  • 含义:邻居的权重与其到待预测样本的距离成反比 ——距离越近的邻居,权重越大,对预测结果的影响越强。

3.2 随机搜索 (Randomized Search)

随机采样部分参数组合:
P(找到最优解)=1−(1−p)nP(\text{找到最优解}) = 1 - (1-p)^n P(找到最优解)=1(1p)n
(其中ppp 为采样一次命中最优区域的概率,nnn 为采样次数。)

3.3 贝叶斯优化 (Bayesian Optimization)

利用高斯过程或树模型拟合“超参数 → 评分”的函数,通过采集函数(如期望改进 EI)智能选择下一步采样位置。


4. 模型选择:如何最终定夺

4.1 集成学习的思路

  • Bagging:降低方差(随机森林)。
  • Boosting:降低偏差(XGBoost)。
  • Stacking:综合多模型优势。

4.2 评估指标(详细公式)

分类任务:
  • 准确率
    Accuracy=TP+TNTP+FP+TN+FN\text{Accuracy} = \frac{TP+TN}{TP+FP+TN+FN} Accuracy=TP+FP+TN+FNTP+TN

  • 精确率(Precision)
    Precision=TPTP+FP\text{Precision} = \frac{TP}{TP+FP} Precision=TP+FPTP

  • 召回率(Recall)
    Recall=TPTP+FN\text{Recall} = \frac{TP}{TP+FN} Recall=TP+FNTP

  • F1 分数
    F1=2⋅Precision⋅RecallPrecision+RecallF1 = 2 \cdot \frac{\text{Precision} \cdot \text{Recall}}{\text{Precision} + \text{Recall}} F1=2Precision+RecallPrecisionRecall

  • AUC(ROC 曲线下面积):衡量分类器对正负样本排序能力。

    这个链接有个在线实验可以帮助理解:
    Google实验案例
    image-20250806191204763

回归任务:
  • 均方误差 (MSE)
    MSE=1n∑i=1n(yi−y^i)2\text{MSE} = \frac{1}{n}\sum_{i=1}^n (y_i-\hat{y}_i)^2 MSE=n1i=1n(yiy^i)2

  • 平均绝对误差 (MAE)
    MAE=1n∑i=1n∣yi−y^i∣\text{MAE} = \frac{1}{n}\sum_{i=1}^n |y_i-\hat{y}_i| MAE=n1i=1nyiy^i

  • 决定系数 (R²)
    R2=1−∑(yi−y^i)2∑(yi−yˉ)2R^2 = 1 - \frac{\sum (y_i-\hat{y}_i)^2}{\sum (y_i-\bar{y})^2} R2=1(yiyˉ)2(yiy^i)2


5. 实战案例:以 KNN 和随机森林为例

  1. 划分数据集并进行标准化

  2. 使用 Stratified K-Fold 进行评估

  3. 分别通过 Grid Search 和 Random Search 调参

  4. 对比最佳模型性能(表格+曲线)

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    from sklearn.datasets import make_classification
    from sklearn.model_selection import train_test_split, StratifiedKFold, GridSearchCV, RandomizedSearchCV
    from sklearn.preprocessing import StandardScaler
    from sklearn.neighbors import KNeighborsClassifier
    from sklearn.ensemble import RandomForestClassifier
    from sklearn.pipeline import Pipeline
    from scipy.stats import randint# 1. 加载数据
    data = make_classification(n_samples=1000, n_features=20, n_informative=10, n_redundant=5,n_classes=3, n_clusters_per_class=1, random_state=42
    )
    X, y = data
    print(f"数据集特征数: {X.shape[1]}, 样本数: {X.shape[0]}, 类别数: {len(np.unique(y))}")# 2. 分层划分训练集和测试集(保持类别比例)
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42
    )# 3. 定义分层K折交叉验证(适合分类问题)
    cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)# 4. KNN - 网格搜索(KNN需要标准化)
    knn_pipe = Pipeline([('scaler', StandardScaler()),  # KNN对特征尺度敏感,必须标准化('knn', KNeighborsClassifier())
    ])
    param_knn = {'knn__n_neighbors': [3, 5, 7, 9],  # 增加参数范围'knn__weights': ['uniform', 'distance']
    }
    grid_knn = GridSearchCV(estimator=knn_pipe,param_grid=param_knn,cv=cv,scoring='accuracy',n_jobs=-1,  # 使用所有可用CPUverbose=1  # 显示调参过程
    )
    grid_knn.fit(X_train, y_train)# 5. 随机森林 - 随机搜索(随机森林不需要标准化)
    rf_pipe = Pipeline([# 移除StandardScaler,随机森林对特征尺度不敏感('rf', RandomForestClassifier(random_state=42))
    ])
    param_rf = {'rf__n_estimators': randint(50, 200),  # 增加参数范围'rf__max_depth': randint(3, 15),'rf__min_samples_split': randint(2, 10),'rf__min_samples_leaf': randint(1, 5)  # 增加叶子节点参数
    }
    random_rf = RandomizedSearchCV(estimator=rf_pipe,param_distributions=param_rf,n_iter=20,  # 增加搜索迭代次数cv=cv,scoring='accuracy',n_jobs=-1,random_state=42,verbose=1
    )
    random_rf.fit(X_train, y_train)# 6. 性能对比表格
    results = pd.DataFrame({'模型': ['KNN(网格搜索)', '随机森林(随机搜索)'],'最佳参数': [grid_knn.best_params_, random_rf.best_params_],'交叉验证准确率': [f"{grid_knn.best_score_:.4f}", f"{random_rf.best_score_:.4f}"],'测试集准确率': [f"{grid_knn.score(X_test, y_test):.4f}", f"{random_rf.score(X_test, y_test):.4f}"]
    })
    print("\n模型性能对比:")
    print(results)# 7. 可视化 - KNN超参数(n_neighbors)与准确率关系
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文
    plt.rcParams['axes.unicode_minus'] = False    # 显示负号
    plt.figure(figsize=(10, 6))# 提取网格搜索结果
    mean_scores = grid_knn.cv_results_['mean_test_score']
    params = grid_knn.cv_results_['params']# 按权重分组绘制
    for weight in ['uniform', 'distance']:# 筛选当前权重的结果scores = [mean_scores[i] for i, p in enumerate(params) if p['knn__weights'] == weight]n_neighbors = [p['knn__n_neighbors'] for i, p in enumerate(params) if p['knn__weights'] == weight]plt.plot(n_neighbors, scores, marker='o', label=f'权重={weight}')plt.xlabel('近邻数量(n_neighbors)')
    plt.ylabel('交叉验证准确率')
    plt.title('KNN不同近邻数量与权重的性能对比')
    plt.legend()
    plt.grid(alpha=0.3)
    plt.tight_layout()
    plt.show()# 8. 输出最佳模型在测试集上的表现
    print("\nKNN最佳模型测试集准确率:", grid_knn.score(X_test, y_test))
    print("随机森林最佳模型测试集准确率:", random_rf.score(X_test, y_test))
    数据集特征数: 20, 样本数: 1000, 类别数: 3
    Fitting 5 folds for each of 8 candidates, totalling 40 fits
    Fitting 5 folds for each of 20 candidates, totalling 100 fits模型性能对比:模型                                               最佳参数 交叉验证准确率  \
    0   KNN(网格搜索)  {'knn__n_neighbors': 7, 'knn__weights': 'dista...  0.9262   
    1  随机森林(随机搜索)  {'rf__max_depth': 9, 'rf__min_samples_leaf': 1...  0.9287   测试集准确率  
    0  0.9450  
    1  0.9200
    

    image-20250806192309446


6. 总结与建议

  • 分层抽样在类别不平衡下必不可少。
  • K 折交叉验证是为了更稳定地估计泛化误差,而非直接“提高泛化性”。
  • AIC/BIC更适用于概率模型;交叉验证适合通用机器学习场景。
  • 实战中可结合随机搜索 + 贝叶斯优化以降低计算成本。
  • 评估指标需根据业务目标选取,而非盲目追求单一指标。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/94503.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/94503.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【教程】Unity CI/CD流程

测试机:红帽 Linux8 源码仓库:Gitee - MrRiver/Unity Example   系统环境准备 1)yum 源 sudo curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo sudo sed -i s/\$releasever/8/g /etc/yum.repos…

文献阅读 | Briefings in Bioinformatics | Hiplot:全面且易于使用的生物医学可视化分析平台

文献介绍文献题目: Hiplot:一个综合且易于使用的 Web 服务,用于增强出版物准备的生物医学数据可视化 研究团队: Openbiox/Hiplot 社区 发表时间: 2022-07-05 发表期刊: Briefings in Bioinformatics 影响因…

【数字图像处理系列笔记】Ch04:灰度变换与空间域图像增强(2)

目录 一、空域滤波基础 一、空域滤波的基本概念 二、空域滤波的数学原理 三、空域滤波器的分类与典型示例 (一)线性滤波器(Linear Filter) (二)非线性滤波器(Non-linear Filter&#xff0…

AI浪潮下,FPGA如何实现自我重塑与行业变革

引言:AI 与 FPGA,新时代的碰撞 2025 年,人工智能技术迎来爆发式增长,大模型、生成式 AI 和多模态技术持续突破,人形机器人量产元年正式开启,自动驾驶商业化进程加速,工业数字化转型全面铺开(1)…

系统集成项目管理工程师【第十一章 规划过程组】定义范围、创建WBS、规划进度管理和定义活动篇

系统集成项目管理工程师【第十一章 规划过程组】定义范围、创建WBS、规划进度管理和定义活动篇 一、定义范围:给项目画好"边界线" 定义范围是明确项目和产品"做什么、不做什么"的过程,直接影响后续所有工作的方向。 1. 核心概念与作…

Spring Boot 参数校验全指南

Spring Boot 参数校验全指南 在 Web 开发中,参数校验是保障接口安全性和数据合法性的关键环节。手动编写校验逻辑不仅繁琐,还容易遗漏边界情况。Spring Boot 整合了 validation 工具,提供了一套简洁高效的参数校验方案,可快速实现…

常用技术资料链接

1.team技术 https://zhuanlan.zhihu.com/p/11389323664 https://blog.csdn.net/Lucky_Lu0/article/details/121697151 2.bond切换主备 https://www.xgss.net/3306.html 3.ssh详解: https://cloud.tencent.com/developer/news/105165 https://blog.huochengrm.c…

【Spring Cloud】-- 注册中心

文章目录1. 什么是注册中心2. CPA理论1. 什么是注册中心 注册中心有三种角色: 服务提供者(Server) :提供接口给其他微服务的程序。服务消费者(Client):调用其他微服务提供的接口。**服务注册中…

go-zero 详解

go-zero 详解 go-zero 是一个基于 Go 语言的微服务框架,由字节跳动团队开发并开源,旨在帮助开发者快速构建高可用、高性能的微服务架构。它集成了丰富的组件,简化了微服务开发中的常见问题(如服务注册发现、配置管理、限流熔断等&…

接口自动化框架封装之统一请求封装及通过文件实现接口关联

接口自动化测试框架封装目的:简化自动化框架的落地,提高投入和产出比,只要一个人封装好框架,另外的测试通过写yaml测试用例即可实现接口自动化1.统一请求的封装去除多余重复的代码可跨py文件实现通过一个session来自动关联有cookie的接口设置统一公共参数,统一文件处理,统一异常…

Vue 最佳实践:如何利用唯一 key 值保证 el-table 动态渲染的稳定性

📋 问题描述 在Vue 2.0 ElementUI项目的偏置条件管理页面中,每次切换到"内规拉偏"菜单时,表格样式会发生崩溃,导致表格布局异常、列宽错乱、固定列显示不正确等问题。 🔍 问题分析 通过深入分析代码&#x…

popen开启进程,写入数据

通过管道&#xff08;popen&#xff09;启动 SDIWAN_WEB 进程并写入 JSON 数据的过程可以分为以下步骤&#xff0c;结合代码示例和关键注意事项进行说明&#xff1a;1. 核心代码示例 #include <stdio.h> #include <json-c/json.h>int main() {// 1. 创建 JSON 对象…

计算机视觉的四项基本任务辨析

计算机视觉是使计算机能理解采集设备采集的图像视频的一门学科&#xff0c;目的是让计算机实现人的视觉功能——对客观世界的三维场景的感知、识别和理解。换句话说&#xff0c;要让计算机具备通过二维图像认识三维环境的能力。 目录 三个阶段 视觉层级 基本任务 技术难点…

iostat 系统IO监控命令学习

一、iostat 命令描述 “iostat”命令用于监测系统输入/输出设备的负载情况&#xff0c;其通过观察设备处于活跃状态的时间与平均传输速率之间的关系来实现这一目的。该命令会生成报告&#xff0c;这些报告可用于调整系统配置&#xff0c;以更好地平衡物理磁盘之间的输入/输出负…

jenkins使用ssh方式连接gitee 公钥、私钥配置、指纹

前言 Gitee 提供了基于 SSH 协议的 Git 服务&#xff0c;jenkins可使用ssh方式连接gitee&#xff0c;拉取代码、提交tag等&#xff1b;使用ssh 连接&#xff0c;相比用户名密码方式&#xff0c;可省去因密码变更而引起的jenkins关联修改。 gitee生成、添加 SSH 公钥 生成SSH…

如何在Android设备上删除多个联系人(3种方法)

如果您想清理安卓手机&#xff0c;或者只是想删除旧的、不需要的联系人&#xff0c;或者删除多个联系人&#xff0c;有三种有效的方法可供选择。无论您是想手动删除安卓手机上的联系人&#xff0c;还是使用专用工具&#xff0c;都可以按照以下步骤操作。方法1&#xff1a;如何通…

Angular进阶之十三:Angular全新控制流:革命性的模板语法升级

随着Angular v17的发布&#xff0c;框架带来了革命性的控制流语法&#xff0c;彻底改变了我们编写模板的方式。这些改进不仅仅是语法糖——它们提升了性能、开发体验和代码可维护性。 为什么我们需要新的控制流&#xff1f; 在之前的Angular版本中&#xff0c;我们使用结构指令…

【Redis】string字符串

目录 一.常见命令 1.1.SET 1.2.GET 1.3.MGET 1.4.MSET 1.5.SETNX 二.计数命令 2.1.INCR 2.2.INCRBY 2.3.DECR 2.4.DECYBY 2.5.INCRBYFLOAT 三 . 其他命令 3.1.APPEND 3.2.GETRANGE 3.3.SETRANGE 3.4.STRLEN 四. 字符串类型内部编码 五. 典型使用场…

Nginx 学习

通过网盘分享的文件&#xff1a;Nginx 链接: https://pan.baidu.com/s/1dCc7FoND90H_x7rvRUXJqg 提取码: yyds 通过网盘分享的文件&#xff1a;Tomcat 链接: https://pan.baidu.com/s/1nj_5j_66gS_YHUAX1C25jg 提取码: yyds Nginx安装、启动 安装依赖库 #安装C编译器 yum insta…

Java、Android及计算机基础面试题总结

1. String、StringBuffer、StringBuilder区别特性StringStringBufferStringBuilder可变性不可变可变可变线程安全是是(synchronized)否性能低(频繁操作时)中等高场景字符串常量多线程字符串操作单线程字符串操作2. 接口和抽象类的区别特性接口(Interface)抽象类(Abstract Class…