如何在时间序列预测图中添加95%置信区间?代码相关疑问咨询
关于时间序列预测图中95%置信区间的问题解答
首先得明确:你当前代码里的置信区间计算逻辑是完全错误的,不是把0.1换成0.05就能解决的,咱们一步步拆解问题:
1. 你的置信区间计算错在哪?
原来的代码行:
ci = 0.1 * np.std(y_for)/np.mean(y_for)
这本质是用预测值的变异系数(标准差/均值)乘以0.1,和统计意义上的95%置信区间没有任何关系。95%置信区间的核心是围绕预测值,考虑预测误差的分布,而不是预测值本身的离散程度。
如果假设预测误差服从正态分布,95%置信区间对应的是「预测值 ± 1.96 × 预测的标准误差」——这里的标准误差是模型预测的不确定性,不是预测值的标准差。
2. 关于正态性假设的疑问
是的,如果你用「1.96倍标准误差」的方式计算置信区间,确实隐含了预测误差服从正态分布的假设。如果你的时间序列数据或预测误差明显不符合正态性(比如厚尾、偏态),这种方法会不准确,此时更适合用非参数方法(比如bootstrap)生成置信区间。
3. 自动生成置信区间的实用方法
最省心的方式是用statsmodels这类专业时间序列库,它的模型(比如ARIMA、SARIMAX)在预测时会直接返回置信区间,无需手动计算。下面是完整的示例代码:
方法1:用statsmodels内置置信区间(推荐)
import pandas as pd import numpy as np import matplotlib.pyplot as plt from statsmodels.tsa.statespace.sarimax import SARIMAX # 替换成你的数据和预测步长 data = df1['Annualised vol21'] forecast_horizon = 你的预测步长数值 # 拟合模型(这里用SARIMAX,你可以换成自己的模型,比如ARIMA) model = SARIMAX(data[:-forecast_horizon], order=(1,1,1), seasonal_order=(0,0,0,0)) results = model.fit() # 直接获取拟合值、预测值和95%置信区间 fitted_values = results.fittedvalues forecast_values = results.get_forecast(steps=forecast_horizon).predicted_mean confidence_interval = results.get_forecast(steps=forecast_horizon).conf_int() # 整理数据用于绘图 volatility = pd.DataFrame({ 'actual': data.values, 'model': np.append(fitted_values, forecast_values) }, index=data.index) y_train = volatility['actual'][:-forecast_horizon] y_fit = volatility['model'][:-forecast_horizon] y_test = volatility['actual'][-forecast_horizon:] y_for = volatility['model'][-forecast_horizon:] # 绘图 plt.plot(y_train.index, y_train, label='Train') plt.plot(y_test.index, y_test, label='Test') plt.plot(y_fit.index, y_fit, label='Fitted') plt.plot(y_for.index, y_for, label='Forecasted') # 绘制95%置信区间 plt.fill_between(y_for.index, confidence_interval[:,0], confidence_interval[:,1], color='b', alpha=.3, label='95% Confidence Interval') plt.legend() plt.ylim(0, 0.2) plt.xlim(5000, 5500) plt.show()
方法2:Bootstrap非参数置信区间(适合非正态数据)
如果你的数据不满足正态性,可以用bootstrap方法手动生成置信区间,无需分布假设:
# 定义bootstrap置信区间计算函数 def bootstrap_prediction_ci(y_true, y_fitted, y_forecast, n_iter=1000): # 提取拟合阶段的误差 fit_errors = y_true[:-len(y_forecast)] - y_fitted ci_lower = [] ci_upper = [] # 多次重采样误差生成预测区间 for _ in range(n_iter): resampled_errors = np.random.choice(fit_errors, size=len(y_forecast), replace=True) bootstrap_pred = y_forecast + resampled_errors ci_lower.append(np.percentile(bootstrap_pred, 2.5)) ci_upper.append(np.percentile(bootstrap_pred, 97.5)) return np.array([ci_lower, ci_upper]).T # 计算bootstrap置信区间 boot_ci = bootstrap_prediction_ci(volatility['actual'], y_fit, y_for) # 绘图时替换置信区间即可 plt.fill_between(y_for.index, boot_ci[:,0], boot_ci[:,1], color='b', alpha=.3, label='95% Bootstrap CI')
内容的提问来源于stack exchange,提问作者Luigi87




