ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

风电光伏功率预测实战:从数据对齐到Seq2Seq模型调优全解析

风电光伏功率预测实战:从数据对齐到Seq2Seq模型调优全解析 简介这是一份面向风电光伏功率预测竞赛与新能源人工智能研究者的资源包内容围绕DataFountain光伏发电量预测、百度KDD杯2022、国能日新光伏竞赛等真实赛题场景覆盖光伏与风电的发电量预测、序列建模和数据处理方法适合正在备赛或希望入门新能源预测领域的开发者学习。压缩包共含258个文件总大小约139.69MB其中包括120个Python脚本、38个CSV数据集、9个ipynb示例笔记本以及pkl、pth、h5等模型权重与中间结果同时附有xml配置文件、pdf说明和sh运行脚本可支撑从数据清洗、特征工程到模型训练与评估的完整流程。预览中可见电站气象CSV、train_9.csv、wtbdata_245days.csv等典型数据便于对照真实任务做复现实验。目前已有212人学习下载适合需要快速获取现成基线方案、理解seq2seq时间序列预测思路并加速竞赛起步的参赛者参考。1. 风电光伏人工智能竞赛资源DataFountain 光伏预测与百度 KDD Cup 2022 赛题底稿做光伏发电量预测和风电功率预测最折磨人的往往不是模型调参而是数据文件零散、基线代码跑不起来、checkpoint 拿到手里也不知道怎么恢复到自己的训练流程。DataFountain 光伏发电量预测、百度 KDD Cup 2022 这类赛题技术核心都是功率预测背后靠的全是人工智能那套数据分析与深度学习流程。这份资源把竞赛场景里最缺的几样东西装在一起245 天连续采样的风电数据表、七座电站的气象观测文件、三套预测框架源码photovoltaics、PVPredict、Wind_predict_seq2seq以及训练好的 checkpoint。它适合准备参赛的算法工程师、做新能源预测方向的毕设学生以及想快速验证新模型效果的从业者。有了它你可以从原始 CSV 一路跑到预测结果和指标对比省去到处凑数据的时间直接进入改结构和调参阶段。2. 数据文件拆解245 天风电序列与七座电站气象文件怎么对齐先说一个判断这个资源包里的数据是层次分明的三块——风电主表、电站气象表、训练推理样例表。很多人一上来就用 pandas 读完全部文件直接塞模型结果大概率踩到单位不一致、时间戳错位、方向特征跳变这些基础坑。我复现时习惯先把每个文件单独读一遍确认字段、行数、时间跨度再决定怎么合并。下面按实际处理顺序拆开讲。2.1 wtbdata_245days.csv字段、单位与读取检查wtbdata_245days.csv 是这个包里时间跨度最长的核心风电数据245 天意味着有数十万行 10 分钟级采样记录。典型字段包括风机编号、相对日期、分钟级时间戳、风速、风向、理论功率与实际功率。竞赛数据通常把功率做了取整同一风速下功率会有 ±1 的量化抖动这属于数据本身的分布噪声不是脏数据清洗时不要把它当异常值处理。import pandas as pd df pd.read_csv(wtbdata_245days.csv) print(df.columns.tolist()) print(df[TurbID].nunique(), df[Day].min(), df[Day].max()) print(df[Tmstamp].describe()) # Tmstamp 是当天从 0 点累计的分钟数拆成时分后可构造标准时间列 total_minutes df[Tmstamp] hours total_minutes // 10 minutes total_minutes % 10 df[time] pd.to_datetime( df[Day].astype(str) hours.astype(str) : minutes.astype(str) :00 )这段代码先做可读性验证再用日序号与分钟偏移合成标准时间格式目的是让风电主表和后续电站气象 csv 落在同一时间尺度上。Tmstamp // 10是把分钟数换算成小时Tmstamp % 10取分钟余数。需要注意如果你的数据里 Tmstamp 不是这个语义换成// 60和% 60再跑一遍检查。2.2 train_9.csv 与 0001in.csv训练主表与接口样例train_9.csv 是训练主表列结构一般是时间格点、气象变量、历史功率和目标功率。0001in.csv 更像一个推理输入样例它的价值不在于数据量而在于让你不跑完整训练流程就能验证模型接口能不能吃下真实数据。很多人忽略这个文件等到推理阶段才发现特征顺序和训练时不一致回头再调就浪费时间了。train pd.read_csv(train_9.csv) inp pd.read_csv(0001in.csv) print(train.shape, inp.shape) print(inp 独有列:, set(inp.columns) - set(train.columns)) print(train 独有列:, set(train.columns) - set(inp.columns))这段代码用列差集判断两个表的定位。如果 inp 多出来的是 id 和时间字段说明它是按行组织的输入模板如果 train 多出目标列目标变量的列名就明确了。切分特征与标签时先跑这一步能避免把目标列混进特征矩阵。2.3 电站气象文件七座电站 csv 怎么参与建模电站1_气象.csv 到电站7_气象.csv对应七座电站的气象观测。与风电主表不同这些文件更偏水平辐照度、气温、相对湿度、气压等光伏强相关特征。在光伏发电量预测里地表水平辐照度是影响发电量的第一因子温度其次风速主要影响组件散热在大多数模型里权重不高。如果你的目标是做风电这些文件可以作为外生特征补充但不要指望它们带来质的提升。station pd.read_csv(电站5_气象.csv, parse_dates[time]) merged pd.merge_asof( train.sort_values(time), station.sort_values(time), ontime, directionnearest ) print(merged.isna().sum())pd.merge_asof解决的是两表时间戳不等间隔对齐问题每个训练行自动就近匹配一个气象观测时刻避免手动重采样丢失信息。directionnearest表示双向就近匹配适合 10 分钟级训练表与 15 分钟级气象表这类非严格对齐的情况。如果合并后 NaN 过多优先检查时区差异和气象表时间跨度是否覆盖训练表而不是盲目改匹配方向。2.4 特征工程方向余弦化、辐照度滑窗与滞后功率这部分最影响精度。风电方向 Wdir 是 0360 度圆环变量直接喂线性模型会出现 359 度和 0 度物理方向几乎相同、数值距离却很大的问题光伏辐照度天然有昼夜周期夜间为 0直接滑窗会把夜间的零值平均进去导致清晨预测偏低。我的做法是方向拆成 cos 和 sin 两个分量辐照度与功率各做 1 小时滑窗均值与最大值功率再补上 t-1、t-2 滞后值作为自回归特征。import numpy as np def build_features(df, targetpower): df df.copy() df[wdir_cos] np.cos(np.deg2rad(df[Wdir])) df[wdir_sin] np.sin(np.deg2rad(df[Wdir])) df[ghi_ma6] df[GHI].rolling(6).mean() df[ghi_max6] df[GHI].rolling(6).max() for lag in [1, 2]: df[f{target}_lag{lag}] df[target].shift(lag) return df.dropna()这里滑窗 6 对应 10 分钟级采样下的 1 小时窗口。rolling(6).mean()取过去 6 个采样点均值shift(1)和shift(2)取上一时刻与上上时刻功率。滞后特征训练阶段合法但推理阶段第一天会缺失所以脚本里要保留冷启动回退路径把缺失的滞后值替换成当天同一时刻的历史均值而不是直接丢样本。曾有选手在这里翻车上线第一天预测全为 NaN检查了半天才发现是 lag 特征没做兜底。注意merge_asof 前必须对两表按时间列排序否则会报错或匹配出错误结果。3. 模型与代码库选型PVPredict、photovoltaics、Seq2Seq 怎么搭资源包里同时出现 photovoltaics、PVPredict、Wind_predict_seq2seq 三套代码很多人会纠结到底用哪套。我的建议是先搞清楚各自边界选一套当主线其余两套当工具调用。三套都读但都不深入是最耗时间的做法。3.1 三套库的定位先跑通基线再谈结构创新photovoltaics-master 偏向光伏系统设计与性能评估里面可以复用逆变器效率曲线、组件温度模型和归一化评估函数PVPredict-master 是光伏发电量预测专项库适合小样本回归和短期预测Wind_predict_seq2seq 是典型的时间序列序列到序列项目处理风电功率这类强自相关任务更有优势。我的选型逻辑是以 Wind_predict_seq2seq 作为主基线因为它把“历史序列预测未来序列”的样本构造方式写好了循环网络结构也更契合风电时序photovoltaics 里的指标计算函数和数据处理工具留作辅助PVPredict 则当光伏赛道的对比实验组。这样组合最省事且三个库都能用上不会有人问“为什么库都齐了却一个都不用”。3.2 Wind_predict_seq2seq从原始 CSV 到序列样本构建Seq2Seq 处理预测问题的基本假设是未来一段序列与过去一段序列存在可学习的映射关系而非单点对单点回归。竞赛里常用设置是 60 点历史预测 24 点未来对应 10 分钟级采样就是过去 10 小时预测未来 4 小时。下面这段代码把长表时序切成长度为 60 的输入和长度为 24 的输出。def make_sequences(data, input_len60, output_len24): X, y [], [] for i in range(len(data) - input_len - output_len): X.append(data[i:i input_len]) y.append(data[i input_len:i input_len output_len]) return np.array(X), np.array(y) X, y make_sequences(series, input_len60, output_len24) print(X.shape, y.shape)这里的滑窗步长为 1样本数最大化适合数据量不大的竞赛场景。input_len 是编码器看到的历史长度output_len 是解码器输出的预测长度。60 对 24 在竞赛里很常用窗口太长会引入远期噪声太短则看不到天气过程演变。实际调参时可以用验证集 RMSE 来回扫不必死守这个比例。3.3 训练参数序列长度、归一化、损失函数与早停训练配置这块给一组我实测下来比较稳的参数可以直接当起点参数取值说明历史长度6010 小时覆盖典型天气过程预测长度244 小时兼顾短期精度与竞赛需求归一化MinMax功率和风速量纲差异大统一到 01损失函数HuberLoss对功率尖峰鲁棒比 MSE 平稳优化器Adam lr1e-3通用配置免去手工调学习率早停验证集连续 8 轮不降防止过拟合训练尾段噪声model Seq2Seq(input_dimX.shape[-1], hidden_dim64, output_len24) criterion nn.HuberLoss(delta1.0) optimizer torch.optim.Adam(model.parameters(), lr1e-3) best_val float(inf) for epoch in range(60): train_loss train_one_epoch(model, X_train, y_train, criterion, optimizer) val_loss evaluate(model, X_val, y_val, criterion) if val_loss best_val: best_val val_loss torch.save(model.state_dict(), checkpoint.pt) if epoch 10 and val_loss best_val * 1.05: break早停条件里val_loss best_val * 1.05表示验证集比历史最优劣化 5% 以上就停比单纯看是否上升更抗噪声。HuberLoss 的 delta 取 1.0对应归一化后功率的绝对误差阈值对尖峰时段的大误差惩罚更温和避免模型被少数极端天气样本带偏。3.4 checkpoint 加载与推理路径配置checkpoint 是训练好的模型权重加载的关键是把它恢复到与模型结构完全一致的 state_dict 里。很多人把 checkpoint 文件路径写死在自己的工程目录一换机器就报文件找不到还有人在训练脚本里给模型改了层名再加载旧权重直接 KeyError。正确做法是先打印 state_dict 的键名确认层名一致后再加载。import torch model Seq2Seq(input_dimX.shape[-1], hidden_dim64, output_len24) ckpt torch.load(checkpoint.pt, map_locationcpu) print(list(ckpt.keys())[:5]) if list(ckpt.keys()) list(model.state_dict().keys()): model.load_state_dict(ckpt) print(checkpoint 加载成功) else: print(键名不一致需逐层对齐或重训)map_locationcpu是防止服务器上用 GPU 训练、本地用 CPU 推理时出现设备不匹配报错。键名对比是加载前最值得养成的习惯它能在几秒内告诉你权重能不能用而不是等到前向传播跑一半才炸出来。如果键名不一致常见做法是打印差异键手动修改模型层名或写一个映射字典不建议直接strictFalse糊弄过去那等于放弃了一部分已训练参数。提示如果加载时报错形状不匹配先检查输入特征维度。特征工程环节加了方向余弦和滑窗列之后input_dim 会从 4 变成 8 左右旧 checkpoint 无法直接复用。4. 避坑与常见问题跑新能源功率预测模型最值得记录的五个坑这一章写给想快速复现的人。竞赛包下载下来通常能跑通但你要改自己的输入特征、换预测时长、加第三方库时问题才会真正暴露。下面五条是我在风电光伏赛题里反复遇到的类型按“现象、原因、解决”写清楚。4.1 验证集 loss 震荡不降先查数据切分方式现象训练 loss 稳步下降验证 loss 在某个区间剧烈震荡怎么看都不收敛。原因最常见的是用随机切分把同一天样本分到了训练和验证两侧。风电和光伏数据都有强日周期性同一天的凌晨和中午样本被切到两个集合里验证集就泄漏了未来信息模型学到的时序规律在验证集上表现极不稳定。解决改成按时间切分前 80% 天训练后 20% 天验证。同时把切分点写死比如cutoff days[-20]保证每次实验数据口径一致。如果用了滑窗构造序列样本还要检查序列有没有跨切分点把跨边界的样本从训练集拿掉否则仍会有泄漏。4.2 checkpoint 加载报 KeyError变量名不匹配现象加载checkpoint.pt时抛出KeyError: encoder.rnn.weight_ih_l0这类错误。原因训练时模型类名或层名和加载时不一致。最常见的场景是原作者用了Encoder类你在自己的脚本里改成了LSTMEncoder即使结构完全相同PyTorch 依然认为这是两个不同的字典键。解决先print(list(model.state_dict().keys()))和print(list(ckpt.keys()))对比写一个简单的键名映射表。如果只是前缀差异用字典推导式把键名的相同部分对齐如果结构确实变了直接重训最后一层或整个模型不要硬撑。4.3 气象 csv 与训练主表时间戳对不齐merge 后出现大片 NaN现象merge 之后训练集的特征列出现大面积缺失模型训练 loss 直接崩到 0 或者报 NAN。原因气象站采样频率和主表不一致比如主表是 10 分钟粒度气象文件是 1 小时粒度直接按时间字段精确 merge 必然大量落空。另一个隐蔽原因是时区差异某些气象文件用的是 UTC训练表用的本地时间差 8 小时导致匹配不到。解决统一先看两表时间跨度和频率。pd.merge_asof配合directionnearest是短期补空的首选如果时间差超过 30 分钟先重新采样气象数据。时区问题直接给时间列加tz_localize再tz_convert统一到同一时区后重新对齐。不要用bfill无脑填夜间光伏序列前向填充会把白天数据填到夜里。4.4 光伏预测在夜间出现负功率输出层没做约束现象预测曲线整体合理但夜间时段出现负功率比如 -8MW物理上不可能。原因输出层用了纯线性激活模型为了拟合某个阴雨天的低辐照时段学出了一段略微过冲的映射关系。光伏夜间真实功率就是 0模型输出负值完全是因为没有物理约束。解决在推理阶段对输出做clip(min0)这是最轻量的方案。更严谨的做法是在输出层后接ReLU()或softplus从网络结构层面保证非负。推荐后者因为它让训练和推理的行为一致clip 只修推理不修训练梯度仍然会走到负值区间。pred model(X_batch) pred torch.clamp(pred, min0) # 推理兜底夜间功率强制归零这种小改动对最终评分影响显著RMSE 可能因此下降 2% 左右因为夜间样本的平方误差从 64 变成了 0。4.5 第三方库 import 报错Python 版本与依赖冲突现象导入 photovoltaics 或 PVPredict 时报ModuleNotFoundError或版本不兼容的红字比如 numpy 版本过新导致某个函数没有属性。原因竞赛包的代码通常在 2022 年前后写成依赖的是旧版 pandas、numpy、sklearn。你本地环境装的是最新版API 变化后旧代码直接废了。解决建虚拟环境按仓库里的 requirements 安装。如果仓库没有 requirements按代码里 import 的包手工逐个装版本参考 2022 年前后的稳定版本比如 pandas 1.5、numpy 1.23、torch 1.12。安装第三方库之前先python --version确认解释器版本Python 3.10 以下对旧代码更友好。如果真的要在新版环境里跑优先替换已删除的 API例如 sklearn 的train_test_split不会变但sklearn.preprocessing里某些函数签名变了需要逐行对报错处理。注意不要为了省事把新版本 numpy 降级到旧版某些新代码库会反向报错。最好的习惯是给每个竞赛包单独开虚拟环境互不污染。5. 进阶验证用竞赛口径复现 RMSE 与误差拆解5.1 复现评分逻辑MAE、RMSE 与预测时段偏好竞赛评分通常以预测功率与实际功率的均方根误差RMSE为主要指标部分赛题会加权处理不同时段。复现评分脚本是验证模型好不好用的第一步它决定你后面所有调参是否有意义。很多选手在自己脚本里算的指标和官方结果差不少原因多半是归一化逆变换没做好或者预测值没有对齐到真实时间索引。from sklearn.metrics import mean_squared_error, mean_absolute_error pred inverse_transform(pred) # 逆归一化回真实功率单位 mae mean_absolute_error(y_true, pred) rmse np.sqrt(mean_squared_error(y_true, pred)) with open(result.txt, w) as f: f.write(fMAE: {mae:.3f}, RMSE: {rmse:.3f}\n)逆变换是整个流程里最容易翻车的一步。如果训练时用 MinMax 把功率压到 01推理后忘记还原RMSE 会小得离谱那不是模型好是单位错了。写完这段脚本后先在一小段验证集上人工核对几个点的量级确认功率在几十到几百 MW 的正常范围再去做模型迭代。5.2 预测曲线合理性检查日夜切换、爬坡时段与功率天花板数值指标达标的模型曲线不一定合理。我每次训练完都会画几张预测对比图重点看三个区域清晨日出时预测有没有滞后傍晚日落时预测有没有拖尾以及强风爬坡段预测是否跟得上斜率。辐照度曲线在日出时段变化最陡模型如果只学了平滑拟合预测会明显落后真实曲线半个到一个采样点爬坡段偏慢则说明历史窗口太短模型还没看到足够趋势就被要求输出未来 24 点。import matplotlib.pyplot as plt plt.plot(y_true[240:288], labelreal) plt.plot(pred[240:288], labelpred) plt.legend() plt.savefig(check.png, dpi100)240 到 288 是某天白天时段的 48 个点涵盖日出和午间平段。如果曲线出现「预测永远比真实慢半拍」的模式不要急着加模型层数先把滑窗长度从 60 加到 96一般能缓解。如果夜里预测有波纹状抖动检查归一化边界是否有异常值或者在训练集里把夜间样本按比例降权。从那以后我每跑一个竞赛包都强制走一遍「数据核对 → 基线冒烟 → 指标复现」三步任何一步不确认清楚都不往下调参。这套流程帮我省下的返工时间远比想象的要多也希望帮到你。本文还有配套的精品资源点击获取
返回列表