ARTICLE DETAIL

资讯详情

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

LSTM短期光伏预测实战:Python源码与数据集全解析

LSTM短期光伏预测实战:Python源码与数据集全解析 简介一款基于长短期记忆网络的短期光伏预测毕业设计项目包含完整Python源码与光伏数据集面向计算机、人工智能、自动化等专业学生的毕设、课程设计或项目初期演示也适合机器学习初学者进阶。资源共402个文件压缩包大小12.46MB以Java、JavaScript和HTML文件为主并含SQL、配置与说明文档其中Java与前端文件用于配套管理或展示模块Python源码与数据集支撑核心预测流程。目前已有2668人学习下载。项目代码经测试运行成功功能稳定可直接部署使用包内附带详细说明文档与多种压缩格式的备份资料方便不同环境下的迁移与查阅。对于基础较好的学习者可基于此项目修改扩展实现自定义预测目标或界面优化。整体目录结构清晰便于按需检索与对照学习是兼顾教学演示与工程实践的完整参考。1. 用 LSTM 做短期光伏预测一套能直接跑的 Python 源码与数据集毕设课设都能用做光伏预测毕设的同学十个里有八个首选 LSTM但真正动手时卡住的往往不是模型本身而是数据。气象站给的原始数据带缺失、带异常天气类型是中文文本辐照度和功率的量纲差着好几个数量级——这些坑不处理干净后面跑出来的预测曲线就是一条平移版本的实测线导师一眼就能看出来是“抄作业”。这套基于 LSTM 的短期光伏预测项目源码正是冲着这个场景来的自带一份整理过的光伏数据集Python 脚本从数据清洗、特征构造到 LSTM 模型训练和结果可视化一条龙走完。它不是教学 demo是能从零跑到出图、出指标的完整工程适合做本科毕设、课程设计或者刚入门时序预测想找个真实数据集练手的人。重点是你拿到手不用再到处找数据集、拼代码。2. 数据先行光伏数据集的特点与预处理这一步决定了预测的天花板2.1 光伏数据大概长什么样有哪些坑光伏功率预测本质上是一个时间序列回归问题用过去一段时间的气象观测值和发电功率预测未来某个时刻的功率。但原始数据远没有教科书那么干净。这套源码里附带的数据集通常包含以下几列时间戳精确到分钟或小时、辐照度W/m²、环境温度、组件温度、湿度、风速、天气类型晴/多云/雨等中文文本以及实际发电功率kW。第一个坑是时间戳连续性。很多光伏电站的数据在夜间会整段缺失或者通讯故障导致某几天完全没有记录。直接用 df.dropna() 会把白天和夜晚的样本比例搞乱模型会偏向预测小功率值。正确的做法是先把时间列设为索引用 reindex 补全所有时间点缺失的辐照度按夜间为 0 的物理常识填充功率缺失再用插值。第二个坑是恶劣天气样本占比低。光伏预测模型在晴天表现好一到阴雨天就开始飘因为训练集里晴天样本太多了。处理手段不是强行过采样而是把天气类型转成监督信号——后面讲模型输入时你会看到这类离散特征该怎么进 LSTM。2.2 预处理步骤详解从原始 CSV 到模型能吃的张量数据预处理的代码一般会集中在一个脚本里把加载、清洗、特征工程、训练集划分都封装好。核心流程如下import pandas as pd import numpy as np # 读取原始数据 df pd.read_csv(pv_data.csv, parse_dates[timestamp], index_coltimestamp) # 1. 补全时间索引保证时间序列连续 full_idx pd.date_range(startdf.index.min(), enddf.index.max(), freq15min) df df.reindex(full_idx) # 2. 夜间辐照度按物理常识填 0 night_mask (df.index.hour 5) | (df.index.hour 19) df.loc[night_mask, irradiance] df.loc[night_mask, irradiance].fillna(0) # 3. 其余缺失值用线性插值 df[power] df[power].interpolate(methodlinear, limit_directionboth) # 4. 天气类型编码one-hot而不是映射成 0/1/2 weather_dummies pd.get_dummies(df[weather], prefixweather) df pd.concat([df, weather_dummies], axis1) df df.drop(weather, axis1)这段代码的逻辑说明第一步和第二步解决的是时间维度上的坏数据第三步用插值而不是直接删行是为了保住样本量因为 LSTM 对样本量很敏感第四步很多人会做“晴0, 多云1, 雨2”这种映射这是错的——LSTM 会认为 2 比 1 大晴天比多云“距离”更远但实际上天气类型没有大小关系one-hot 才能正确表达这种无序类别。参数说明采样频率15min不是随手写的。这套数据集的原始时间粒度大概率就是 15 分钟如果你手里的数据是小时级建议保持原样不要强行重采样成 15 分钟插值出来的中间点没有物理含义。2.3 滑动窗口构造LSTM 的输入到底长什么样LSTM 不能直接吃一整条时间序列它吃的是“窗口”。你的预测目标是未来 1 小时4 个 15 分钟点输入就是过去几小时的观测值。滑动窗口的大小直接影响模型效果,窗口太短学不到天气变化的趋势窗口太长则引入过多历史噪声。def create_sequences(data, input_steps16, output_steps4): X, y [], [] for i in range(len(data) - input_steps - output_steps 1): X.append(data.iloc[i:iinput_steps].values) y.append(data.iloc[iinput_steps:iinput_stepsoutput_steps][power].values) return np.array(X), np.array(y) # 只保留模型需要的特征列 feature_cols [irradiance, temperature, humidity, wind_speed] \ [c for c in df.columns if c.startswith(weather)] [power] X, y create_sequences(df[feature_cols])这里input_steps16对应过去 4 小时16 × 15minoutput_steps4对应未来 1 小时。为什么不是输入 24 个点输出 1 个点因为短期预测更看重“未来一小时内的功率变化曲线”用来做并网调度或者储能策略都有意义如果只预测未来一个点边际价值很低。注意代码里 y 取的是[power]单列但 X 里包含了 power 列——这是有意的因为光伏功率自身的历史值对短期预测有很强的自回归作用属于“用昨天的功率猜今天的功率”这在时间序列预测里是主流做法。我之前见过有人把功率列从特征里删掉结果预测曲线几乎不跟随真实值变化。3. 模型搭建与训练LSTM 的 PyTorch 实现输入尺寸和损失函数一个都不能错3.1 网络结构两层 LSTM 加全连接隐藏层大小怎么定这套资源用的是 PyTorch 实现不是 Keras。两者差别不大但 PyTorch 的显式 tensor 操作更适合你后续做模型改进——比如加注意力机制、换双向 LSTM。一个典型的短期预测网络结构长这样import torch import torch.nn as nn class LSTMPredictor(nn.Module): def __init__(self, input_size, hidden_size64, num_layers2, output_steps4): super(LSTMPredictor, self).__init__() self.lstm nn.LSTM( input_sizeinput_size, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue, dropout0.2 ) self.fc nn.Linear(hidden_size, output_steps) def forward(self, x): # x shape: (batch, seq_len, input_size) out, _ self.lstm(x) # out: (batch, seq_len, hidden_size) out out[:, -1, :] # 取最后一个时间步的输出 out self.fc(out) return out代码说明batch_firstTrue让输入张量的第一维是 batch符合直觉out[:, -1, :]表示不管前面 15 个时间步的隐状态只拿最后一个作为全连接层的输入——这是时序预测的标准做法。至于为什么不是nn.LSTM的返回的(hidden, cell)因为没有必要最后一个隐状态已经编码了整段窗口的信息。参数参考hidden_size64、num_layers2是这套数据集的合理起点。数据量在几万条级别时64 维隐状态足够如果你发现验证集损失后期震荡得厉害可以降到 32。层数 2 是性价比最高的再加一层收益很小但训练时间明显变长。3.2 数据划分前 80% 训练、后 20% 验证严禁随机打乱时间序列划分和图像分类有个本质区别不能 shuffle。你拿 7 月份的数据训练拿 3 月份的数据验证模型没学过 7 月的天气规律验证结果一定难看。正确做法是按时间顺序切分而且最好预留一段连续时间作为最终测试集。train_ratio 0.8 split_idx int(len(X) * train_ratio) train_X, train_y X[:split_idx], y[:split_idx] val_X, val_y X[split_idx:], y[split_idx:] # 转成 PyTorch tensor并构造 DataLoader from torch.utils.data import TensorDataset, DataLoader train_dataset TensorDataset( torch.tensor(train_X, dtypetorch.float32), torch.tensor(train_y, dtypetorch.float32) ) train_loader DataLoader(train_dataset, batch_size64, shuffleTrue)注意对窗口样本而言shuffleTrue 是安全的因为每个窗口内部的时间顺序已经固定打乱的是“哪个窗口先看”的顺序不会破坏序列内部的因果关系。batch_size64结合数据量规模如果显存吃紧改成 32。3.3 训练循环Adam 优化器、MSELoss 损失函数与学习率策略光伏功率预测属于回归任务损失函数选MSELoss均方误差。你说为什么不是 MAE因为 MSE 对大幅偏差的惩罚更重而光伏预测最怕的是夏季午间那种“骤降”场景——云层飘过导致功率在几分钟内从满发掉到 20%MSE 能让模型更早学会捕捉剧烈波动。model LSTMPredictor(input_sizetrain_X.shape[2]) optimizer torch.optim.Adam(model.parameters(), lr1e-3) criterion nn.MSELoss() epochs 50 for epoch in range(epochs): model.train() total_loss 0 for batch_X, batch_y in train_loader: optimizer.zero_grad() pred model(batch_X) loss criterion(pred, batch_y) loss.backward() optimizer.step() total_loss loss.item() print(fEpoch {epoch1}/{epochs}, Loss: {total_loss/len(train_loader):.4f})lr1e-3是默认参数不一定是最优。这套数据集的量纲跨度大辐照度 0~1000功率 0~2000我建议第一个 epoch 之后看一眼 loss 是不是 nan如果是调低学习率到 5e-4再做一次特征标准化。另外训练完成后一定要保存参数torch.save(model.state_dict(), lstm_pv_model.pt)下次直接用model.load_state_dict(torch.load(lstm_pv_model.pt))恢复模型不用重训。这在毕设答辩现场很实用——你不需要给老师演示训练过程直接加载参数做预测出图。4. 评估与可视化RMSE 计算、预测曲线绘制以及如何从图上看出模型有没有“作弊”4.1 评价指标RMSE、MAE 之外的第二个隐藏指标大多数毕设论文里都会放 RMSE 和 MAE但光伏预测领域还有一个指标被高频使用R²决定系数它衡量的是模型对功率波动方差的解释能力。R² 低于 0.9 的晴天预测结果一般过不了答辩。评估代码from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score model.eval() with torch.no_grad(): pred model(torch.tensor(val_X, dtypetorch.float32)).numpy() # 展平后计算指标 true_flat val_y.reshape(-1) pred_flat pred.reshape(-1) rmse mean_squared_error(true_flat, pred_flat) ** 0.5 mae mean_absolute_error(true_flat, pred_flat) r2 r2_score(true_flat, pred_flat) print(fRMSE: {rmse:.2f} kW, MAE: {mae:.2f} kW, R²: {r2:.4f})需要说明的是这几个指标是全时段计算的包含了夜间功率为 0 的大量样本。夜间样本把 RMSE 拉低了看起来很好看。要区分模型真实水平应当单独统计白天辐照度 50W/m²时段的指标。你可以加一行 filter 条件把夜间样本剔掉再算一次。4.2 画图预测曲线和实测曲线叠在一起看“滞后性”最明显可视化代码一般会画三张图训练集拟合曲线、验证集对比曲线、误差分布直方图。对短期预测来说最有信息量的是验证集连续一段时间的对比import matplotlib.pyplot as plt # 选取验证集中某连续 3 天的数据可视化 show_steps 288 # 3天 × 96个15分钟点 plt.figure(figsize(12, 5)) plt.plot(true_flat[:show_steps], labelActual Power, alpha0.7) plt.plot(pred_flat[:show_steps], labelPredicted Power, alpha0.7) plt.xlabel(Time Steps (15 min)) plt.ylabel(Power (kW)) plt.legend() plt.title(LSTM Short-term PV Power Forecasting) plt.grid(alpha0.3) plt.savefig(forecast_result.png, dpi150) plt.show()看这张图有个技巧如果预测曲线比实测曲线晚了一个采样点说明模型学的是“把上一个时刻的值搬过来”也就是自回归主导了预测没有真正学习辐照度的变化。具体表现是实测功率上升的拐点预测曲线晚了 15 到 30 分钟才跟上。这时候回查两个地方——输入特征里辐照度的权重是否占主导可以打印模型第一层权重看以及滑动窗口是不是太短导致模型没有足够的历史信息推断趋势。4.3 超参数调优方向窗口长度、隐藏层大小、学习率衰减窗口长度 16 是默认值但不一定最优。你可以在 8 / 16 / 24 / 32 之间做简单网格搜索只看验证集的 RMSE。这个资源里没有自动调参脚本但手动调也不麻烦。隐藏层大小同理。还有一个容易忽略的因素学习率衰减。scheduler torch.optim.lr_scheduler.StepLR(optimizer, step_size15, gamma0.5)每 15 个 epoch 把学习率乘 0.5让模型在后期以更小步长收敛。很多人的 loss 在 30 个 epoch 后就进入平台期不再下降加了衰减后往往还能再降一截。这也是我拿到任何新时序数据集后的默认操作。5. 避坑指南光伏预测里最常见的六个错误我拿这套代码逐一踩过5.1 训练集和验证集没有按时间切分指标虚高导致答辩翻车现象验证集 RMSE 只有个位数你觉得模型很完美。答辩老师随机指定某段历史数据让你现场预测结果曲线完全走形。 原因写代码时图省事用了sklearn.model_selection.train_test_split默认的 random_state 随机打乱了样本。时间序列被打乱后模型等于“偷看”了未来的数据。 解决严格按索引顺序划分而且最好让训练集包含一整年的数据验证集取其后 60 天。5.2 夜间样本权重过大指标好看但白天一塌糊涂现象R² 高达 0.95但单独看白天时段的预测误差到了不可用的程度。 原因夜间功率全天为 0这类样本太好预测了模型犯错的空间很小。全时段 MSE 被大量零值样本拉低。 解决评估时按辐照度过滤白天样本再算一次指标。如果白天 R² 低于 0.85你真正要做的是在训练时给白天样本更高权重或者干脆训练时随机丢弃部分夜间样本。5.3 天气类型做了数值化编码而不是 one-hot现象晴天和雨天预测结果还行多云和阴天完全不对预测功率普遍偏高或偏低。 原因把天气映射成 0/1/2/3LSTM 学到了“数值越大天气越差”这种隐含关系但实际天气类型没有这种单调性。 解决用pd.get_dummies做 one-hot。如果你手里的数据集没有天气字段只有辐照度和功率也可以不加这个特征但效果上限会低一些。5.4 直接 dropna 处理缺失值把白天数据也删了现象训练集规模和原始 CSV 差了一大截模型预测晴天的非满发状态比如上午 10 点时误差变大。 原因夜间数据缺失很常见把含 NaN 的行整行删除后白天样本也被误删了。更麻烦的是时间序列被断开后窗口跨越断层处的样本会异常。 解决先按物理常识填充夜间辐照度为 0再对功率列做插值。插值方法linear就够不要用polynomial高阶插值它会在突变段制造震荡。5.5 预测长度选错了用了未来一天导致结果飘现象预测未来 24 小时前 6 小时还行后面越来越平最后变成一条直线。 原因LSTM 的单步预测误差会随步长累积这是时序模型固有问题。直接输出 96 个未来点24 小时 × 15min不等价于“预测能力强”只等价于“重复 96 遍单步预测”。 解决这套资源定位是短期预测1~3 小时内短输出的 RMSE 明显更好。如果导师要求做“超短期预测”未来 0~4 小时把output_steps改成 4 到 8 之间最合理。5.6 训练完没有保存模型参数每次跑一遍预测都要重训现象你改了某个参数重新训练结果预测效果比上一次差想回退但是模型已经没存。 原因没有torch.save。 解决每个实验保存一批参数文件名带超参数标记比如lstm_win16_h64_lr1e-3.pt。这样调参翻车时能快速回滚。6. 进阶玩法把 LSTM 升级成双向结构加注意力机制以及一套可复用的验证习惯这套资源给你的 LSTM 基线跑通之后如果你还想在论文里加点创新点有两个成本较低的升级方向。第一个是双向 LSTM。光伏功率预测虽然本质上是“用过去预测未来”但双向结构在训练阶段可以同时看到窗口内前后方向的信息对捕捉辐照度的突变拐点有帮助。实现上只需要把nn.LSTM改成nn.LSTM(bidirectionalTrue)然后把out[:, -1, :]改成out[:, -1, :hidden_size] out[:, 0, hidden_size:]——前向最后一个时间步的隐状态加后向第一个时间步的隐状态拼起来喂给全连接层。这样模型参数量翻倍训练时间大概增加 60%但 R² 通常能提升 0.02 到 0.04。第二个是加注意力机制。标准 LSTM 只取最后一个时间步的输出相当于默认“最后时刻的信息最重要”。但光伏预测里最重要的时刻往往不是窗口的末尾——比如早上 9 点预测接下来的功率变化决定性的信号可能是 8:40 之后辐照度的上升趋势。注意力机制能对不同时间步分配权重class AttentionLSTM(nn.Module): def __init__(self, input_size, hidden_size64, num_layers2, output_steps4): super(AttentionLSTM, self).__init__() self.lstm nn.LSTM(input_size, hidden_size, num_layers, batch_firstTrue) self.attn nn.Linear(hidden_size, 1) self.fc nn.Linear(hidden_size, output_steps) def forward(self, x): out, _ self.lstm(x) # (batch, seq_len, hidden) attn_weights torch.softmax(self.attn(out), dim1) context torch.sum(attn_weights * out, dim1) return self.fc(context)注意这里attn_weights输出后做了一个softmax确保权重和为 1。修改后你会发现模型对“辐照度由升转降”的拐点更敏感代价是训练时 loss 收敛速度减慢需要多跑十几轮。最后说验证习惯。从那以后我每次拿到光伏数据都会强制走一遍白昼切片验证法——先把时间序列按“日出-日落”切成每天一段分别计算每天的 RMSE再把 60 天的日误差取中位数作为最终报告指标。这样做的好处很明显单独一天的偶然偏差不会影响整体判断而且你能直观看出来模型是不是在阴雨天集体失效。如果 60 天里有 10 天以上的日误差超过晴天均值的两倍那说明模型对天气突变根本无感之前全时段 RMSE 的低值不过是被晴天样本平均掉了。这套方法同样适用于你拿到的任何时间序列预测项目。希望帮到你。本文还有配套的精品资源点击获取
返回列表