用Python实现时间序列模型实战——Day 17: 时间序列模型的评估方法

一、学习内容
1. 预测误差的评估指标

在时间序列预测中,常用的评估指标包括 MAE (Mean Absolute Error), MSE (Mean Squared Error) 和 RMSE (Root Mean Squared Error)。这些指标用于衡量模型的预测误差。

  • MAE (Mean Absolute Error): MAE 衡量预测值与实际值之间的平均绝对误差,公式为:

其中,​ 是实际值, 是预测值, 是样本数量。

  • MSE (Mean Squared Error): MSE 衡量预测值与实际值之间的平均平方误差,公式为:
  • RMSE (Root Mean Squared Error): RMSE 是 MSE 的平方根,用于衡量预测误差的大小,公式为:
2. 交叉验证在时间序列中的应用

在时间序列中,交叉验证的使用不同于普通数据,因为时间序列有时间依赖性。常见的时间序列交叉验证方法是 时间序列滚动窗口法 (Time Series Cross-Validation)。这种方法通过固定训练集,逐步扩大测试集的方式进行交叉验证,保证模型仅使用过去的数据进行预测。

3. 时间序列模型的稳定性分析

模型稳定性 指的是模型在未来时间步中的性能是否能够保持一致。通过分析预测误差随时间的变化情况,我们可以评估模型的稳定性。

二、实战案例

使用不同时间序列模型评估其预测性能,在这个案例中,我们将使用 ARIMA 模型和 Holt-Winters 模型进行预测,评估它们的性能,并使用滚动窗口法进行交叉验证。

1. 数据生成
python 复制代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.holtwinters import ExponentialSmoothing
from sklearn.metrics import mean_absolute_error, mean_squared_error

# 生成模拟的时间序列数据
np.random.seed(42)
n_obs = 150
time = pd.date_range(start='2000-01-01', periods=n_obs, freq='M')
data = 0.5 * np.arange(n_obs) + np.random.normal(0, 1, n_obs)

# 创建数据框
ts_data = pd.DataFrame({'Date': time, 'Value': data})
ts_data.set_index('Date', inplace=True)

# 绘制时间序列
plt.figure(figsize=(10, 6))
plt.plot(ts_data['Value'], label='Original Data')
plt.title('Simulated Time Series Data')
plt.legend()
plt.show()

代码解释:

  • 生成了一个带有线性趋势和噪声的模拟时间序列。

结果输出:

2. 模型构建与预测
python 复制代码
# 构建 ARIMA 模型 (p=1, d=1, q=1)
arima_model = ARIMA(ts_data['Value'], order=(1, 1, 1)).fit()

# 进行一步预测
arima_forecast = arima_model.forecast(steps=12)

# 构建 Holt-Winters 模型
hw_model = ExponentialSmoothing(ts_data['Value'], trend='add', seasonal=None).fit()
hw_forecast = hw_model.forecast(steps=12)

代码解释:

  • 使用 ARIMA 和 Holt-Winters 模型分别对数据进行拟合,并进行未来 12 个月的预测。

3. 模型评估

python 复制代码
# 评估 ARIMA 模型的 MAE, MSE, RMSE
arima_mae = mean_absolute_error(ts_data['Value'][-12:], arima_forecast)
arima_mse = mean_squared_error(ts_data['Value'][-12:], arima_forecast)
arima_rmse = np.sqrt(arima_mse)

# 评估 Holt-Winters 模型的 MAE, MSE, RMSE
hw_mae = mean_absolute_error(ts_data['Value'][-12:], hw_forecast)
hw_mse = mean_squared_error(ts_data['Value'][-12:], hw_forecast)
hw_rmse = np.sqrt(hw_mse)

# 打印评估结果
print(f"ARIMA - MAE: {arima_mae}, MSE: {arima_mse}, RMSE: {arima_rmse}")
print(f"Holt-Winters - MAE: {hw_mae}, MSE: {hw_mse}, RMSE: {hw_rmse}")

代码解释:

  • 使用 MAE、MSE 和 RMSE 三个指标对模型的预测性能进行评估,并输出结果。MAE 评估绝对误差,MSE 评估平方误差,RMSE 评估误差的平方根。

结果输出:

python 复制代码
ARIMA - MAE: 3.0684361288958293, MSE: 12.956223363680662, RMSE: 3.599475428959151
Holt-Winters - MAE: 6.07368718610084, MSE: 37.78886789846922, RMSE: 6.1472650746872155
4. 交叉验证
python 复制代码
# 交叉验证 - 滚动窗口法
window_size = 120
rolling_mae, rolling_mse, rolling_rmse = [], [], []
for i in range(window_size, n_obs):
    train = ts_data['Value'][:i]
    test = ts_data['Value'][i:i+1]
    
    model = ARIMA(train, order=(1, 1, 1)).fit()
    forecast = model.forecast(steps=1)
    
    # 计算滚动窗口内的误差
    rolling_mae.append(mean_absolute_error(test, forecast))
    rolling_mse.append(mean_squared_error(test, forecast))
    rolling_rmse.append(np.sqrt(mean_squared_error(test, forecast)))

代码解释:

  • 使用滚动窗口法进行交叉验证,每次滚动一个时间步,对下一个时间点进行预测。通过滚动预测,计算每个时间点的预测误差。

5. 误差可视化

python 复制代码
# 绘制滚动窗口的预测误差
plt.figure(figsize=(10, 6))
plt.plot(range(window_size, n_obs), rolling_mae, label='MAE')
plt.plot(range(window_size, n_obs), rolling_rmse, label='RMSE')
plt.title('Rolling Forecast Error (Cross-Validation)')
plt.legend()
plt.show()

代码解释:

  • 绘制滚动窗口法中的预测误差变化情况,展示了预测误差随时间的变化趋势。

结果输出:

三、结果分析

1. ARIMA 和 Holt-Winters 模型的预测性能
  • 从输出的 MAE、MSE 和 RMSE 值可以看出,两个模型的预测误差。通常 RMSE 用于评估模型的预测性能,值越小表明模型预测效果越好。
2. 滚动窗口的预测误差分析
  • 随着时间的推移,预测误差(MAE 和 RMSE)可以帮助我们判断模型的稳定性。如果误差波动较小,模型预测性能较为稳定;如果误差逐渐增大,表明模型可能存在过拟合或不适应未来趋势的情况。

四、总结

通过本次案例学习,我们详细了解了时间序列模型的评估方法,尤其是通过 MAE、MSE 和 RMSE 来衡量模型的预测误差。此外,滚动窗口交叉验证方法在时间序列数据中的应用,可以帮助我们更好地评估模型在不同时间点上的稳定性和预测能力。

相关推荐
程序员_三木4 分钟前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
是小崔啊14 分钟前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
tianmu_sama20 分钟前
[Effective C++]条款38-39 复合和private继承
开发语言·c++
黄公子学安全23 分钟前
Java的基础概念(一)
java·开发语言·python
liwulin050624 分钟前
【JAVA】Tesseract-OCR截图屏幕指定区域识别0.4.2
java·开发语言·ocr
jackiendsc29 分钟前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
Oneforlove_twoforjob33 分钟前
【Java基础面试题027】Java的StringBuilder是怎么实现的?
java·开发语言
羚羊角uou35 分钟前
【C++】优先级队列以及仿函数
开发语言·c++
FeboReigns41 分钟前
C++简明教程(文章要求学过一点C语言)(1)
c语言·开发语言·c++
FeboReigns44 分钟前
C++简明教程(文章要求学过一点C语言)(2)
c语言·开发语言·c++