当前位置: 首页 > backend >正文

第 6 篇:衡量预测好坏 - 评估指标

第 6 篇:衡量预测好坏 - 评估指标

上一篇,我们小试牛刀,用朴素预测、平均法、移动平均法和季节性朴素预测这几种简单方法对未来进行了预测。我们还通过可视化将预测结果与真实值进行了对比。

但光靠眼睛看图来判断“哪个预测更好”往往是不够的,尤其是在模型众多或差别细微时。我们需要一套客观、量化的标准来评估预测模型的表现。这就是预测评估指标 (Evaluation Metrics) 的用武之地。

本篇,我们将学习几种最常用的时间序列预测评估指标:

  1. 它们的核心思想是什么? (基于预测误差)
  2. 常用的指标有哪些? (MAE, MSE, RMSE, MAPE)
  3. 如何用 Python 计算它们?
  4. 如何解读这些指标并比较模型?

准备好给你的预测模型打分了吗?

核心思想:预测误差 (Forecast Error)

所有评估指标的基础都是预测误差,即预测值 (Predicted Value)真实值 (Actual Value) 之间的差异。

Error = Actual Value - Predicted Value

我们通常在测试集 (Test Set) 上计算这些误差,因为测试集代表了模型在“未见过”的数据上的表现,更能反映其真实的预测能力。

单个时间点的误差有正有负,直接求和可能会相互抵消。因此,评估指标通常会对误差进行处理,比如取绝对值或平方,然后再求平均。

常用的评估指标

以下是几个最常用的指标:

1. MAE (Mean Absolute Error) - 平均绝对误差

  • 计算方法: 计算每个时间点误差的绝对值,然后求平均
    • MAE = mean(|Actual - Predicted|)
  • 解读:
    • 表示预测值平均偏离真实值的幅度
    • 单位与原始数据相同,易于理解。例如,如果 CO2 浓度的 MAE 是 2 ppm,意味着我们的预测平均来看与真实值相差 2 ppm。
    • 对所有误差一视同仁,不像 MSE 那样对大误差有更高的惩罚。
  • 目标: 越小越好

2. MSE (Mean Squared Error) - 均方误差

  • 计算方法: 计算每个时间点误差的平方,然后求平均
    • MSE = mean((Actual - Predicted)^2)
  • 解读:
    • 惩罚大误差:由于平方的存在,较大的误差会被不成比例地放大。这对异常值(特别大的误差)很敏感。
    • 单位是原始数据单位的平方(例如 ppm²),不太直观。
    • 在模型优化中常用(因为数学性质好)。
  • 目标: 越小越好

3. RMSE (Root Mean Squared Error) - 均方根误差

  • 计算方法: 计算 MSE,然后取其平方根
    • RMSE = sqrt(MSE)
  • 解读:
    • 同样惩罚大误差
    • 单位与原始数据相同,比 MSE 更容易解释(例如 RMSE 为 2.5 ppm)。
    • 可能是最常用的回归/预测评估指标之一。
  • 目标: 越小越好

4. MAPE (Mean Absolute Percentage Error) - 平均绝对百分比误差

  • 计算方法: 计算每个时间点误差的绝对值占真实值的百分比,然后求平均
    • MAPE = mean(|(Actual - Predicted) / Actual|) * 100%
  • 解读:
    • 表示预测值平均偏离真实值的百分比
    • 易于理解和比较:因为它是一个相对值,可以在不同尺度的数据集或模型间进行比较(例如,“模型 A 的 MAPE 是 5%,模型 B 是 10%”)。
    • 重要缺点:
      • 如果真实值 Actual 为 0,则无法计算(除零错误)。
      • 如果真实值接近 0,MAPE 会变得非常大且不稳定。
      • 当真实值较小时,同样的绝对误差会产生更大的百分比误差,可能导致模型倾向于低估。
  • 目标: 越小越好

该选哪个?

  • RMSEMAE 是最常用的。RMSE 对大误差更敏感,如果你认为大误差特别不可接受,RMSE 是个好选择。MAE 更直观地反映平均误差幅度。
  • MAPE 在需要相对误差比较或向非技术人员解释时很有用,但要注意其缺点。
  • 通常建议同时看多个指标来更全面地评估模型。

Python 计算评估指标

我们可以使用 scikit-learn 这个强大的机器学习库来方便地计算这些指标。

import pandas as pd
import numpy as np
import statsmodels.api as sm
from sklearn.metrics import mean_absolute_error, mean_squared_error, mean_absolute_percentage_error
import matplotlib.pyplot as plt # 如果需要重新绘图# --- 复现上一篇的数据和预测结果 ---
# 1. 加载数据
data = sm.datasets.co2.load_pandas().data
data['co2'].interpolate(inplace=True)
monthly_data = data.resample('M').mean()
train_data = monthly_data[:-24]
test_data = monthly_data[-24:]# 2. 获取/重新生成预测值 (确保这些变量存在且是 Pandas Series/Numpy Array)
# 假设 naive_forecast, simple_avg_forecast, moving_avg_forecast, seasonal_naive_forecast
# 变量已在环境中,或者重新运行上一篇的代码生成它们# --- 朴素预测 ---
last_train_value = train_data['co2'].iloc[-1]
naive_forecast = pd.Series([last_train_value] * len(test_data), index=test_data.index)# --- 简单平均法 ---
train_mean = train_data['co2'].mean()
simple_avg_forecast = pd.Series([train_mean] * len(test_data), index=test_data.index)# --- 移动平均法 ---
window_size = 12
moving_avg = train_data['co2'].iloc[-window_size:].mean()
moving_avg_forecast = pd.Series([moving_avg] * len(test_data), index=test_data.index)# --- 季节性朴素预测 ---
seasonality = 12
seasonal_naive_forecast_list = []
for i in range(len(test_data)):corresponding_train_index = len(train_data) + i - seasonalityif corresponding_train_index >= 0:seasonal_naive_forecast_list.append(train_data['co2'].iloc[corresponding_train_index])else:seasonal_naive_forecast_list.append(last_train_value) # Fallback
seasonal_naive_forecast = pd.Series(seasonal_naive_forecast_list, index=test_data.index)# --- 计算评估指标 ---# 真实值
y_true = test_data['co2']# 各模型预测值
forecasts = {"Naive": naive_forecast,"Simple Average": simple_avg_forecast,f"Moving Average (N={window_size})": moving_avg_forecast,"Seasonal Naive": seasonal_naive_forecast
}results = {}
for name, y_pred in forecasts.items():mae = mean_absolute_error(y_true, y_pred)mse = mean_squared_error(y_true, y_pred)rmse = np.sqrt(mse) # RMSE is sqrt of MSEtry:# MAPE: Ensure y_true doesn't contain zero for calculation# For CO2 data, this is not an issue. Add check for general cases.if np.any(y_true == 0):mape = np.nan # Or handle differently if zeros are expectedelse:mape = mean_absolute_percentage_error(y_true, y_pred) * 100 # sklearn returns fractionexcept Exception as e:print(f"Could not calculate MAPE for {name}: {e}")mape = np.nanresults[name] = {"MAE": mae, "MSE": mse, "RMSE": rmse, "MAPE (%)": mape}print(f"--- {name} ---")print(f"  MAE: {mae:.3f}")print(f"  MSE: {mse:.3f}")print(f"  RMSE: {rmse:.3f}")print(f"  MAPE: {mape:.3f} %")print("-" * (len(name) + 8))# (可选) 将结果整理成 DataFrame 方便比较
results_df = pd.DataFrame(results).T # Transpose to have models as rows
print("\n--- 评估结果汇总 ---")
print(results_df.round(3)) # 保留3位小数

解读与比较

运行上面的代码,你会得到一个清晰的表格,列出了四种简单预测方法在 CO2 数据测试集上的各项评估指标。
在这里插入图片描述
观察 CO2 数据的评估结果 (预期):

  • 你会发现 Seasonal Naive 方法的各项误差指标(MAE, MSE, RMSE, MAPE)通常是最低的。这符合我们上一篇的视觉观察:虽然它没能捕捉到长期趋势,但至少它成功复制了季节性模式,这比完全忽略时间结构的 Naive 和 Average 方法要好得多。
  • Naive, Simple Average, 和 Moving Average 的误差会比较大,因为它们生成的预测线是平的,完全没有跟上 CO2 数据持续上升的趋势和季节性波动。Simple Average 可能误差最大,因为它基于整个(包括很久以前的低值)历史平均。
  • 比较 MAE 和 RMSE:对于所有模型,RMSE 可能都比 MAE 大一些,这反映了 RMSE 对较大误差的惩罚作用。误差分布越不均匀(存在一些特别大的误差),RMSE 相对于 MAE 的值会越大。

关键 takeaway:

  • 评估指标为我们提供了一种客观比较不同模型预测性能的方法。
  • 对于特定数据集,不同模型的表现可能差异很大。
  • 即使是简单的基准模型(如 Naive, Seasonal Naive),计算它们的评估指标也非常重要,因为任何更复杂的模型都应该能超越这些基准才有价值。

小结

今天我们学习了如何科学地评估时间序列预测模型:

  • 核心在于计算预测值真实值之间的误差
  • 掌握了四种常用评估指标:
    • MAE (平均绝对误差): 平均误差幅度,单位与原数据相同。
    • MSE (均方误差): 惩罚大误差,单位是平方。
    • RMSE (均方根误差): 惩罚大误差,单位与原数据相同,常用。
    • MAPE (平均绝对百分比误差): 相对误差,易于比较,但要注意零值和近零值问题。
  • 学会了使用 sklearn.metrics 来计算这些指标。
  • 理解了如何根据指标比较不同模型的预测准确性。

下一篇预告 (系列终章)

我们已经从零基础出发,一起走过了时间序列的加载、可视化、分解、平稳性处理、简单预测和评估的全过程。这为我们打下了坚实的基础。

在下一篇,也是本入门系列的最后一篇,我们将:

  • 回顾整个时间序列分析的基本流程。
  • 讨论本系列介绍内容的局限性。
  • 展望更高级的时间序列模型和技术(如指数平滑, ARIMA, Prophet, 机器学习/深度学习方法)。
  • 提供一些继续学习的资源推荐。

准备好为我们的时间序列入门之旅画上一个圆满的句号,并开启新的学习篇章了吗?敬请期待!


(你的简单预测模型在测试集上得分如何?哪个指标你觉得最有用?欢迎在评论区分享你的计算结果和看法!)

http://www.xdnf.cn/news/955.html

相关文章:

  • 实现侧边栏点击标题列表,和中间列表区域联动效果
  • 《P3029 [USACO11NOV] Cow Lineup S》
  • 代码随想录算法训练营day8(栈与队列)
  • 个性化的配置AndroidStudio
  • MySQL-存储过程--游标
  • 腾讯IMA深度使用指南:从下载安装到高效应用
  • 安全协议分析概述
  • 10天学会嵌入式技术之51单片机-day-3
  • CSS文本属性
  • Java 泛型使用教程
  • 力扣第446场周赛
  • 时序逻辑入门指南:LTL、CTL与PTL的概念介绍与应用场景
  • Typescript中的泛型约束extends keyof
  • 速查手册:TA-Lib 超过150种量化技术指标计算全解 - 7. Pattern Recognition(模式识别)
  • ubuntu学习day4
  • SaltStack远程协助工具
  • Oracle for Linux安装和配置(11)——Linux配置
  • Franka机器人ROS 2来袭:解锁机器人多元应用新可能
  • SpringBoot + Vue 实现云端图片上传与回显(基于OSS等云存储)
  • 单片机可以用来做机器人吗?
  • 超详细实现单链表的基础增删改查——基于C语言实现
  • 聚类算法(K-means、DBSCAN)
  • 基于DeepSeek/AI的资产测绘与威胁图谱构建
  • Java高频面试之并发编程-04
  • LangGraph(一)——QuickStart样例中的第一步
  • linux sysfs的使用
  • XAttention
  • 初识Redis · C++客户端list和hash
  • 爬楼梯(每日一题-简单)
  • 240422 leetcode exercises