用 ERA5 历史数据回测新能源功率预测模型:walk-forward 实战

新能源功率预测模型上线前,最该回答的问题不是「线下指标多好看」,而是「换到没见过的历史时段,它还稳不稳」。回测就是干这件事的。问题在于:真实的功率标签来自电站 SCADA,气象输入却分两种身份——训练阶段你想要一份「干净、连续、无缺测」的历史气象底座,上线后又只能拿到带误差的未来预报。把这两种身份混着用,回测就会系统性偏乐观。本文给出一套以 ERA5 为检验底座、用 walk-forward 切分、严格防数据泄漏,并最终与德国气象局(DWD)预报衔接做在线评估的工程方法,所有气象数据都通过运梦气象 API 拉取。
关键要点
- ERA5(ECMWF 第五代再分析,0.25°、1 小时步长)适合当回测底座,因为它无缺测、口径统一、可复现;但它是「近似真值的气象输入」而非预报,量出的是机理上限,不是生产精度。
- 回测必须用 walk-forward 滚动切分(训练窗永远在检验窗之前),绝不能随机打乱做 K 折,且折与折之间要留至少一个最长滑窗长度的 gap 防止串味。
- 误差指标核心四项:RMSE/nRMSE、MAE/nMAE、MAPE(只在日间或有效出力样本上算)、合格率(|ŷ−y|/C ≤ 阈值,光伏短期常用 25%);对外建议只报 nRMSE + 合格率,并补一个相对持续法的 Skill Score。
- 回测偏乐观九成是数据泄漏:未来信息泄漏、标签泄漏、底座身份泄漏、重采样泄漏——scaler 只在训练折上 fit,重采样一律用因果处理。
- 运梦气象 API 把 ERA5 历史(dataSourceId="era5")与德国气象局预报("ger",覆盖未来约 7 天)统一在一个端点下发,响应为统一 JSON envelope;上线后从 era5 切到 ger 做在线评估即可量出端到端生产精度。
为什么用 ERA5 当回测底座
ERA5 是 ECMWF 第五代再分析数据集,把卫星、地面站、探空等多源观测同化到一致的全球网格上,水平 0.25°、时间 1 小时步长,物理一致且时空连续。对回测而言它有三个不可替代的好处:一是无缺测,不会像站点观测那样隔三差五断档,回测样本不会被掏空;二是口径统一,同一套 CF 命名字段(tas 气温、rsds 地表短波、uas/vas 与 u100/v100 风分量、ws/wd 派生风速风向),跨年份跨站点都对得上;三是可追溯,再分析对历史是确定的,任何人重跑都能复现同一份输入。
但要钉死一个认知:ERA5 是「近似真值的气象输入」,不是「预报」。它有约 T-5 天的滞后,且本质是后验同化产物。所以拿 ERA5 训出来、用 ERA5 验出来的模型,衡量的是机理映射能力(从气象到功率这层物理关系学得准不准),而不是端到端的生产精度。后者要等接入真实预报后才算数——这正是第六节在线评估要补的一环。先用 ERA5 把模型的天花板量出来,再看预报误差把它拉低了多少,归因才清楚。
walk-forward 回测怎么切
时间序列绝不能随机打乱做 K 折,那等于让模型「看着未来猜过去」。正确做法是 walk-forward(滚动前推):按时间把样本切成若干段,训练窗永远在检验窗之前,窗口逐段向前滚动。
一种常用的扩张窗口方案:用 2021 全年训练、2022 Q1 检验;再用 2021 至 2022 Q1 训练、2022 Q2 检验;如此滚动。每一折的检验段都是模型从未见过的未来时段,多折指标取平均与分布,才能反映模型在不同季节、不同天气型下的真实泛化。固定窗口(只保留最近 N 个月训练)则更贴近生产中「概念漂移、近期更重要」的场景,适合容量或运行方式频繁变动的电站。
两个工程细节要守住。其一,折与折之间留缓冲间隔(gap)。功率预测常用滞后特征和滑动统计,如果检验段紧贴训练段末尾,滑窗会跨越边界把训练段的信息带进来。在两段之间空出至少一个最长滑窗长度的间隔,能切断这种串味。其二,按自然时间块切,不按样本数切,保证每折检验段覆盖完整的昼夜与天气周期,否则光伏模型很容易在「全是阴天的检验折」上得出误导性结论。
误差指标怎么报才不骗人
回测产出的指标必须能落到电网两个细则和内部调度两套口径上。核心四个:
RMSE(均方根误差)对大误差敏感,平方放大极端时刻,工程上常归一化到装机容量 C 得到 nRMSE(单位 %)。MAE(平均绝对误差)更稳健,反映平均偏多少,同样可归一化为 nMAE。MAPE(平均绝对百分比误差)在功率趋近零时会爆炸——光伏的夜间、风电的静风期分母太小,数值毫无意义,所以 MAPE 只在日间或有效出力样本(如光伏 GHI > 50 W·m⁻²)上算。合格率对齐两个细则:统计 |ŷ − y| / C ≤ 阈值(光伏短期常用 25%)的时段占比,这是直接挂考核电费的硬指标。
报指标时务必声明四件事:是否剔除限电/检修样本、归一化用的是装机还是开机容量、MAPE 的日间掩码阈值、时间分辨率(15 min 还是 1 h)。少了任何一条,nRMSE 9% 和 12% 之间的差距可能纯粹是口径游戏。建议对外只报 nRMSE + 合格率两项,再补一个相对持续法(persistence)的 Skill Score 防止「看着准其实没跑赢什么都不做」。
最容易踩的数据泄漏
回测偏乐观,九成是泄漏。逐条排雷:
未来信息泄漏:构造特征时用了检验时刻之后才知道的量。最隐蔽的是用全样本统计量(整段均值、整段分位数)做标准化或分箱——这些统计量里已经含了未来。正确做法是 scaler 只在训练折上 fit,再 transform 到检验折。
标签泄漏:把与功率强相关、但生产时拿不到的量当特征,比如把实测 GHI 或实测功率的同期值喂进模型。回测时它在,上线时它没有。
底座身份泄漏(本文重点):训练和检验都用 ERA5,会让模型误以为「气象输入永远像 ERA5 一样准」。可生产时输入是带误差的预报,模型对气象输入的脆弱性被回测掩盖了。务必明确:用 ERA5 跑出的是机理上限,不是生产精度,二者要分开报。
重采样泄漏:把 1 h 的 ERA5 插值/重采样到 15 min 时若用了居中插值,会把后一个时刻的值漏给前一时刻。回测一律用因果(只用过去与当前)的处理方式。
在运梦气象 API 上手
运梦气象 API 把 ERA5 历史与德国气象局(DWD)预报统一在一个端点下发:历史用 dataSourceId="era5",预报用 "ger"(覆盖未来约 7 天)。响应是统一 JSON envelope,data 里 timeList 与各字段数组按下标一一对应,没有 CSV/NetCDF、没有 format 参数,用 resp.json() 解析即可。下面这段可直接跑,拉一段 ERA5 作为回测底座:
import os, requests
import pandas as pd
API = "https://console.yun-meng.top/api/energy-weather/search/weather/action/downloadSync"
TOKEN = os.environ["YM_API_TOKEN"] # 试用注册即得
payload = {
"dataSourceId": "era5", # 历史底座;预报改成 "ger"
"lat": 39.9, "lon": 116.4,
"stime": "2021-01-01 00:00",
"etime": "2022-12-31 23:00",
"timezone": "8", # 必填,时区偏移
"fields": ["tas", "u100", "v100", "ws", "rsds"],
}
resp = requests.post(API, headers={"Authorization": f"Bearer {TOKEN}"},
json=payload, timeout=600)
resp.raise_for_status()
result = resp.json()
if not result.get("success"):
raise RuntimeError(result.get("msg", "查询失败"))
data = result["data"]
df = pd.DataFrame({
"time": pd.to_datetime(data["timeList"]),
"tas": data["tas"],
"u100": data["u100"],
"v100": data["v100"],
"ws": data["ws"],
"rsds": data["rsds"],
}).set_index("time")
print(df.shape, df.head())
# df 即可作为 walk-forward 回测的气象底座,与电站功率标签按时间对齐
拿到 df 后,按时间和 SCADA 功率标签 join,再走前面的 walk-forward 切分与指标评估即可。注意 tas 单位是开尔文(K),rsds 是 W·m⁻²,ws 是 m·s⁻¹,对齐时不要漏掉单位换算。
衔接 ger 预报做在线评估
回测只是上线许可,不是终点。模型上线后,要把 dataSourceId 从 "era5" 切到 "ger",按预报时效(D+1、D+2……)滚动拉取预报,用同一套指标做在线评估。这一步才量出端到端生产精度。
实操上有两点:一是对齐发布时刻。每天预报发布后归档当时的 ger 输入与模型输出,等真实功率回流后再算指标,避免用「事后修订过的预报」自我安慰。二是做归因拆分:把同一时段分别喂 ERA5 与 ger,对比两者驱动的功率误差——ERA5 驱动的误差是机理项,ger 与 ERA5 的差额就是预报误差项。如果在线指标明显劣于回测,先看是预报误差放大(多半如此,换更优 NWP 或做偏差订正),还是模型对输入扰动过敏(回去补抗噪)。把 ERA5 底座回测与 ger 在线评估这条闭环搭起来,功率预测的迭代才有据可依,而不是盲目调参。
常见问题
为什么不能用 ERA5 的回测结果直接当生产精度? ERA5 是后验同化的「近似真值的气象输入」,有约 T-5 天滞后,不是预报。用 ERA5 训、用 ERA5 验,量出的是从气象到功率的机理映射能力(机理上限);生产时输入是带误差的预报,端到端精度要等接入 ger 预报做在线评估后才算数。
功率预测回测为什么不能随机打乱做 K 折交叉验证? 随机打乱会让训练集混入检验时段之后的样本,等于让模型「看着未来猜过去」,指标系统性偏乐观。正确做法是 walk-forward 滚动前推,训练窗永远在检验窗之前,并在折与折之间留至少一个最长滑窗长度的 gap,切断滞后特征和滑动统计的串味。
MAPE 在功率预测里为什么经常不靠谱? MAPE 在功率趋近零时会爆炸——光伏的夜间、风电的静风期分母太小,数值毫无意义。所以 MAPE 只在日间或有效出力样本(如光伏 GHI > 50 W·m⁻²)上算,对外更建议用 nRMSE + 合格率,再补一个相对持续法的 Skill Score。
回测时最容易踩的数据泄漏有哪些? 四类:未来信息泄漏(用全样本统计量做标准化,应让 scaler 只在训练折上 fit)、标签泄漏(把实测 GHI 或实测功率等生产时拿不到的量当特征)、底座身份泄漏(训练和检验都用 ERA5,掩盖了模型对预报误差的脆弱性)、重采样泄漏(居中插值把未来值漏给当前,应一律用因果处理)。
运梦气象 API 怎么同时拿到 ERA5 历史和预报数据? 两者统一在同一个端点下发:历史用 dataSourceId="era5",预报用 "ger"(覆盖未来约 7 天)。响应是统一 JSON envelope,data 里 timeList 与各字段数组按下标一一对应,没有 CSV/NetCDF、没有 format 参数,用 resp.json() 解析即可。上线后把 era5 切到 ger 就能做在线评估。
参考与延伸阅读
- Hersbach, H., Bell, B., Berrisford, P., Hirahara, S., Horányi, A., Muñoz-Sabater, J., et al. (2020). The ERA5 global reanalysis. Quarterly Journal of the Royal Meteorological Society, 146(730), 1999–2049. https://doi.org/10.1002/qj.3803
- Rasp, S., Hoyer, S., Merose, A., Langmore, I., Battaglia, P., Russell, T., et al. (2024). WeatherBench 2: A benchmark for the next generation of data‑driven global weather models. Journal of Advances in Modeling Earth Systems, 16(6), e2023MS004019. https://doi.org/10.1029/2023MS004019
- Eaton, B., Gregory, J., Drach, B., Taylor, K., Hankin, S., et al. (2023). NetCDF Climate and Forecast (CF) Metadata Conventions, Version 1.11. https://cfconventions.org/cf-conventions/cf-conventions.html (Zenodo: https://doi.org/10.5281/zenodo.14275572)
- 国家能源局.《电力并网运行管理规定》(国能发监管规〔2021〕60号)、《电力辅助服务管理办法》(国能发监管规〔2021〕61号). 2021年12月. (业内俗称新版「两个细则」的上位文件;各区域据此制定《区域电力并网运行管理实施细则》《区域电力辅助服务管理实施细则》)