如何编程获取SARIMAX模型p/q/m参数范围以缩短网格搜索耗时
SARIMAX参数自动取值范围实现方案
下面是对应参数的编程实现方案,不需要人工查看可视化结果,直接输出可用的取值范围:
差分阶数d自动计算
通过ADF单位根检验自动判断所需差分次数,不需要手动循环,且最优差分阶数通常唯一,不需要做网格搜索:
from statsmodels.tsa.stattools import adfuller def get_optimal_d(ts, max_diff=2, sig_level=0.05): d = 0 # 最多差分2次,差分会丢失信息,超过2次通常没有实际意义 while d <= max_diff: adf_p = adfuller(ts)[1] if adf_p < sig_level: return d ts = ts.diff().dropna() d += 1 return max_diff
p值取值范围计算
基于PACF的统计显著性判断最大p值,最小值默认取0即可:
from statsmodels.tsa.stattools import pacf import numpy as np def get_p_range(ts, max_p_limit=10, sig_level=0.05): # 计算pacf和对应的置信区间 pacf_vals, conf_int = pacf(ts, nlags=max_p_limit, alpha=sig_level) # 找到所有显著不为0的滞后阶数(排除0阶自相关) sig_lags = np.where(np.abs(pacf_vals) > (conf_int[:,1] - pacf_vals))[0] max_p = sig_lags.max() if len(sig_lags) > 0 else 0 # 限制上限避免搜索范围过大 max_p = min(max_p, max_p_limit) return 0, max_p
返回的第一个值就是min_series_p,第二个值就是max_series_p。
q值取值范围计算
逻辑和p值完全一致,替换为ACF计算即可:
from statsmodels.tsa.stattools import acf def get_q_range(ts, max_q_limit=10, sig_level=0.05): acf_vals, conf_int = acf(ts, nlags=max_q_limit, alpha=sig_level) sig_lags = np.where(np.abs(acf_vals) > (conf_int[:,1] - acf_vals))[0] max_q = sig_lags.max() if len(sig_lags) > 0 else 0 max_q = min(max_q, max_q_limit) return 0, max_q
返回的第一个值就是min_series_q,第二个值就是max_series_q。
季节性周期m自动计算
可以根据你的数据特性选以下任意一种方案:
方案1:ACF峰值法(最常用)
def get_seasonal_m(ts, max_m_limit=365): acf_vals = acf(ts, nlags=max_m_limit) # 排除0阶,找ACF最大的峰值对应的滞后阶数 acf_vals[0] = 0 # 过滤掉小于0.2的峰值,避免噪声干扰 acf_vals[acf_vals < 0.2] = 0 m = acf_vals.argmax() return m if m > 0 else 1
方案2:已知采样频率直接赋值
如果你的数据采样频率是固定的,可以直接写规则,不需要计算:
def get_seasonal_m_by_freq(freq): # freq是pandas的时间频率,比如'H'是小时,'D'是天,'M'是月 freq_map = { 'H': 24, 'D': 7, 'W': 52, 'M': 12, 'Q': 4 } return freq_map.get(freq, 1)
返回值就是sts_series_m。
搜索代码优化提示
你原来的网格搜索代码可以简化,不需要两层循环:
# 先计算所有参数 min_p, max_p = get_p_range(ts) min_q, max_q = get_q_range(ts) d = get_optimal_d(ts) m = get_seasonal_m(ts) p_range = range(min_p, max_p+1) q_range = range(min_q, max_q+1) for p in p_range: for q in q_range: param = (p, d, q) param_s = (p, d, q, m) mod = SARIMAX(ts.to_numpy(), order=param, seasonal_order=param_s) model_fit = mod.fit(iprint=0, disp=0, method_kwargs={"warn_convergence": False})
该方案可以直接把搜索范围缩小到合理区间,耗时至少能减少80%以上。
内容的提问来源于stack exchange,提问作者Stavros Koureas
相关产品推荐
相关产品推荐

