Python/Pandas技术问题:寻找AIC曲线的局部最优值(非全局最小)
寻找96附近的最优AIC阶数的Python实现方案
嘿,这个需求特别合理——有时候全局最优的阶数可能太过高阶(比如这里的192),反而带来过拟合风险,而相近AIC值的低阶模型(比如96附近)会更简洁实用。下面给你几种落地的实现思路:
方法1:直接限定区间找局部最小值
最简单直接的方式就是把搜索范围锁定在96的邻近区间(比如±20阶,你可以根据需求调整),然后在这个区间内找出AIC最小的阶数。
import pandas as pd # 你已有的数据 dic_aic = {0: 16.83024400288158, 1: 10.580792750644934, ..., 192: 10.272853618268071} aic_df = pd.DataFrame(dic_aic.items(), columns=['Order', 'AIC']) aic_df = aic_df.set_index('Order') # 定义96附近的搜索区间,比如80到112 target_range = range(80, 113) # 筛选出区间内的数据 subset_aic = aic_df.loc[target_range] # 找出区间内AIC最小的阶数 local_best_order = subset_aic['AIC'].idxmin() local_min_aic = subset_aic['AIC'].min() print(f"96附近的最优阶数:{local_best_order},对应的AIC值:{local_min_aic}")
方法2:平滑曲线后找局部极小值
如果原始AIC曲线有微小波动,你可以先对曲线做平滑处理,再寻找96附近的局部极小值点,这样结果更稳定。比如用滚动平均来平滑:
# 对AIC值做滚动平滑(窗口大小可以调整,比如5阶) aic_df['Smoothed_AIC'] = aic_df['AIC'].rolling(window=5, center=True).mean() # 寻找局部极小值:当前值小于左右相邻值 aic_df['Is_Local_Min'] = (aic_df['Smoothed_AIC'] < aic_df['Smoothed_AIC'].shift(1)) & \ (aic_df['Smoothed_AIC'] < aic_df['Smoothed_AIC'].shift(-1)) # 筛选出96附近的局部极小值点(比如±15阶) local_mins = aic_df.loc[(aic_df.index >= 81) & (aic_df.index <= 111) & aic_df['Is_Local_Min']] # 从这些局部极小值里挑出AIC最小的那个 if not local_mins.empty: best_local = local_mins['Smoothed_AIC'].idxmin() print(f"平滑后96附近的最优阶数:{best_local},平滑AIC值:{local_mins.loc[best_local, 'Smoothed_AIC']}") else: print("96附近没有找到局部极小值,建议调整窗口大小或区间范围")
方法3:基于曲线变化率(积分/导数)选择最优阶数
如果想用积分的思路,本质是看AIC曲线在96附近的下降趋势:当阶数增加时,AIC下降的幅度越来越小,说明再增加阶数收益很低,这时候的阶数就是我们要找的“拐点”。
你可以计算AIC的一阶差分(也就是相邻阶数的AIC变化量),然后找变化量趋近于0的点(在96附近):
# 计算AIC的一阶差分(后一阶减当前阶,负数表示下降) aic_df['AIC_Diff'] = aic_df['AIC'].diff() # 找96附近,差分绝对值小于某个阈值(比如0.005)的点,且之后的差分变化不大 threshold = 0.005 candidates = aic_df.loc[(aic_df.index >= 85) & (aic_df.index <= 105)] # 筛选出差分绝对值小于阈值的点 potential_orders = candidates[abs(candidates['AIC_Diff']) < threshold].index.tolist() if potential_orders: # 从候选点里选最接近96的,或者AIC最小的 best_order = min(potential_orders, key=lambda x: (abs(x-96), candidates.loc[x, 'AIC'])) print(f"基于变化率的96附近最优阶数:{best_order},AIC值:{candidates.loc[best_order, 'AIC']}") else: print("96附近没有找到符合阈值的阶数,建议调整阈值或区间")
另外,你也可以对差分曲线做积分,看累积的下降总量,当累积量不再明显增加时,对应的阶数就是合适的选择——不过对于这个场景,直接用差分已经足够直观了。
内容的提问来源于stack exchange,提问作者christianbauer1
相关产品推荐
相关产品推荐

