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

第 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, 机器学习/深度学习方法)。
  • 提供一些继续学习的资源推荐。

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


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

相关文章:

  • 机器视觉lcd屏增光片贴合应用
  • unity基础自学2.3:移动和抓握物品
  • Qt项目——汽车仪表盘
  • Git SSH 密钥多个 Git 来源
  • 研究夜间灯光数据在估计出行需求方面的潜力
  • MySQL 按照日期统计记录数量
  • python 练习
  • 基于LoRA的Llama 2二次预训练实践:高效低成本的大模型领域适配
  • 使用c++调用deepseek的api(附带源码)
  • AI律师匹配AI分析法律需求意图并匹配律师
  • 为什么在TCP层(即传输层)没有解决半包、粘包的问题
  • 基于SpringBoot的在线抽奖系统测试用例报告
  • unity之协程
  • 算法学习(二)
  • 【Leetcode 每日一题】2145. 统计隐藏数组数目
  • 爬虫学习——LinkEXtractor提取链接与Exporter导出数据
  • OpenCV 图形API(47)颜色空间转换-----将 I420(YUV 4:2:0) 格式的图像数据转换为 RGB 格式
  • 大模型应用开发大纲
  • 什么是SPA,SPA与MAP区别
  • alibaba-JSONObject使用
  • ESG领跑者|每一步都向前,李宁要让可持续发展成为可持续之事
  • 三部门:对不裁员少裁员的参保企业实施稳岗返还政策至今年底
  • 新质生产力的宜昌解法:抢滩“高智绿”新赛道,化工产品一克卖数千元
  • 动力电池、风光电设备退役潮来袭,国家队即将推出“再生计划”
  • 世界读书日丨这50本书,商务印书馆推荐给教师
  • 上海又现昆虫新物种:体长仅1.5毫米,却是凶猛的捕食者