光伏发电量预测实战:从DataFountain赛题到工程落地

发布时间:2026/10/13 13:10:54
光伏发电量预测实战:从DataFountain赛题到工程落地 简介这份资源面向新能源功率预测方向的学习者与竞赛选手汇集了DataFountain光伏发电量预测、百度KDD杯2022、国能日新光伏竞赛等多个赛事的代码与数据覆盖风电、光伏发电量预测这一人工智能典型应用场景适合具备一定机器学习与深度学习基础、希望系统复现赛题方案的中高级读者。压缩包共258个文件约139.69MB以120个Python脚本和38个CSV数据文件为主另含Jupyter笔记本、模型权重、配置与说明文档涵盖数据处理、模型训练到结果评估的完整链路。资源中既有光伏电站气象与发电数据也包含序列到序列风电预测模型及光伏预测库可帮助读者理解时间序列建模、特征工程与模型调优思路并对照基线方案快速搭建自己的实验环境。目前已有212人学习下载适合作为新能源功率预测入门与竞赛复盘的参考素材。1. 从 DataFountain 光伏发电量预测赛题说起一条被低估的工程落地路径很多人第一次接触「风电光伏人工智能竞赛」是从 DataFountain 光伏发电量预测、百度 KDD 杯 2022 这类赛题开始的。赛题给的往往是一年多的历史功率、气象观测和数值天气预报要求预测未来 1 到 3 天的发电量。看起来是个回归问题但真正做过的人都知道它比图像分类难缠得多白天有功率、晚上恒为零阴天骤降、晴天爬坡云层移动带来的分钟级波动几乎无法从日尺度特征里还原。这也是为什么「光伏第三方库」在近两年被反复提起——pvlib、SolarPosition、PVGIS 这些工具能把太阳几何、组件温度、辐照度转换算清楚让你不必从零推导天文公式。这篇文章面向的是想把这套东西真正跑起来的人无论你是打竞赛、做电站功率预测系统还是给园区做光伏出力分析下面这条路径都能直接复用。人工智能在这里不是噱头而是把物理先验和统计模型缝在一起的那根线。2. 光伏功率预测的物理底座先算清楚太阳再谈模型2.1 为什么不能直接把气象特征丢给 XGBoost我见过太多人拿到赛题数据后第一反应是把温度、湿度、辐照度、风速全部塞进 LightGBM然后发现验证集 RMSE 卡在某个值上再也下不去。问题不在模型而在特征本身没有物理含义。光伏出力 P 大致正比于组件接收到的辐照度 G 和组件效率 η而 η 又随组件温度升高而下降。如果你只给模型一个「环境温度」它无法区分「冬天正午 5℃」和「夏天清晨 5℃」这两种辐照条件完全不同的场景。正确做法是先算出太阳位置高度角、方位角再算晴空辐照度最后用云量或实测辐照度去修正。这一步做完你会发现同样的 LightGBMRMSE 能降 15% 以上。这不是玄学是物理先验在帮你把输入空间对齐。2.2 用 pvlib 算太阳位置与晴空辐照度的最小代码下面这段代码是我每次做光伏预测时的起手式输入只有时间戳、经纬度和时区输出是太阳天顶角、方位角和晴空 GH I。注意 pvlib 的 API 在不同版本间有过调整我一般锁定 0.10 以上的版本。import pandas as pd import pvlib from pvlib.location import Location # 站点信息以某华东电站为例经纬度按实际填 lat, lon, tz 31.23, 121.47, Asia/Shanghai site Location(lat, lon, tz, altitude10, namedemo) # 构造时间索引频率 15 分钟与多数赛题数据对齐 times pd.date_range(2023-01-01 00:00, 2023-12-31 23:45, freq15min, tztz) # 太阳位置apparent_zenith 为视天顶角azimuth 为方位角 sp site.get_solarposition(times) # 晴空模型Ineichen 在低纬表现稳Simplified_Solis 更快 cs site.get_clearsky(times, modelineichen) df pd.DataFrame({ zenith: sp[apparent_zenith], azimuth: sp[azimuth], ghi_clear: cs[ghi], dni_clear: cs[dni], dhi_clear: cs[dhi], }) print(df.head())逻辑说明get_solarposition内部用的是 NREL SPA 算法精度在秒级足够 15 分钟粒度使用。get_clearsky返回的是假设无云条件下的辐照度它是后续做「晴空指数」的基准。参数上altitude影响大气质量修正平原电站填 0 到 50 即可高原电站必须填真实海拔否则晴空辐照度会偏高。model选ineichen是因为它同时输出 GHI、DNI、DHI 三个分量方便后面做倾斜面转换如果只关心 GHI用simplified_solis能快一倍。2.3 从水平面到倾斜面POA 辐照度转换的四个参数拿到 GHI 之后不能直接喂模型因为组件是倾斜安装的。pvlib 的get_total_irradiance需要你提供组件倾角、方位角、以及一个分解模型。我一般用haydavies它在多数气候区误差可控。# 组件朝向固定式支架倾角 25 度正南 tilt, surface_azimuth 25, 180 poa pvlib.irradiance.get_total_irradiance( surface_tilttilt, surface_azimuthsurface_azimuth, solar_zenithsp[apparent_zenith], solar_azimuthsp[azimuth], dnics[dni], ghics[ghi], dhics[dhi], modelhaydavies, albedo0.2, # 地面反射率草地 0.2雪地 0.6 ) df[poa_clear] poa[poa_global]这里albedo是最容易被忽略的参数。华东草地取 0.2西北戈壁取 0.25冬季有积雪的北方电站要按月份动态调整否则冬季预测会系统性偏低。surface_azimuth用 180 表示正南如果电站是东西向跟踪支架这个值要随时间变化那就得用pvlib.tracking模块单独处理。做完这一步你手里就有了「理论出力上限」接下来才是机器学习登场的时候。3. 从竞赛数据到可训练特征DataFountain 与 KDD 杯的通用处理链3.1 赛题数据长什么样先做三张图再动手DataFountain 光伏发电量预测和百度 KDD 杯 2022 的数据结构高度相似一张功率表时间戳 实际出力一张气象表时间戳 辐照度、温度、湿度、风速、气压有时还有一张 NWP 预报表。别急着 merge先画三张图第一张是功率全年时序看有没有停机检修的零值段第二张是功率对晴空指数的散点看离群点第三张是每日功率曲线叠加看季节性的日出日落偏移。这三张图能帮你判断数据里有没有「人为清零」和「传感器漂移」。我一般用 matplotlib 快速出图不追求美观只求看出问题。3.2 晴空指数与清洗规则把夜间和异常值摘干净晴空指数 kt 实测 GHI / 晴空 GHI是光伏预测里最有用的中间变量。kt 接近 1 表示晴天0.3 到 0.6 表示多云低于 0.2 基本是阴雨天。但实测 GHI 经常有夜间负值或白天尖刺需要清洗。# 合并实测辐照度与晴空辐照度 df df.join(meas_ghi) # meas_ghi 为实测 GHI 列 df[kt] df[meas_ghi] / df[ghi_clear] # 清洗规则夜间 kt 置 NaN白天异常值截断 df.loc[df[zenith] 90, kt] float(nan) df[kt] df[kt].clip(lower0, upper1.2) # 功率归一化除以装机容量得到 0-1 的出力比 df[power_ratio] df[power] / capacity df.loc[df[zenith] 90, power_ratio] 0注意clip上限给 1.2 而不是 1.0是因为实测 GHI 偶尔会因反射增强超过晴空值直接截到 1 会丢失信息。夜间功率强制置零而不是置 NaN是因为物理上夜间出力必然为零置 NaN 反而会让模型学到「夜间缺失」这种无意义模式。这一步做完你的特征表里应该同时有kt、power_ratio、zenith、azimuth、poa_clear这几列它们构成了后续所有模型的输入基础。3.3 滑窗特征与时间编码让树模型看见「昨天同时刻」光伏功率有强自相关性昨天同一时刻的出力对今天有参考价值。我一般构造三类滑窗前 1 天同时刻、前 3 天同时刻均值、前 1 小时均值。时间编码用 sin/cos 对小时和月份做周期展开避免树模型把 23 点和 0 点当成相距很远。# 滑窗特征按 15 分钟粒度96 点 1 天 df[power_lag_1d] df[power_ratio].shift(96) df[power_lag_3d_mean] df[power_ratio].shift(96).rolling(3).mean() df[power_lag_1h] df[power_ratio].shift(4) # 时间周期编码 df[hour_sin] np.sin(2 * np.pi * df.index.hour / 24) df[hour_cos] np.cos(2 * np.pi * df.index.hour / 24) df[month_sin] np.sin(2 * np.pi * df.index.month / 12) df[month_cos] np.cos(2 * np.pi * df.index.month / 12)参数上shift(96)对应 15 分钟粒度的 1 天如果你的数据是 5 分钟粒度就要改成 288。rolling(3)是三天均值不要用rolling(3).mean()后再 shift顺序反了会引入未来信息。这是竞赛里最常见的泄漏点之一验证集分数虚高往往就出在这里。4. 模型选型与训练LightGBM、LSTM 还是物理引导网络4.1 树模型仍然是基线首选但特征工程决定上限在光伏功率预测这个任务上LightGBM 和 XGBoost 至今仍是最稳的基线。原因很简单表格特征、样本量中等、非线性关系明确。我一般先用 LightGBM 跑一版看验证集 RMSE 和 MAE再决定要不要上深度学习。关键参数上num_leaves控制在 31 到 63learning_rate0.05min_data_in_leaf给 20 以上防止过拟合。早停轮数设 50监控验证集 RMSE。如果树模型已经能把晴天的 RMSE 压到装机容量的 3% 以内那深度学习带来的边际收益就很有限了。4.2 LSTM 与 TCN 的适用边界什么时候值得上深度学习深度学习在光伏预测里的优势场景是「多站点联合预测」和「分钟级超短期预测」。如果你只有单站点、15 分钟粒度、一年数据LSTM 大概率跑不过调好参的 LightGBM。但如果你有 10 个以上电站且希望模型共享气象模式那 TCN 或 Informer 这类结构就值得试。我一般用 PyTorch 搭一个两层 LSTM输入是过去 24 小时的 kt、温度、功率序列输出未来 24 小时功率。注意归一化要用训练集的均值和方差验证集和测试集只能 transform 不能 fit否则又是泄漏。4.3 物理引导的损失函数把晴空上限写进训练目标一个我反复用的小技巧在损失函数里加一项惩罚当预测功率超过晴空理论上限时加大惩罚。这样模型不会在阴天预测出晴天级别的出力。import torch import torch.nn as nn class PhysicalLoss(nn.Module): def __init__(self, alpha0.1): super().__init__() self.alpha alpha self.mse nn.MSELoss() def forward(self, pred, target, poa_clear): # 基础 MSE loss self.mse(pred, target) # 物理惩罚预测超过晴空上限的部分 excess torch.relu(pred - poa_clear) loss loss self.alpha * excess.mean() return lossalpha控制惩罚强度我一般从 0.1 开始试太大模型会变得保守阴天也预测偏低。poa_clear需要提前归一化到和功率同一量纲否则惩罚项尺度不对。这个损失函数在 KDD 杯这类赛题里能明显改善阴雨天的预测偏差因为纯 MSE 对少数极端样本不敏感。5. 避坑与排查光伏预测里那些让你白干一周的细节5.1 时区与夏令时时间戳对不上全盘皆输现象模型在验证集上表现正常但提交后分数暴跌。原因赛题给的时间戳是 UTC而你按本地时间算了太阳位置导致日出日落偏移 8 小时。解决拿到数据第一件事就是确认时区用pd.to_datetime后统一tz_localize到 UTC再tz_convert到站点本地时区。pvlib 的Location必须传本地时区否则太阳位置全错。5.2 数据泄漏滑窗特征里的未来信息现象交叉验证 RMSE 低得离谱线上却一塌糊涂。原因构造滑窗时先对整个数据集做了rolling再切分训练测试导致测试集用到了训练集未来的信息。解决先按时间切分再在训练集内部做滑窗测试集的滑窗只能用测试集之前的历史。我一般写一个make_lag_features函数传入已切分的数据确保不跨边界。5.3 装机容量变更同一列里混了两种量纲现象某段时间功率突然翻倍模型学出错误的日周期。原因电站扩容了但功率表没有标注前半年是 10MW后半年是 20MW。解决画全年功率时序图找阶跃点分段归一化。如果赛题没给容量用晴天正午功率的 95 分位数作为容量估计再人工核对。5.4 阴天样本太少模型学会「永远预测晴天」现象晴天预测很准阴天误差巨大。原因训练集里阴天样本占比低MSE 被晴天主导。解决对 kt 低于 0.4 的样本做加权或者用分位数损失替代 MSE。我一般给阴天样本 2 到 3 倍权重再配合前面说的物理惩罚项效果比较稳。5.5 第三方库版本冲突pvlib 与 pandas 的兼容坑现象get_clearsky报AttributeError或返回全 NaN。原因pvlib 0.9 和 pandas 2.0 存在不兼容或者times索引没有时区。解决锁定 pvlib 0.10 以上、pandas 1.5 到 2.0 之间并确保times是带时区的 DatetimeIndex。如果还是报错先跑官方文档里的最小示例确认环境没问题再排查自己的数据。6. 进阶技巧用第三方库做站点级校验与在线更新当你把模型跑通之后下一步值得投入的是「站点级校验」和「在线更新」。我一般会用 pvlib 的ModelChain做一次独立校验把组件参数、逆变器效率、温度系数填进去跑一遍物理模型和机器学习预测做对比。如果两者在晴天偏差小于 5%说明特征工程到位如果偏差大优先查辐照度转换和温度修正。在线更新方面光伏电站的季节性漂移很明显我习惯每月用最近 3 个月数据重新训练一次而不是全年数据一把梭。重训练时保留旧模型的验证集划分确保新模型在历史同期上不退化。校验项物理模型基准机器学习预期偏差处理晴天正午功率ModelChain 输出偏差 5%查温度系数阴天全天能量晴空指数加权偏差 15%查云量特征日出后 1 小时低辐照模型偏差 10%查低辐照响应夜间恒为零必须为零强制置零最后说一个我自己的习惯每次做完一版模型我都会把预测曲线和实际曲线叠在一起按月份各画一张图肉眼过一遍。那些 RMSE 指标看不出来的系统性偏差往往在图上一眼就能发现。风电光伏人工智能竞赛这条路拼的不是模型多花哨而是谁把物理细节抠得更细。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询