news 2026/9/28 5:09:45

基于LSTM的短期光伏预测Python源码与数据集实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于LSTM的短期光伏预测Python源码与数据集实战指南

简介:本资源为基于LSTM的短期光伏预测算法Python实现包,面向计算机、人工智能、通信工程、自动化等专业的在校学生、教师及企业技术人员,可用于毕业设计、课程设计、项目立项演示或算法进阶学习。包内共11个文件,以6个ipynb交互式笔记本为核心,配合1个py脚本、1个xlsx数据表、1个txt使用说明及png、jpg图示,压缩包约3.89MB,结构轻量便于快速上手。内容围绕园区光伏与负荷数据展开,涵盖单变量与多变量预测流程、规则集与储能框架探索、模拟程序及数据清洗脚本,可帮助读者理解LSTM在时间序列预测中的建模思路、特征构造与结果评估方法。已有248人学习下载,适合希望掌握短期光伏功率预测完整实现路径、并在此基础上修改扩展功能的读者参考。

1. 从一份 LSTM 光伏预测源码包说起:它到底能解决什么问题

光伏电站最头疼的不是发电,而是「发多少」说不准。云层飘过来三分钟,功率能从满载掉到三成,调度侧要备用容量,交易侧要报次日曲线,偏差一大就是真金白银的罚款。短期光伏预测要干的事,就是拿历史功率、辐照度、温度、风速这些时序数据,把未来 1 到 24 小时的出力曲线提前算出来。这份「基于 LSTM 的短期光伏预测算法 python 源码 + 数据集」压缩包,本质是一套能跑通的最小闭环:数据读取、归一化、滑窗构造、LSTM 建模、训练、评估、画图,一条龙。它适合两类人——刚入门时间序列预测、想找一个能跑通全流程的 python 项目练手的新手;以及手上真有电站数据、想快速验证 LSTM 到底比持久化模型强多少的运维或算法工程师。别指望它直接上线,但拿它当基线、当脚手架,性价比很高。

2. LSTM 做光伏预测的原理与选型:为什么不是 ARIMA 也不是 XGBoost

2.1 光伏功率序列的三个特性决定了模型选型

光伏功率序列有三个绕不开的特性。第一是强日周期性,晴天曲线几乎是标准正弦,早上爬坡、正午封顶、傍晚回落。第二是天气突变带来的非平稳性,一片云就能让功率在分钟级抖出 40% 的波动,这种突变没有明显的前兆规律。第三是多变量耦合,功率不只跟自身历史有关,还跟辐照度、组件温度、环境温度强相关。

传统 ARIMA 类模型假设序列线性、平稳,遇到云遮这种非线性突变基本抓瞎,差分阶数调半天也压不住误差。树模型如 XGBoost 对特征工程依赖极重,你得手工构造滞后项、滑动均值、辐照度交互项,特征没做好效果就上不去,而且它天然不擅长处理长序列的时序依赖。LSTM 的门控结构(遗忘门、输入门、输出门)恰好能选择性地记住「昨天同一时刻的功率水平」这种长周期信息,又能对短时突变做出响应,输入多变量也天然支持。这就是为什么短期光伏预测里 LSTM 及其变体(BiLSTM、CNN-LSTM、Attention-LSTM)是主流基线。

提示:LSTM 不是万能的。如果只有功率单变量、且预测步长只有 15 分钟,持久化模型(拿上一时刻值当预测)往往就很难打败,先跑通持久化基线再上 LSTM,才知道模型到底有没有价值。

2.2 从零把环境搭起来:python 与 pytorch 的版本选择

拿到源码包第一件事不是急着跑,而是把环境对齐。LSTM 实现主流用 PyTorch 或 TensorFlow/Keras,这份源码包大概率是 PyTorch 路线(pytorch lstm 源码是热搜高频词)。python 安装建议 3.9 到 3.11,太新的版本某些科学计算库轮子还没跟上,太老的又缺特性。用 conda 建独立环境,避免污染系统 python。

# 创建独立环境,python 版本锁在 3.10 conda create -n pv_lstm python=3.10 -y conda activate pv_lstm # 安装核心依赖,pytorch 按自己显卡的 CUDA 版本去官网选对应命令 # 这里给的是 CPU 版示例,有 GPU 的换成 cu118 对应命令 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install numpy pandas matplotlib scikit-learn openpyxl

这段命令的逻辑是:先隔离环境,再装框架和数据处理三件套。参数上,python=3.10是稳妥选择;--index-url指定 pytorch 官方源,避免装到不匹配的版本;openpyxl是为了读 Excel 格式的数据集,很多电站导出就是 xlsx。装完用python -c "import torch; print(torch.__version__)"验证,能打印版本号就说明环境通了。vscode python 环境配置的话,记得在右下角把解释器切到刚建的pv_lstm,否则跑起来还是系统 python,报「找不到 torch」的玄学错误多半出在这。

2.3 数据集长什么样:字段、粒度与清洗要点

光伏数据集通常包含时间戳、有功功率、辐照度、组件温度、环境温度、风速、风向这几列。粒度常见 15 分钟或 1 小时一条,一天 96 点或 24 点。拿到数据先做三件事:时间戳解析、缺失值处理、异常值剔除。

import pandas as pd import numpy as np # 读取数据,parse_dates 直接把时间列解析成 datetime df = pd.read_excel("pv_data.xlsx", parse_dates=["timestamp"]) df = df.sort_values("timestamp").reset_index(drop=True) # 缺失值:功率列用线性插值,气象列用前向填充 df["power"] = df["power"].interpolate(method="linear", limit=4) df["irradiance"] = df["irradiance"].ffill() # 异常值:夜间功率应为 0,出现负值或白天超装机容量的直接置 NaN 再插值 df.loc[df["power"] < 0, "power"] = np.nan df.loc[df["power"] > df["capacity"], "power"] = np.nan df["power"] = df["power"].interpolate(method="linear") # 加时间特征,小时和分钟能帮模型捕捉日周期 df["hour"] = df["timestamp"].dt.hour df["minute"] = df["timestamp"].dt.minute

逻辑说明:interpolate的limit=4表示连续缺失超过 4 个点就不插了,避免用假数据填出一大段;异常值先置 NaN 再插值,比直接删行保留更多样本。参数上,capacity是电站装机容量,得从数据说明里拿,没有就问现场。清洗完打印df.isna().sum()确认没有残留空值,否则后面归一化会报错。

3. 把 LSTM 模型跑起来:滑窗构造、网络定义与训练循环

3.1 滑窗构造:把时序问题变成监督学习问题

LSTM 吃的是序列,但训练时需要「输入序列 + 对应标签」的样本对。滑窗就是拿过去 N 个时刻的多变量特征,预测未来 M 个时刻的功率。N 是回看窗口,M 是预测步长。

from sklearn.preprocessing import MinMaxScaler features = ["power", "irradiance", "temperature", "hour"] data = df[features].values # 归一化,LSTM 对量纲敏感,不归一化收敛极慢 scaler = MinMaxScaler() data_scaled = scaler.fit_transform(data) def make_windows(data, lookback=24, horizon=4): X, y = [], [] for i in range(len(data) - lookback - horizon + 1): X.append(data[i:i + lookback]) # 过去 24 个点 y.append(data[i + lookback:i + lookback + horizon, 0]) # 未来 4 个点的功率 return np.array(X), np.array(y) X, y = make_windows(data_scaled, lookback=24, horizon=4) print(X.shape, y.shape) # (样本数, 24, 4) (样本数, 4)

逻辑说明:lookback=24对应 15 分钟粒度就是过去 6 小时,horizon=4是预测未来 1 小时。y只取第 0 列(功率),因为预测目标就是功率。参数怎么定:回看窗口太短抓不到日周期,太长引入噪声且训练慢,24 到 96 是常见区间;预测步长按业务需求,日前调度要 96 步,实时调度 4 步就够。注意归一化必须用训练集 fit,再 transform 测试集,否则数据泄漏,评估结果虚高,这是血泪经验。

3.2 LSTM 网络定义:层数、隐藏单元与 dropout 的取舍

网络结构不用堆太深,光伏预测这种任务两层 LSTM 足够,堆到四五层反而过拟合。

import torch import torch.nn as nn class PVLSTM(nn.Module): def __init__(self, input_size=4, hidden_size=64, num_layers=2, output_size=4): super().__init__() self.lstm = nn.LSTM( input_size=input_size, hidden_size=hidden_size, num_layers=num_layers, batch_first=True, dropout=0.2, # 两层以上才生效 ) self.fc = nn.Linear(hidden_size, output_size) def forward(self, x): out, _ = self.lstm(x) # out: (batch, seq, hidden) out = out[:, -1, :] # 取最后一个时间步 return self.fc(out) model = PVLSTM() print(sum(p.numel() for p in model.parameters()), "个参数")

逻辑说明:batch_first=True让输入维度是 (batch, seq, hidden),符合直觉;out[:, -1, :]取最后一个时间步的隐藏状态,因为它聚合了整段序列的信息;dropout=0.2是防过拟合的常规值,注意单层 LSTM 时 dropout 不生效。参数上,hidden_size=64是起点,数据量大可以加到 128,数据少就降到 32;num_layers=2够用,再深收益递减。参数量打印出来心里有数,几万到几十万级别都正常。

3.3 训练循环与早停:损失曲线怎么看

训练用 MSE 损失、Adam 优化器,加早停防止过拟合。

from torch.utils.data import TensorDataset, DataLoader X_t = torch.tensor(X, dtype=torch.float32) y_t = torch.tensor(y, dtype=torch.float32) loader = DataLoader(TensorDataset(X_t, y_t), batch_size=64, shuffle=True) model = PVLSTM() criterion = nn.MSELoss() optimizer = torch.optim.Adam(model.parameters(), lr=1e-3) best_loss, patience, wait = float("inf"), 10, 0 for epoch in range(200): model.train() for xb, yb in loader: optimizer.zero_grad() loss = criterion(model(xb), yb) loss.backward() optimizer.step() # 简单起见用训练损失做早停,正式项目应看验证集 if loss.item() < best_loss: best_loss, wait = loss.item(), 0 torch.save(model.state_dict(), "best_lstm.pt") else: wait += 1 if wait >= patience: print(f"早停于 epoch {epoch}") break if epoch % 20 == 0: print(f"epoch {epoch}, loss {loss.item():.6f}")

逻辑说明:batch_size=64是显存和收敛稳定性的折中;lr=1e-3是 Adam 的默认甜点值,loss 震荡就降到 5e-4;patience=10表示连续 10 轮没进步就停。看损失曲线:正常是快速下降后趋平,如果训练 loss 一直不降,检查归一化和学习率;如果训练 loss 降但验证 loss 涨,就是过拟合,加 dropout 或减层数。正式项目一定要切验证集,这里为了代码简洁用训练 loss 演示,别照搬到生产。

4. 评估与调参:MAPE、RMSE 怎么算,超参数怎么搜

4.1 反归一化与评估指标:别在归一化空间里算误差

预测出来的值还在 0 到 1 之间,必须反归一化回真实功率量纲再算误差,否则 MAPE 毫无意义。

from sklearn.metrics import mean_absolute_error, mean_squared_error model.eval() with torch.no_grad(): pred = model(X_t).numpy() # 反归一化:功率是第 0 列,用 scaler 的 min/max 还原 p_min, p_max = scaler.data_min_[0], scaler.data_max_[0] pred_real = pred * (p_max - p_min) + p_min y_real = y * (p_max - p_min) + p_min mae = mean_absolute_error(y_real.flatten(), pred_real.flatten()) rmse = np.sqrt(mean_squared_error(y_real.flatten(), pred_real.flatten())) # MAPE 要避开夜间 0 功率,否则除零爆炸 mask = y_real.flatten() > 0.05 * p_max mape = np.mean(np.abs((y_real.flatten()[mask] - pred_real.flatten()[mask]) / y_real.flatten()[mask])) * 100 print(f"MAE {mae:.2f}, RMSE {rmse:.2f}, MAPE {mape:.2f}%")

逻辑说明:反归一化用data_min_和data_max_,这是 MinMaxScaler 记录的训练集极值。MAPE 的坑在于夜间功率接近 0,分母极小导致百分比爆炸,所以用mask只统计功率大于装机 5% 的白天点。指标参考:短期光伏预测 MAPE 做到 10% 以内算不错,晴天能到 5%,阴雨天 15% 到 20% 也正常,别拿晴天指标去要求阴天。

4.2 超参数搜索:回看窗口、隐藏单元、学习率三件套

调参优先动这三个,其他先固定。

超参数常用范围影响调整建议
lookback16 / 24 / 48 / 96太短抓不到周期,太长噪声大从 24 起,按粒度换算成 6 到 24 小时
hidden_size32 / 64 / 128太小欠拟合,太大过拟合数据少于 1 万条用 32 到 64
learning_rate1e-3 / 5e-4 / 1e-4太大震荡,太小收敛慢从 1e-3 起,loss 震荡就减半
num_layers1 / 2 / 3深了易过拟合2 层起步,数据少用 1 层
dropout0.1 / 0.2 / 0.3防过拟合过拟合明显就加到 0.3

搜索策略上,网格搜索太慢,用随机搜索或 Optuna 贝叶斯优化,20 到 30 组就能找到不错的组合。别一上来就搜,先把默认参数跑通看基线,再针对性调。

4.3 对比基线:持久化模型和 LSTM 到底差多少

不上基线就不知道 LSTM 值不值。持久化模型最简单:拿当前时刻功率当未来所有时刻的预测。

# 持久化基线:用回看窗口最后一个点的功率,重复 horizon 次 persist = np.repeat(X[:, -1, 0:1], y.shape[1], axis=1) persist_real = persist * (p_max - p_min) + p_min persist_mape = np.mean(np.abs((y_real[mask] - persist_real.flatten()[mask]) / y_real.flatten()[mask])) * 100 print(f"持久化 MAPE {persist_mape:.2f}% vs LSTM MAPE {mape:.2f}%")

逻辑说明:X[:, -1, 0]取每个样本回看窗口最后一刻的功率,np.repeat复制成 horizon 长度。如果 LSTM 的 MAPE 只比持久化低一两个点,说明模型没学到东西,得回去查特征和结构;低五个点以上才算有价值。这个对比是判断项目成败的硬标准,别跳过。

5. 避坑与排查:光伏 LSTM 训练里最常见的五个翻车现场

5.1 损失不下降,一直卡在高位

现象:训练几十轮 loss 几乎不动,或者只在小数点后第三位晃。原因通常是归一化没做或做错,或者学习率太小。解决:确认所有输入特征都归一化到 0 到 1,检查scaler.fit是不是只在训练集上做的;学习率从 1e-3 试到 1e-2,还不行就换优化器。

5.2 预测曲线整体平移,形状对但数值偏

现象:预测曲线跟真实曲线形状很像,但整体高了一截或低了一截。原因是反归一化用错了极值,或者训练集和测试集分布差异大。解决:反归一化必须用训练集的data_min_和data_max_,不能用测试集的;如果测试集是不同季节的数据,考虑重新训练或加季节特征。

5.3 夜间预测出非零功率

现象:明明太阳落山了,模型还预测出几百瓦。原因是夜间样本在训练集里占比大且功率为 0,模型没学好这个边界,或者归一化后 0 值被映射到非零。解决:在特征里显式加「是否白天」的 0/1 标志,或者后处理时把夜间时段强制置 0。

5.4 验证集 loss 上升但训练 loss 下降

现象:典型的过拟合。原因是模型太复杂或数据太少。解决:减层数、减隐藏单元、加 dropout、加 L2 正则,或者做数据增强(对训练样本加小幅噪声)。数据少于 5000 条时,LSTM 很容易过拟合,考虑先用简单模型。

5.5 换了数据集就报维度错误

现象:RuntimeError: input size mismatch。原因是新数据集的列数和顺序跟源码里写死的input_size=4不一致。解决:把特征列名和顺序固定下来,input_size改成len(features),别硬编码。每次换数据先打印X.shape确认维度。

6. 让预测再准一点的三个进阶技巧

第一个技巧是加注意力机制。标准 LSTM 把整段序列压成一个隐藏状态,信息有损。在 LSTM 输出上加一层注意力,让模型自己决定回看窗口里哪些时刻更重要——比如突变前那几个点权重更高。实现上就是在out上过一个线性层算权重再加权求和,代码量不大,MAPE 通常能再降一到两个点。

第二个技巧是误差修正。LSTM 对晴天拟合很好,阴雨天误差大。可以训练一个副模型专门预测残差,或者按天气类型分模型训练。我一般会先按辐照度把样本分成晴、多云、阴三类,分别训 LSTM,推理时按预报天气选模型,阴天场景提升明显。

第三个技巧是滚动预测。别一次性预测未来 24 小时,而是预测 1 步、把预测值喂回输入、再预测下一步。这样能利用最新信息,但误差会累积,适合短期几步。实现时注意每次喂回的值要归一化,别把真实值混进去造成泄漏。

验证方法上,别只看一个测试集。用滚动窗口做交叉验证:前 70% 训练、接下来 15% 验证调参、最后 15% 测试,再整体前移重跑几次,看指标稳定性。指标波动大说明模型不稳,别急着上线。

我自己踩过最深的坑是拿测试集调参,调到最后指标漂亮得不像话,一上真实数据就崩。后来养成习惯:测试集只在最后碰一次,调参全在验证集上做。这个习惯比任何调参技巧都值钱。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 5:09:44

建一个网站大概需要多少钱? 5种方案对比评测避坑

建一个网站大概需要多少钱? 5种方案对比评测避坑 别再被那些99元一年的模板站忽悠了。那种千篇一律的UI,不仅丑得掉渣,更致命的是性能拉胯,客户一看就掉线,SEO根本做不起来。…

作者头像 李华
网站建设 2026/9/28 5:09:32

选那家网站建设公司好?3个免费工具实测避坑

选那家网站建设公司好?3个免费工具实测避坑 昨晚刚给一个客户做完安全审计,发现他们的官网后台被植入了挖矿脚本,首页还挂了暗链。客户急得团团转,问:“网站被黑挂马不知道怎么办?是不是得换服务器?”…

作者头像 李华
网站建设 2026/9/28 5:09:29

RK3568视频硬解+Qt融合实战:绕过GStreamer实现零拷贝OpenGL渲染

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 5:09:29

网站被黑挂马别慌:拆解做搬家服务网站问卷调查的目的与对比评测实战

网站被黑挂马别慌:拆解做搬家服务网站问卷调查的目的与对比评测实战 昨晚十一点,我的微信突然炸了。一个做同城搬家服务的客户急匆匆发来截图,他的官网首页被替换成了满屏的赌博广告,浏览器直接弹出“不安全”的警告。他问我:“网站被黑挂马不知道怎么办?我明明没改过代码,怎么一夜之间就变样了?”…

作者头像 李华
网站建设 2026/9/28 5:08:57

Win11下Keil MDK安装避坑指南:驱动签名、ARMCC V5与芯片支持包全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 5:08:47

一键装机安全吗?无U盘重装系统的隐藏风险与官方方案

很多人在重装系统这件事上&#xff0c;都有过类似的经历&#xff1a;电脑变慢了&#xff0c;弹窗变多了&#xff0c;系统卡得不行&#xff0c;于是决定自己动手。但一搜索“重装系统”&#xff0c;满屏都是“一键装机”“无U盘重装系统”“在线安装”这类工具。你点进去一看&am…

作者头像 李华