ARTICLE DETAIL

资讯详情

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

Python机器学习光伏功率预测:时序数据切分与特征工程实战

Python机器学习光伏功率预测:时序数据切分与特征工程实战 简介这是一套面向计算机相关专业学生与项目实战学习者的光伏功率预测完整项目基于Python与机器学习实现可作为毕业设计、课程设计或期末大作业的高分参考方案。资源包共16个文件约4.64MB包含8个csv训练与测试数据集、4个py核心脚本、1个ipynb实验笔记、1个md说明文档及1个docx任务说明覆盖数据加载、数据处理、模型训练与预测全流程目录结构清晰便于按模块理解与复现。项目经导师指导并认可评审分99分代码完整可运行对新手友好。已有56人学习下载。读者可从中获得一套可直接运行的预测方案、配套训练与测试数据、分步实验笔记以及数据预处理与模型调参的排错思路适合希望快速上手机器学习实战或需要完整项目案例支撑论文与答辩的学习者。1. 光伏功率预测为什么总在下午三点翻车做过光伏电站运维的人大多有过类似经历早上模型预测曲线和实际出力贴合得不错中午开始飘到了下午三点前后直接跑偏晚高峰前又莫名其妙拉回来。这不是模型“玄学”而是光伏功率预测这件事本身对特征工程和时序切分极其敏感。Python 基于机器学习的光伏功率预测核心就是用历史辐照、温度、组件出力等数据训练一个能映射气象条件到发电功率的模型再拿它去预测未来 15 分钟到 4 小时的出力。它解决的是电站并网调度、储能充放电策略、功率考核罚款这三个真金白银的问题适合有 Python 基础、手头有逆变器和气象站历史数据的运维或算法同学。标题里说的“源码训练数据测试数据”落地时最关键的不是模型多深而是数据怎么切、特征怎么造、评估怎么防泄漏。2. 光伏功率预测的数据集怎么切才不泄漏未来2.1 训练数据、测试数据不是随机分是按时间分很多人拿到一份光伏出力 CSV第一反应是train_test_split(random_state42)这是最典型的翻车起点。光伏数据是强时序数据随机切分会让测试集里的某一天和训练集里的相邻时刻混在一起模型相当于“偷看”了未来评估指标好看得离谱上线就崩。常见做法是按时间顺序切前 70% 做训练中间 15% 做验证最后 15% 做测试且三段之间留出至少一天的 gap避免边界泄漏。import pandas as pd # df 至少包含 timestamp, irradiance, temp, power 四列 df pd.read_csv(pv_data.csv, parse_dates[timestamp]) df df.sort_values(timestamp).reset_index(dropTrue) n len(df) train_end int(n * 0.70) val_end int(n * 0.85) train df.iloc[:train_end].copy() val df.iloc[train_end:val_end].copy() test df.iloc[val_end:].copy() # 打印三段的时间范围确认没有重叠 for name, part in [(train, train), (val, val), (test, test)]: print(name, part[timestamp].min(), part[timestamp].max())这段代码的逻辑是先按时间排序再按比例硬切最后打印每段的时间范围做人工确认。参数上70/15/15 是光伏预测里比较稳的默认值如果数据只有几个月可以把验证集比例压到 10%但测试集不要低于 10%否则评估方差太大。注意parse_dates必须加否则 timestamp 是字符串排序会按字典序10 月会排在 2 月前面。2.2 特征工程把辐照和温度变成模型能吃的滞后项光伏功率和辐照度几乎是线性关系但直接拿当前时刻的辐照去预测当前时刻的功率没有意义因为预测时你拿不到未来的辐照。真正能用的是历史滞后特征和气象预报特征。我一般会造这几类功率的 lag_1、lag_2、lag_4、lag_9615 分钟粒度下 96 个点是一天辐照的 lag_1 和 lag_4温度的 lag_1再加上小时、分钟、是否周末这类时间特征。def add_lag_features(data, cols, lags): for col in cols: for lag in lags: data[f{col}_lag{lag}] data[col].shift(lag) return data lag_cols [power, irradiance, temp] df add_lag_features(df, lag_cols, lags[1, 2, 4, 96]) # 时间特征 df[hour] df[timestamp].dt.hour df[minute] df[timestamp].dt.minute df[is_weekend] df[timestamp].dt.dayofweek.isin([5, 6]).astype(int) # 造完 lag 后前 96 行会有 NaN直接丢掉 df df.dropna().reset_index(dropTrue)逻辑说明shift(lag)把过去第 lag 个时刻的值挪到当前行lag_96 捕捉“昨天同一时刻”的日周期。参数上lag 列表不是越多越好光伏功率的自相关在 4 小时16 个点之后衰减很快lag_96 主要是给模型一个日周期的锚点。丢 NaN 这一步不能省否则后面 sklearn 会直接报错。注意is_weekend对光伏本身影响不大但对“周末是否有人工清洗组件”这类隐性规律有间接作用留着成本很低。2.3 训练数据和测试数据的分布对齐训练集和测试集如果季节不同模型会严重偏。比如用夏天数据训练、冬天数据测试辐照峰值差一倍模型直接失效。落地时要么保证训练集覆盖至少一整年要么在特征里加入“日序数”让模型自己学季节偏移。我一般会加一个day_of_year特征并检查训练集和测试集的功率均值差异超过 20% 就要警惕。df[day_of_year] df[timestamp].dt.dayofyear print(train power mean:, train[power].mean()) print(test power mean:, test[power].mean())如果差异过大常见做法是做分季节建模或者用滑动窗口重新切分让训练集和测试集覆盖相近的月份。这一步没有代码能自动救必须人工看一眼。3. 用 Python 机器学习模型跑通光伏功率预测的最小闭环3.1 选 LightGBM 而不是 LSTM 的理由光伏功率预测的公开研究和工程实践里梯度提升树LightGBM、XGBoost在中小规模数据上经常打得过 LSTM。原因很实际光伏特征里大量是滞后项和表格型气象数据树模型对这类特征的捕捉效率高训练快调参少还不容易过拟合。LSTM 需要更长的序列和更多数据才能体现优势而且调参成本高。标题里说“高分项目”如果数据量在几万到几十万行LightGBM 是性价比最高的选择。import lightgbm as lgb from sklearn.metrics import mean_absolute_error, mean_squared_error import numpy as np feature_cols [c for c in df.columns if c not in [timestamp, power]] X_train, y_train train[feature_cols], train[power] X_val, y_val val[feature_cols], val[power] X_test, y_test test[feature_cols], test[power] model lgb.LGBMRegressor( n_estimators800, learning_rate0.05, num_leaves63, min_child_samples20, subsample0.8, colsample_bytree0.8, random_state42 ) model.fit( X_train, y_train, eval_set[(X_val, y_val)], eval_metricmae, callbacks[lgb.early_stopping(50)] ) pred model.predict(X_test) mae mean_absolute_error(y_test, pred) rmse np.sqrt(mean_squared_error(y_test, pred)) print(fMAE{mae:.3f}, RMSE{rmse:.3f})逻辑说明early_stopping(50)表示验证集 MAE 连续 50 轮不下降就停防止过拟合。参数上num_leaves63是中等复杂度数据量小于 5 万行可以降到 31learning_rate0.05配合 800 棵树是比较稳的组合想更快收敛可以提到 0.1但容易震荡。subsample和colsample_bytree都设 0.8 是常规防过拟合手段。评估指标用 MAE 而不是 MSE因为光伏考核通常看平均偏差MAE 更贴近业务。3.2 归一化与反归一化别在树模型上画蛇添足树模型不需要归一化这是常识但很多人从 LSTM 教程里抄来 MinMaxScaler把特征缩到 0-1 再喂给 LightGBM结果模型性能没提升反而因为 scaler 在训练集上 fit、在测试集上 transform 引入了额外的数据依赖。如果一定要用神经网络做对比实验归一化必须只在训练集上 fit然后 transform 验证集和测试集。from sklearn.preprocessing import MinMaxScaler scaler MinMaxScaler() # 只在训练集上 fit scaler.fit(X_train) X_train_scaled scaler.transform(X_train) X_val_scaled scaler.transform(X_val) X_test_scaled scaler.transform(X_test)注意fit只能碰训练集这是防泄漏的铁律。树模型流程里我一般直接跳过这一步省事且不出错。3.3 预测结果的后处理把负功率砍掉光伏功率物理上不可能为负但模型在夜间或低辐照时可能输出负值。直接提交负值会被业务方当成 bug。常见做法是pred np.clip(pred, 0, None)把负值截断到 0。如果电站有额定容量还可以加上限np.clip(pred, 0, capacity)。capacity df[power].max() # 用历史最大出力近似额定容量 pred np.clip(pred, 0, capacity)这一步看起来简单但在实际考核里能救回不少分数。注意 capacity 不要用测试集的最大值要用训练集或已知的装机容量否则又是泄漏。4. 光伏功率预测的避坑与排查清单4.1 现象验证集 MAE 很低测试集 MAE 翻三倍原因训练集和测试集时间分布不一致或者随机切分导致泄漏。解决按时间切分检查两段的功率均值和辐照均值差异必要时做分季节建模或滑动窗口重切。4.2 现象模型在中午出力峰值处系统性偏低原因训练数据里峰值样本少树模型对极端值不敏感。解决对峰值样本做加权或者用objectiveregression_l1替代默认的 L2L1 对极端值更鲁棒。也可以单独训练一个峰值时段的模型。4.3 现象lag 特征造完后数据量骤减原因lag_96 会让前 96 行变成 NaN如果数据本身只有几天丢完就没剩多少。解决确认数据至少覆盖两周以上如果数据短把 lag_96 换成 lag_48 或去掉优先保数据量。4.4 现象预测曲线整体平移形状对但时间对不上原因时间戳时区或对齐问题常见于逆变器数据和气象站数据来自不同系统。解决统一转成同一时区检查两套数据的采样间隔是否一致必要时做重采样对齐。4.5 现象LightGBM 训练报错 “Input contains NaN”原因lag 特征或时间特征里还有缺失值dropna没覆盖到。解决在 fit 之前加assert not X_train.isnull().any().any()定位到具体列再处理。常见漏网之鱼是气象数据里的辐照缺失需要插值或前向填充。5. 把光伏功率预测从 demo 推到可用的三个进阶技巧5.1 用滑动窗口做在线更新电站数据是每天新增的模型不能一训永逸。我一般会保留最近 30 天的数据做增量训练或者每周用全部历史重新训一次。滑动窗口的代码不复杂关键是维护一个滚动的时间边界。def rolling_train(df, window_days30, model_paramsNone): end df[timestamp].max() start end - pd.Timedelta(dayswindow_days) recent df[df[timestamp] start] X recent[feature_cols] y recent[power] model lgb.LGBMRegressor(**(model_params or {})) model.fit(X, y) return model参数上window_days 取 30 是经验值夏天可以短一点冬天建议长一点因为冬季出力低、噪声占比大。注意这个函数没有验证集适合已经调好参后的在线更新不适合首次选型。5.2 用预测区间代替单点预测业务方越来越不满足于一个数他们想知道“明天下午三点出力大概率在 3MW 到 4MW 之间”。LightGBM 可以通过分位数回归给出区间。lower lgb.LGBMRegressor(objectivequantile, alpha0.1) upper lgb.LGBMRegressor(objectivequantile, alpha0.9) lower.fit(X_train, y_train) upper.fit(X_train, y_train) pred_lower lower.predict(X_test) pred_upper upper.predict(X_test)alpha0.1和0.9给出 80% 预测区间。注意分位数模型训练比普通回归慢且区间宽度需要人工检查是否合理太宽没有参考价值。5.3 特征重要性排查别让模型学错东西训练完一定要看model.feature_importances_如果day_of_year或hour排在最前面而irradiance_lag1排在后面说明模型可能在靠时间“背答案”而不是学物理关系。这种情况在训练集和测试集季节重叠时特别危险。importance pd.Series(model.feature_importances_, indexfeature_cols) print(importance.sort_values(ascendingFalse).head(15))我自己的习惯是每次训练完先看这 15 个特征如果 lag 特征没进前五就会回头检查数据对齐和切分。这个动作花不了一分钟但能挡住大部分“指标好看、上线翻车”的情况。希望帮到你。本文还有配套的精品资源点击获取
返回列表