Python中Prophet时间序列模型全参数寻优需求咨询
Prophet时间序列预测调参优化方案
核心需求
使用Prophet模型进行时间序列预测,通过训练集-测试集验证方法最小化MAPE误差,需优化以下参数:
- changepoint_range
- changepoint_prior_scale
- seasonality_prior_scale
- holiday_prior_scale
- holiday_mode
完成调参后执行未来预测。
自定义MAPE计算函数
def mape(y_true, y_pred): return round(np.mean(np.abs(((y_true-y_pred)/y_true)*100)),2)
当前调参局限
目前使用Optuna和Tuner库调参,但仅能设置有限尝试次数(50次试验、10次迭代50个样本),无法充分覆盖参数空间,需优化调参逻辑提升参数覆盖度。
Optuna调参代码
def objective(trial): params={'changepoint_range': trial.suggest_loguniform('changepoint_range', 0.1, 1), 'changepoint_prior_scale' : trial.suggest_loguniform('changepoint_prior_scale', 0.01, 0.5), 'seasonality_prior_scale': trial.suggest_loguniform('seasonality_prior_scale', 0.01, 10), 'holidays_prior_scale': trial.suggest_loguniform('holidays_prior_scale', 0.01, 10), 'holidays_mode': trial.suggest_categorical('holidays_mode', ['additive', 'multiplicative']) } model = Prophet() model.fit(Train) future= model.make_future_dataframe(periods= tst) forecast= model.predict(future) prediction= forecast.tail(tst) return mape(Test['y'], prediction['yhat']) study = optuna.create_study(direction='minimize') study.optimize(objective, n_trials=50)
Tuner库调参代码
def objective_function(args_list): global Train, Test params_evaluated= [] results= [] for params in args_list: try: model = Prophet() model.fit(Train) future= model.make_future_dataframe(periods= tst) forecast= model.predict(future) prediction= forecast.tail(tst) error= mape(Test['y'], prediction['yhat']) params_evaluated.append(params) results.append(error) except Exception as e: print(f"Error for params {params}: {e}") params_evaluated.append(params) results.append(25) return params_evaluated, results from scipy.stats import uniform params_space= dict(changepoint_range= uniform(0.5,0.5), changepoint_prior_scale= uniform(0.001,0.5), seasonality_prior_scale= uniform(0.01,10), holidays_prior_scale= uniform(0.01, 10), holidays_mode= ['additive', 'multiplicative'] ) conf_dict= dict() conf_dict['initial_random']= 10 conf_dict['num_iteration']= 50 tuner= Tuner(params_space, objective_function, conf_dict) results= tuner.minimize()
优化方案:最大化参数空间覆盖
由于部分参数为连续型变量,无法实现绝对意义上的全参数组合遍历,可通过「网格采样+随机采样结合」的方式最大化覆盖合理参数区间:
混合调参实现代码
import itertools import numpy as np from prophet import Prophet # 1. 定义参数采样范围:离散参数全枚举,连续参数按合理逻辑采样 holiday_modes = ['additive', 'multiplicative'] # 连续参数取对数/线性尺度的密集采样点,覆盖Prophet官方建议的合理区间 changepoint_ranges = np.linspace(0.7, 0.95, 6) # 0.7-0.95是changepoint_range常用区间 changepoint_priors = np.logspace(-2, -0.3, 5) # 对数尺度采样0.01-0.5 seasonality_priors = np.logspace(-2, 1, 6) # 对数尺度采样0.01-10 holiday_priors = np.logspace(-2, 1, 6) # 对数尺度采样0.01-10 # 2. 生成所有离散参数+连续网格的组合 param_grid = list(itertools.product( changepoint_ranges, changepoint_priors, seasonality_priors, holiday_priors, holiday_modes )) # 3. 补充随机采样点,覆盖网格未涉及的边缘区间 random_sample_count = 200 random_params = [] for _ in range(random_sample_count): random_params.append([ np.random.uniform(0.1, 1), np.random.uniform(0.01, 0.5), np.random.uniform(0.01, 10), np.random.uniform(0.01, 10), np.random.choice(holiday_modes) ]) # 4. 合并网格与随机参数,遍历计算MAPE寻找最优解 all_params = param_grid + random_params best_mape = float('inf') best_params = None for params in all_params: cp_range, cp_prior, seas_prior, hol_prior, hol_mode = params try: model = Prophet( changepoint_range=cp_range, changepoint_prior_scale=cp_prior, seasonality_prior_scale=seas_prior, holidays_prior_scale=hol_prior, holidays_mode=hol_mode ) model.fit(Train) future = model.make_future_dataframe(periods=tst) forecast = model.predict(future) prediction = forecast.tail(tst) current_mape = mape(Test['y'], prediction['yhat']) if current_mape < best_mape: best_mape = current_mape best_params = params print(f"新最优MAPE: {best_mape}, 参数组合: {best_params}") except Exception as e: print(f"参数组合{params}执行失败: {e}") continue # 5. 输出最优结果并训练最终模型 print(f"\n最终最优参数: {best_params}, 最优MAPE: {best_mape}") final_model = Prophet(**dict(zip( ['changepoint_range', 'changepoint_prior_scale', 'seasonality_prior_scale', 'holidays_prior_scale', 'holidays_mode'], best_params ))) final_model.fit(Train) # 替换为实际需要的未来预测期数 future_final = final_model.make_future_dataframe(periods=30) forecast_final = final_model.predict(future_final)
内容的提问来源于stack exchange,提问作者Arun Raaj Rajendhiran
相关产品推荐
相关产品推荐

