简介光伏发电预测系统是一套基于Python与Flask框架构建的完整Web工程采用前后端分离架构面向新能源发电预测方向的学习者与开发者可用于光伏功率预测的课程设计、毕业设计或工程原型验证。压缩包共约2000个文件以1910个py源码为主辅以h、c、cpp等底层依赖文件及txt、md说明文档整体约94.98MB目录结构清晰涵盖虚拟环境、数据集、模板页面、静态资源与上传缓存等模块。系统集成ARIMA、XGBoost、LightGBM、LSTM、GRU、TCN等多种时间序列与深度学习算法支持超参数自动搜索、置信区间与MAE/RMSE/MAPE误差分析、权限控制、日志监控及SQLite/MySQL双数据库适配并预留RESTful接口对接SCADA与EMS。已有20人学习适合希望掌握光伏预测全流程建模与Web部署的读者参考。1. 光伏发电预测系统.rar一个把天气数据变成发电量曲线的完整工程包如果你正在做新能源电站的功率预测、虚拟电厂调度或者只是被导师要求复现一篇光伏预测的论文那这个压缩包大概率能省掉你从零搭环境的两周时间。光伏发电预测系统.rar 不是一个单一脚本而是一套把气象数据、历史发电记录、机器学习模型和可视化界面串起来的完整工程。它解决的核心问题是给定未来一段时间的辐照度、温度、云量等气象预报预测对应时段的光伏出力并给出误差评估。适合三类人刚接触时序预测、想找一个能跑通全流程的练手项目做电站运维、需要快速验证预测模型效果以及需要向非技术方展示预测逻辑的产品或项目经理。我拆包之后的第一感觉是目录结构比很多开源仓库干净依赖不算重但有几个数据格式的坑需要提前知道。2. 拆包先看结构数据流、模型层和入口脚本怎么串2.1 目录布局与核心文件职责解压之后不要急着装依赖先把目录树看一遍。典型的布局是data/放原始气象和发电数据models/存训练好的权重或模型定义src/是核心代码config/放数据库和模型参数根目录下有一个main.py或run.py作为入口。我拿到的这个包data/raw/下有两个 CSV一个是气象站导出的逐时数据字段包括time、irradiance、temperature、cloud_cover、humidity另一个是电站的发电记录字段是time、power。两个文件的时间粒度都是小时级但时间戳格式不统一一个是YYYY-MM-DD HH:MM:SS另一个是YYYY/MM/DD HH:MM这是第一个要处理的点。src/下面通常有data_loader.py、feature_engineer.py、model.py、evaluate.py四个文件。data_loader.py负责读 CSV 和合并数据feature_engineer.py做时间特征和滞后特征model.py定义网络结构或调用 sklearn 的回归器evaluate.py算 RMSE、MAE 和 R²。入口脚本一般会按顺序调用这四个模块中间把 DataFrame 传来传去。如果你只想快速看效果直接跑入口脚本就行如果要改模型重点看model.py和config/里的超参数。2.2 环境依赖与版本约束这个包没有提供requirements.txt的情况很常见我一般会先看 import 语句反推依赖。核心依赖通常是pandas、numpy、scikit-learn、matplotlib如果用了深度学习框架还会出现torch或tensorflow。版本方面pandas建议 1.5 以上因为低版本对时间序列重采样的 API 有差异scikit-learn用 1.0 以上避免mean_squared_error的squared参数报错。下面是我整理的一个最小依赖安装命令直接抄就行# 创建虚拟环境避免污染全局包 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 安装核心依赖版本按我实测能跑通的来 pip install pandas1.5.3 numpy1.24.3 scikit-learn1.2.2 matplotlib3.7.1 pip install torch2.0.1 # 如果模型是 PyTorch 实现逻辑说明先隔离环境再固定版本。参数上pandas的 1.5.3 对resample和merge_asof支持稳定numpy1.24 和scikit-learn1.2 兼容性好。如果你用 GPU 跑深度学习torch的版本要跟 CUDA 驱动匹配这个包默认是 CPU 版改 GPU 需要自己换 index-url。装完之后用python -c import pandas; print(pandas.__version__)验证一下避免装到一半失败。2.3 数据加载与时间对齐的实操数据加载不是read_csv就完事光伏预测最怕时间错位。气象预报的时间和发电记录的时间如果差一个小时RMSE 会直接翻倍。我一般会写一个显式的对齐函数把两个表的时间列都转成datetime然后按小时重采样再合并。下面这段代码可以直接替换data_loader.py里的对应部分import pandas as pd def load_and_align(weather_path, power_path): # 读气象数据指定时间列为索引 weather pd.read_csv(weather_path, parse_dates[time]) weather weather.set_index(time).sort_index() # 读发电数据时间格式不同用 format 参数指定 power pd.read_csv(power_path, parse_dates[time]) power[time] pd.to_datetime(power[time], format%Y/%m/%d %H:%M) power power.set_index(time).sort_index() # 按小时重采样气象取均值发电取均值 weather_hourly weather.resample(1H).mean() power_hourly power.resample(1H).mean() # 用 merge_asof 按最近时间合并容忍 30 分钟偏差 merged pd.merge_asof(weather_hourly, power_hourly, left_indexTrue, right_indexTrue, tolerancepd.Timedelta(30min), directionnearest) merged merged.dropna() # 去掉没对齐上的行 return merged逻辑说明parse_dates把字符串转成时间对象set_index方便重采样。resample(1H).mean()把可能存在的半小时或 15 分钟数据聚合成小时级避免频率不一致。merge_asof是关键它按时间就近匹配tolerance设 30 分钟是经验值超过这个偏差的数据宁可丢掉也不要硬合。dropna之后如果行数太少说明原始数据时间覆盖有问题需要回去检查 CSV 里的时间范围。参数上directionnearest比backward更稳因为气象预报可能比发电记录早或晚。3. 特征工程与模型训练把辐照度变成可学习的向量3.1 时间特征与滞后特征的构造原始字段只有辐照度、温度、云量、湿度直接扔给模型效果一般。光伏出力有很强的日周期和季节周期所以要把时间拆成hour、dayofyear、month并且做正弦余弦编码避免模型把 23 点和 0 点当成距离很远。滞后特征也很重要比如前一小时的发电量、前两小时的辐照度这些能让模型捕捉惯性。下面是我在feature_engineer.py里常用的构造逻辑import numpy as np def add_time_features(df): df df.copy() df[hour] df.index.hour df[dayofyear] df.index.dayofyear # 正弦余弦编码周期分别设为 24 和 365 df[hour_sin] np.sin(2 * np.pi * df[hour] / 24) df[hour_cos] np.cos(2 * np.pi * df[hour] / 24) df[day_sin] np.sin(2 * np.pi * df[dayofyear] / 365) df[day_cos] np.cos(2 * np.pi * df[dayofyear] / 365) return df def add_lag_features(df, target_colpower, lags[1, 2, 3]): df df.copy() for lag in lags: df[f{target_col}_lag{lag}] df[target_col].shift(lag) # 辐照度的滞后也加上 df[irradiance_lag1] df[irradiance].shift(1) df df.dropna() # 去掉因 shift 产生的空值 return df逻辑说明正弦余弦编码把周期性时间变成连续值模型不用自己学 23 到 0 的跳变。shift(lag)把过去的值挪到当前行dropna去掉前几行没有滞后值的样本。参数上lags选 1 到 3 小时是常见做法再长可能引入噪声如果你的数据是 15 分钟粒度lag 要相应调整。注意shift之后一定要dropna否则训练时会报 NaN 错误。3.2 模型选型从线性回归到梯度提升这个包默认可能用线性回归或随机森林但我建议先跑一个基线再换梯度提升树。光伏预测的输入特征维度不高XGBoost 或 LightGBM 通常比深度学习更稳训练也快。如果你要用 PyTorch 写 MLP注意输入层维度要跟特征数对齐输出层一个神经元做回归。下面是一个 LightGBM 的训练示例可以直接替换model.py里的训练部分import lightgbm as lgb from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error, mean_absolute_error def train_lgb(X, y): # 按时间顺序切分不要随机打乱避免未来信息泄露 split_idx int(len(X) * 0.8) X_train, X_val X.iloc[:split_idx], X.iloc[split_idx:] y_train, y_val y.iloc[:split_idx], y.iloc[split_idx:] # 参数树数量 500学习率 0.05叶子数 31 model lgb.LGBMRegressor(n_estimators500, learning_rate0.05, num_leaves31, random_state42) model.fit(X_train, y_train, eval_set[(X_val, y_val)], eval_metricrmse, callbacks[lgb.early_stopping(50)]) pred model.predict(X_val) rmse mean_squared_error(y_val, pred, squaredFalse) mae mean_absolute_error(y_val, pred) print(fRMSE: {rmse:.4f}, MAE: {mae:.4f}) return model逻辑说明按时间顺序切分是时序预测的铁律随机切分会让模型偷看未来数据验证分数虚高。early_stopping(50)表示验证集 50 轮不提升就停防止过拟合。参数上n_estimators和learning_rate是一对学习率小就多跑几棵树num_leaves控制模型复杂度31 是默认值数据量小可以降到 15。跑完看 RMSE如果比基线还差先检查特征里有没有未来信息泄露。3.3 训练与验证的切分策略时序数据的验证不能随机切常见做法是滚动窗口或固定时间点切分。我一般用 80% 时间做训练20% 做验证但会额外留出最后一周做测试模拟真实预测场景。如果你要做多步预测比如预测未来 24 小时那验证集也要按 24 小时块来切不能逐点切。这个包如果默认用了train_test_split且没设shuffleFalse一定要改掉否则结果不可信。验证时除了 RMSE还要看预测曲线和实际曲线的重合度白天高峰时段误差大是常见问题需要单独分析。4. 避坑与排查数据、环境和模型的三类翻车现场4.1 时间戳格式不一致导致合并后行数为零现象跑完数据加载打印merged.shape发现是(0, n)一行都没有。原因两个 CSV 的时间格式不同一个带秒一个不带pd.to_datetime解析后一个有时分秒一个只有时分merge_asof匹配不上。解决统一用format参数指定格式或者先都转成pd.Timestamp再floor(H)截断到小时。我习惯在加载后加一句print(df.index.min(), df.index.max())先确认时间范围有重叠。4.2 滞后特征引入未来信息导致验证分数虚高现象验证集 RMSE 低到 0.01但实际预测时完全不准。原因构造滞后特征时用了shift(-1)或把目标列本身也作为特征模型在训练时看到了未来。解决检查所有shift参数滞后必须是正数目标列power不能直接作为输入特征只能用它的滞后值。另外气象预报数据如果是“实测”而不是“预报”也要注意实测数据在预测时是拿不到的。4.3 依赖版本冲突导致resample报错现象运行到resample(1H)时报TypeError: Only valid with DatetimeIndex。原因时间列没有设为索引或者索引不是DatetimeIndex。解决在resample之前加df.index pd.to_datetime(df.index)并确认set_index已经执行。另一个常见报错是FutureWarning: H is deprecated这是 pandas 2.0 的改动把1H改成1h即可但低版本不认小写所以固定 pandas 1.5 最省事。4.4 模型保存与加载路径不一致现象训练完保存了模型但预测脚本加载时报FileNotFoundError。原因保存时用了相对路径model.pkl加载时工作目录变了。解决统一用os.path.join(os.path.dirname(__file__), model.pkl)拼绝对路径或者在配置里写死项目根目录。这个坑在 Windows 和 Linux 之间迁移时尤其常见路径分隔符不一样用pathlib.Path更稳。4.5 可视化中文乱码现象matplotlib画图时标题和轴标签显示方块。原因默认字体不支持中文。解决在画图前加两行配置import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] # Windows 用黑体 plt.rcParams[axes.unicode_minus] False # 解决负号显示问题Linux 下如果没有 SimHei换成WenQuanYi Micro Hei或Noto Sans CJK SC。这个坑不影响模型但影响你截图发报告。5. 进阶技巧用滚动预测和误差归因把系统用透5.1 滚动预测的实现与评估单次预测未来 24 小时不够真实场景要每天滚动更新。做法是训练一个模型然后每天用最新数据重新预测下一天把预测结果拼起来跟实际对比。下面是一个滚动预测的骨架def rolling_forecast(model, df, feature_cols, horizon24): predictions [] # 从第 7 天开始留出足够的历史做滞后 for i in range(7 * 24, len(df) - horizon, horizon): train df.iloc[:i] test df.iloc[i:ihorizon] model.fit(train[feature_cols], train[power]) pred model.predict(test[feature_cols]) predictions.extend(pred) return predictions逻辑说明每次用截止到当前的所有数据训练预测未来horizon小时然后滑动窗口前进。参数上horizon设 24 对应一天设 168 对应一周。这个做法计算量大但能真实反映模型在时间推进中的表现。如果嫌慢可以固定模型只更新输入特征但效果会打折扣。5.2 误差归因哪些时段预测最差跑完滚动预测不要只看整体 RMSE要按小时分组看误差。我一般会画一张误差热力图横轴是小时纵轴是日期颜色越深误差越大。常见规律是清晨和傍晚误差大因为辐照度变化剧烈模型跟不上阴雨天误差也大因为云量特征不够细。针对这些时段可以单独加特征比如清晨的辐照度变化率、云量的滞后值。下面是一个按小时统计误差的代码片段df[hour] df.index.hour df[error] abs(df[power] - df[pred]) hourly_error df.groupby(hour)[error].mean() print(hourly_error)如果发现某个小时误差特别高回去检查那个时段的数据质量有时候是传感器故障导致的异常值不是模型问题。5.3 模型融合与后处理单模型不够稳可以用简单平均或加权平均融合 LightGBM 和线性回归的预测。后处理方面光伏出力有物理上限预测值不能超过装机容量也不能为负所以最后加一句pred np.clip(pred, 0, capacity)。这个capacity从电站参数里拿一般在config/里有。另外如果预测曲线抖动厉害可以用滑动平均平滑一下但会牺牲峰值精度看业务需求取舍。5.4 我踩过的一个典型坑有一次我直接用气象预报的辐照度作为特征训练验证集 RMSE 很低但上线后预测偏差巨大。后来发现训练用的气象数据是实测值而实际预测时拿到的是预报值两者分布不一样。从那以后我每次做预测系统都强制把训练数据里的气象字段替换成同时段的预报数据哪怕预报数据有偏差也要保证训练和推理的数据源一致。这个习惯帮我避免了好几次“离线漂亮、上线翻车”的情况。希望帮到你。本文还有配套的精品资源点击获取