第 6 篇:衡量预测好坏 - 评估指标
第 6 篇:衡量预测好坏 - 评估指标
上一篇,我们小试牛刀,用朴素预测、平均法、移动平均法和季节性朴素预测这几种简单方法对未来进行了预测。我们还通过可视化将预测结果与真实值进行了对比。
但光靠眼睛看图来判断“哪个预测更好”往往是不够的,尤其是在模型众多或差别细微时。我们需要一套客观、量化的标准来评估预测模型的表现。这就是预测评估指标 (Evaluation Metrics) 的用武之地。
本篇,我们将学习几种最常用的时间序列预测评估指标:
- 它们的核心思想是什么? (基于预测误差)
- 常用的指标有哪些? (MAE, MSE, RMSE, MAPE)
- 如何用 Python 计算它们?
- 如何解读这些指标并比较模型?
准备好给你的预测模型打分了吗?
核心思想:预测误差 (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 会变得非常大且不稳定。
- 当真实值较小时,同样的绝对误差会产生更大的百分比误差,可能导致模型倾向于低估。
- 如果真实值
- 目标: 越小越好。
该选哪个?
- RMSE 和 MAE 是最常用的。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, 机器学习/深度学习方法)。
- 提供一些继续学习的资源推荐。
准备好为我们的时间序列入门之旅画上一个圆满的句号,并开启新的学习篇章了吗?敬请期待!
(你的简单预测模型在测试集上得分如何?哪个指标你觉得最有用?欢迎在评论区分享你的计算结果和看法!)