基于Optuna的机器学习超参数调优与自定义可视化分析

机器学习关系型数据库云安全

picture.image

背景

在机器学习调参过程中,Optuna是一个强大的自动化超参数优化工具,它通过智能搜索算法在定义的参数空间中寻找最佳参数组合,从而提升模型性能。Optuna-dashboard虽然提供了一定的可视化功能,让用户能够观察到调参过程的变化,但其局限性也较为明显:

  • 数据无法导出:Optuna-dashboard上的数据仅供简单查看,无法直接导出进行进一步的分析和记录
  • 图表展示单一:默认的展示效果和配色较为有限,难以满足个性化展示的需求,尤其在需要深度分析超参数与目标值(object value)或超参数与试验次数关系时显得不够灵活

因此,为了更好地分析调参过程,本文选择使用自定义的可视化方式,通过清晰、灵活的图表呈现调参效果。通过自定义绘制,可以深入探索不同超参数组合对模型表现的影响,从而更有效地优化和展示模型调参结果,这种自定义可视化不仅能够在调参过程中更好地理解模型,还能生成直观、美观的图表,适用于展示和分析,当然还不了解Optuna的读者建议先阅读文章——可视化自动调参工具Optuna在机器学习中的应用:以 XGBoost 回归模型为例

代码实现

基于Optuna的自动化XGBoost超参数优化


          
import pandas as pd
          
import numpy as np
          
import matplotlib.pyplot as plt 
          
import warnings
          
warnings.filterwarnings("ignore")
          

          
plt.rcParams['font.family'] = 'Times New Roman'
          
plt.rcParams['axes.unicode_minus'] = False
          
df = pd.read_excel('2024-11-10-公众号Python机器学习AI.xlsx')
          
from sklearn.model_selection import train_test_split
          

          
X = df.drop(['待预测变量Y'],axis=1)
          
y = df['待预测变量Y']
          

          
# 划分训练集和测试集
          
X_temp, X_test, y_temp, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
          
# 然后将训练集进一步划分为训练集和验证集
          
X_train, X_val, y_train, y_val = train_test_split(X_temp, y_temp, test_size=0.125, random_state=42)  # 0.125 x 0.8 = 0.1
          

          
import optuna  # 导入Optuna库,用于超参数优化
          
from xgboost import XGBRegressor  
          
from sklearn.metrics import mean_squared_error
          
from optuna.visualization import plot_optimization_history, plot_contour, plot_param_importances, plot_parallel_coordinate, plot_edf  # 导入Optuna的可视化工具,用于绘制优化历史、参数重要性等
          

          
# 定义目标函数,用于Optuna的优化
          
def objective(trial):
          
    # 定义模型的超参数搜索空间,Optuna会在此范围内进行参数采样
          
    params = {
          
        # 'n_estimators':模型中要构建的决策树的数量
          
        # 值越高,模型拟合越充分,但计算开销也更大。一般较低的值适合快速迭代和避免过拟合
          
        'n_estimators': trial.suggest_categorical('n_estimators', [50, 100, 200, 300]), #离散的类别选择范围
          

          
        # 'max_depth':控制每棵树的深度,以防止过拟合。较高的深度会增加模型复杂性
          
        'max_depth': trial.suggest_int('max_depth', 3, 15, step=1), #整数范围
          

          
        # 'learning_rate':学习率决定每棵树对最终预测的贡献。较小的学习率通常需要更大的'n_estimators'来充分学习
          
        'learning_rate': trial.suggest_loguniform('learning_rate', 0.01, 0.3), # 对数均匀分布的连续浮点数范围
          

          
        # 'subsample':表示每棵树随机选择的样本比例,通常用于减少过拟合
          
        'subsample': trial.suggest_uniform('subsample', 0.5, 1.0), # 线性均匀分布的连续浮点数范围
          

          
        # 'colsample_bytree':控制每棵树使用的特征比例,以增强模型的鲁棒性
          
        'colsample_bytree': trial.suggest_uniform('colsample_bytree', 0.5, 1.0),
          

          
        # 'gamma':控制是否允许分裂,越高的值会使算法更保守,帮助避免过拟合
          
        'gamma': trial.suggest_uniform('gamma', 0, 5)
          
    }
          

          
    # 使用采样的参数创建XGBRegressor模型
          
    model = XGBRegressor(**params, random_state=42)
          

          
    # 使用训练数据拟合模型
          
    model.fit(X_train, y_train)
          
    # 使用验证集进行预测
          
    y_pred = model.predict(X_val)
          
    # 计算并返回均方误差(MSE),作为优化的目标
          
    return mean_squared_error(y_val, y_pred)
          

          
# 创建Optuna的Study对象,并设置优化方向为“minimize”表示最小化均方误差
          
# 默认情况下,Optuna使用的优化算法是 TPE (Tree-structured Parzen Estimator),
          
# 这是一种贝叶斯优化方法,适合高效地探索超参数空间
          
study = optuna.create_study(direction="minimize")
          
# 运行优化,进行100次试验
          
study.optimize(objective, n_trials=100)
          
print("Best parameters:", study.best_params)
          
# 使用最佳参数重新训练模型
          
best_model = XGBRegressor(**study.best_params, random_state=42)
          
best_model.fit(X_train, y_train)
      

picture.image

使用Optuna库对XGBoost回归模型进行自动化超参数优化。首先,代码将数据集划分为训练集、验证集和测试集,然后定义目标函数(objective)来指定要优化的超参数范围,包括n_estimators、max_depth、learning_rate、subsample、colsample_bytree和gamma。Optuna在此范围内自动采样超参数组合,通过最小化均方误差(MSE)来找到最优参数,运行100次试验后,代码输出最优参数并用其重新训练XGBoost模型,从而提高模型性能

记录与可视化调参优化历史


          
# 获取优化历史中的数据,每列的含义如下:
          
# 'trial_number': 每次试验的编号,用于区分不同的试验
          
# 'value': 每次试验的目标值(优化过程中的结果),通常是需要最小化或最大化的目标值
          
# 'datetime_start': 每次试验的开始时间,用于记录试验的开始时间点
          
# 'datetime_complete': 每次试验的完成时间,用于记录试验的结束时间点
          

          
optimization_history = {
          
    'trial_number': [],       # 试验编号
          
    'value': [],              # 目标值
          
    'datetime_start': [],     # 试验开始时间
          
    'datetime_complete': []   # 试验完成时间
          
}
          

          
for trial in study.trials:
          
    optimization_history['trial_number'].append(trial.number)
          
    optimization_history['value'].append(trial.value)
          
    optimization_history['datetime_start'].append(trial.datetime_start)
          
    optimization_history['datetime_complete'].append(trial.datetime_complete)
          

          
# 将数据转换为 DataFrame
          
optimization_history = pd.DataFrame(optimization_history)
          
optimization_history
      

picture.image

从Optuna的study对象中提取每次试验的编号、目标值、开始和结束时间,存入字典并转换为DataFrame,以便查看和分析优化历史


          
# 找到最优试验
          
best_trial_idx = optimization_history['value'].idxmin()
          
best_trial_number = optimization_history['trial_number'][best_trial_idx]
          
best_value = optimization_history['value'][best_trial_idx]
          
plt.figure(figsize=(10, 6), dpi=1200)
          
# 绘制非最佳点
          
plt.plot(
          
    optimization_history['trial_number'], 
          
    optimization_history['value'], 
          
    marker='o', 
          
    linestyle='-', 
          
    color='skyblue', 
          
    alpha=0.4, 
          
    label='All Trials'
          
)
          
# 绘制最佳点
          
plt.plot(
          
    best_trial_number, 
          
    best_value, 
          
    marker='*', 
          
    color='darkblue', 
          
    markersize=15, 
          
    label=f'Best Trial (#{best_trial_number})'
          
)
          
plt.title("Optimization History")
          
plt.xlabel("Trial Number")
          
plt.ylabel("MSE")
          
plt.grid(True)
          
plt.legend(loc='upper right', bbox_to_anchor=(1, 1), frameon=True)
          
plt.savefig('1.pdf', format='pdf', bbox_inches='tight')
          
plt.show()
      

picture.image

从优化历史中找到具有最低目标值(MSE)的最佳试验,并提取其编号和对应的MSE值。然后,绘制优化历史折线图,其中所有试验结果以点的形式呈现,最佳试验点以星号标出,使得用户能够清晰地看到整个调参过程中的性能变化

超参数重要性分析与可视化


          
from optuna.importance import get_param_importances
          
# 获取超参数的重要性数据
          
param_importances = get_param_importances(study)
          
# 将数据转换为 DataFrame
          
Hyperparameter_Importances = pd.DataFrame(list(param_importances.items()), columns=['Parameter', 'Importance'])
          
Hyperparameter_Importances
      

picture.image

使用Optuna的get_param_importances函数来计算超参数对优化目标的重要性,并将其结果转换为DataFrame便于查看和分析


          
# 对参数按重要性进行排序,便于图表的展示
          
Hyperparameter_Importances = Hyperparameter_Importances.sort_values(by='Importance', ascending=False)
          
# 绘制超参数重要性条形图
          
plt.figure(figsize=(10, 6), dpi=1200)
          
bars = plt.barh(Hyperparameter_Importances['Parameter'], Hyperparameter_Importances['Importance'], color='skyblue')
          
plt.gca().invert_yaxis()  # 反转Y轴,使重要性最高的参数在顶部
          
# 为每个条形图显示数值
          
for bar, importance in zip(bars, Hyperparameter_Importances['Importance']):
          
    plt.text(bar.get_width() + 0.01, bar.get_y() + bar.get_height() / 2, 
          
             f'{importance:.3f}', va='center')
          
plt.title("Hyperparameter Importances")
          
plt.xlabel("Importance")
          
plt.ylabel("Parameter")
          
# 设置x轴范围
          
plt.xlim(0, max(Hyperparameter_Importances['Importance']) * 1.1) 
          
plt.savefig('2.pdf', format='pdf', bbox_inches='tight')
          
plt.show()
      

picture.image

对超参数的重要性数据进行排序,然后使用水平条形图展示每个超参数对模型性能的重要性,确保最重要的参数位于顶部。代码还在每个条形上标出数值,提供了各参数对结果影响的精确度量,结果图显示了gamma和learning_rate是对模型性能影响最大的两个超参数,而max_depth和subsample的影响较小。通过这种可视化,用户可以更好地理解哪些超参数最值得关注和优化

多维参数组合与目标值的可视化分析


          
# 提取每次试验的参数组合和目标值
          
data = {
          
    'trial_number': [],
          
    'value': []
          
}
          

          
# 提取所有参数名并初始化列
          
for param_name in study.trials[0].params.keys():
          
    data[param_name] = []
          

          
# 遍历所有试验,提取参数和目标值
          
for trial in study.trials:
          
    data['trial_number'].append(trial.number)
          
    data['value'].append(trial.value)
          
    
          
    # 填充每个参数的值,如果该试验没有设置某个参数,则填充为 None
          
    for param_name in data.keys():
          
        if param_name not in ['trial_number', 'value']:
          
            data[param_name].append(trial.params.get(param_name, None))
          

          
# 将数据转换为 DataFrame
          
Parameter_Combinations = pd.DataFrame(data)
          
Parameter_Combinations
      

picture.image

从每次试验中提取超参数组合和目标值,将其整理成DataFrame,以便后续分析不同参数组合对目标值的影响

gamma和learning_rate对目标值的2D可视化分析


          
from mpl_toolkits.mplot3d import Axes3D
          
Parameter_Combinations['gamma'] = Parameter_Combinations['gamma'].astype(float)
          
Parameter_Combinations['learning_rate'] = Parameter_Combinations['learning_rate'].astype(float)
          

          
plt.figure(figsize=(10, 8))
          

          
# 绘制散点图,使用 'value' 进行颜色编码
          
sc = plt.scatter(
          
    Parameter_Combinations['gamma'],
          
    Parameter_Combinations['learning_rate'],
          
    c=Parameter_Combinations['value'],
          
    cmap='viridis',
          
    s=50,            # 设置散点大小
          
    alpha=0.7        # 设置透明度
          
)
          

          
cbar = plt.colorbar(sc, format='%.3f')
          
cbar.set_label('Objective Value')
          
plt.xlabel("gamma")
          
plt.ylabel("learning_rate")
          
plt.title("2D Plot of gamma and learning_rate vs Objective Value")
          
plt.savefig('3.pdf', format='pdf', bbox_inches='tight')
          
plt.show()
      

picture.image

绘制gamma和learning_rate两个超参数对目标值(Objective Value)的影响【排名影响前二 参数】,通过散点图展示每组参数组合的效果,并使用颜色编码表示目标值大小。结果显示了不同参数组合下的目标值分布,颜色越浅表示目标值越低,从而帮助识别表现较优的参数区域

colsample_bytree、gamma和learning_rate对目标值的3D可视化分析

picture.image

绘制colsample_bytree、gamma和learning_rate三个超参数组合对目标值(Objective MSE)的三维散点图【排名影响前三参数】,使用颜色编码目标值大小。结果图展示了不同参数组合的目标值分布,颜色越浅表示目标值越低,便于识别在多维参数空间中表现最佳的区域,代码与数据集获取:如需获取本文的源代码和数据集,请添加作者微信联系

🎁 赠书活动来啦! 🎁

picture.image

picture.image

支持知识分享,畅享学习乐趣!特别感谢清华出版社 对本次赠书活动的鼎力支持!即日起,只需

点赞、在看、转发 此文章,作者将从后台随机抽取一位幸运儿,免费包邮赠送清华出版社提供的《MATLAB科技绘图与数据分析》这本精彩书籍📚!

💡 赶快参与,一键三连,说不定你就是那位幸运读者哦!

往期推荐

SCI图表复现:整合数据分布与相关系数的高级可视化策略

SCI图表:基于相关性和标准差的多模型评价——泰勒图解析

期刊文章配图:基于分组折线图的多机器学习模型表现评估对比

复现SCI文章 SHAP 依赖图可视化以增强机器学习模型的可解释性

SCI图表复现:优化SHAP特征贡献图展示更多模型细节

复现 Nature 图表——基于PCA的高维数据降维与可视化实践及其扩展

复现Nature图表——基于PCA降维与模型预测概率的分类效果可视化

SCI图表复现:特征相关性气泡热图展示

SCI图表复现:如何直观展示机器学习模型预测结果的准确性和一致性

期刊文章配图:基于雷达图的多机器学习模型表现评估对比

期刊文章配图:斯皮尔曼相关系数热图反应非线性变量相关性

picture.image

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

个人观点,仅供参考

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论