简介精准的电力负荷预测能够优化发电计划、减少能源浪费这组资料聚焦基于机器学习、特别是反向传播神经网络的负荷预测方法研究面向电力系统相关专业学生、研究人员及对智能预测感兴趣的开发者既可支撑课程设计也可作为科研入门的参考。压缩包内共计334个文件其中329个为Excel格式数据文件包含历史负荷、天气、节假日等影响因子另有3个Matlab脚本负责数据读取、模型训练和结果可视化1个Markdown说明文档梳理研究思路包体仅5.32MB当前已有2460人学习下载热度较高。学习这份资料可系统理解从原始数据清洗、特征选择、网络拓扑构建到梯度下降反向传播的完整流程。真实可跑的数据与脚本让读者能直接上手复现关键实验并通过替换或扩充数据进一步验证模型为后续改进预测精度或探索深度学习打下基础。1. 电力负荷预测为什么机器学习方案值得认真做电力负荷预测是电网调度、需求响应、现货交易和配电规划共同依赖的底层能力预测偏差直接决定经济性和安全性。做负荷预测时很多团队上来就套深度学习模型结果发现效果并不比简单模型好原因往往是数据边界没理清、特征构造粗糙甚至训练集和测试集泄漏了未来信息。机器学习的价值在于它能把温度、日历、历史负荷这些信息揉进同一个模型里自动找到那些人工经验很难总结的规律。我这里分享的是一条可以直接落地的技术路线覆盖任务定义、数据清洗、特征工程、模型选型、滚动预测和上线避坑适合正在做能源数据分析或负荷预测项目的开发者也适合准备把预测能力接入调度系统的团队。目标是让你按这份笔记走一遍能稳定跑出一个可用的预测模型。2. 数据准备与特征工程先把预测的天花板抬起来数据质量决定了模型效果的上限模型算法只是尽量逼近这个上限。负荷预测尤其如此因为负荷序列有强周期、强温度相关性和明显的日历效应。这一章从任务定义开始把数据清洗和特征构造的每一步都拆开说明这些工作做完后面的模型选型才有意义。2.1 定义预测任务粒度、步长与目标变量做负荷预测之前有三个问题必须想清楚预测粒度、预测步长、目标变量。它们直接影响后面所有特征和模型的选择。第一个问题是粒度。负荷数据常见的有15分钟级、小时级、日级。电网调度通常需要小时级或15分钟级的短期预测用于机组组合和备用安排设备检修和规划类业务只需要日级或周级预测。粒度不同可用的特征完全不同15分钟级数据能利用最近一个时点的负荷特征小时级数据则要更多依赖日周期和温度变化。第二个问题是步长。要预测未来1小时还是未来24小时单步预测只要搭建一个回归模型就能跑多步预测则要面对误差累积或者为每个步长单独建模型。我一般会先做一个预测未来1小时的单步模型把特征、验证流程跑通再扩展成24步。这样容易定位问题出在模型还是出在多步策略上。第三个问题是目标变量。大多数场景直接预测原始负荷单位是MW或kW。有些团队喜欢对负荷做差分预测增量的好处是能去掉趋势但还原回原始负荷时会累积误差反而不如直接预测稳定。如果数据有明显的长期增长趋势更推荐把原始负荷做归一化或去趋势后再预测但归一化要在训练集上拟合不能把验证集数据也放进来算。另外时间戳必须统一。不同系统导出的数据有的带时区偏移有的用本地时间如果不处理后面构造“前一天同一时刻”这类特征时会错位几个小时这种问题很难排查。我通常先把时间列解析成标准UTC时间再转回业务时区保证所有特征在同一套时间体系下。2.2 数据清洗缺失值、异常值与节假日冲击电力负荷数据通常来自SCADA或电表采集系统质量参差不齐。最常见的问题有三类缺失、突变、节假日。缺失值处理要看规模。单点缺失可以直接线性插值连续一段缺失尤其是超过6个小时的就不能简单插值否则会抹平真实的负荷形态。我会优先用历史相似日填充相似日的选择逻辑是相同星期几、相同时段、温度相近。注意不要用缺失点之后的数据回填那会引入未来的信息在离线验证时看起来准确上线后完全没有对应数据可用。异常值处理要区分设备故障和真实冲击。设备故障通常表现为单点跳变或连续多个点变成0真实冲击比如大型工厂集中启停负荷曲线会出现短时尖峰那是模型应该学习的规律。我的习惯是先用可视化把所有时序曲线看一遍再用统计阈值兜底比如计算相邻时刻负荷差分的标准差超过4倍标准差就标记出来逐个判断。如果是采集故障用周围正常点均值替代如果是真实冲击保留原值。节假日冲击是最容易被忽视的问题。电网负荷在春节、国庆期间会明显下降而且不同节假日形态差异很大。最简单可靠的做法是维护一份节假日列表为每个样本打上是否属于节假日更细一点的做法是加入“节假日第几天”“假期前第几天”这类特征比如春节这种长假期节前一两天的负荷下降和节中的低谷是不同的模式只用0/1标签无法区分。import pandas as pd import numpy as np df pd.read_csv(load_data.csv, parse_dates[timestamp]) df df.set_index(timestamp).sort_index() # 单点缺失用线性插值连续缺失超过6个点先置空 df[load] df[load].interpolate(methodlinear, limit6) # 异常值诊断对相邻时刻差分计算 z-score diff df[load].diff() z (diff - diff.median()) / diff.std() df.loc[abs(z) 4, load] np.nan df[load] df[load].interpolate(methodtime)逻辑说明第一处interpolate(methodlinear, limit6)只对连续不超过6个缺失点的片段做线性插值更长的缺失段保留NaN方便后面用相似日填充。第二处计算相邻时刻负荷差分再标准化成z-score超过4倍标准差点先置空最后用时间插值补齐。阈值4不是固定值如果数据本身波动很大可以适当放宽。参数说明limit的取值要结合采样间隔来看小时级数据6个点是6小时建筑负荷在这个尺度内变化相对平缓可以接受15分钟级数据连续缺6个点就不建议直接插值。z-score阈值太小会把正常尖峰误判成异常我通常先试4再结合曲线图确认误判比例如果误判多就放宽到5。2.3 特征构造让模型看到日历与温度特征工程决定模型能学到什么。负荷和人的作息高度相关模型必须看到日历信息也要看到温度、湿度这类气象信息以及历史负荷本身。日历特征至少包括小时、星期几、月份、是否工作日、是否节假日。小时和星期几可以直接用数值但树模型和线性模型的处理方式不同。树模型对数值编码不敏感给0到23的数字也能正确分裂线性模型则很容易被“23点和0点距离很接近”这种假设误导所以我给线性模型做小时周期编码用sin和cos两个分量表达小时在一天里的循环位置。温度特征是负荷预测里信息量最大的外部特征夏季降温和冬季采暖都会让负荷与温度呈现很强的相关关系而且是分段线性温度低于采暖拐点时越低负荷越高温度高于制冷拐点时越高负荷越高。如果只用线性模型可以人为加入双向温差特征比如取温度超过18度的部分和低于18度的部分分别作为两个特征如果用树模型温度特征直接给进去模型会自动找到拐点。历史负荷特征是短期预测里最有效的特征。我会构造前1小时负荷、前一天同一时刻负荷、前一周同一时刻负荷以及最近3小时和最近24小时的移动平均值。对小时级负荷预测来说前1小时的实际负荷携带大量信息模型靠这类滞后特征就能把误差压得很低。但要记住真正上线时预测未来多个小时前1小时负荷是拿不到的需要用递归方式替换成预测值这一点会在滚动预测部分再展开。气象数据的接入要根据业务范围来判断。如果有区域气象站的温度、湿度、风速数据可以把它们作为特征如果没有用公开气象数据也能凑但要注意网格预报值和实测值之间的偏差比如某地区夏季温度预报普遍偏高1到2度如果不做偏差校准负荷预测也会系统性偏高。特征量要控制住。很多滞后特征之间高度相关比如前1小时负荷和前3小时均值相关系数可能超过0.9树模型还能处理线性模型则会出现明显的系数不稳定。我一般先计算相关性矩阵把相关系数超过0.95的特征删掉一组再通过特征重要性验证。def build_features(df, holiday_dates): df df.copy() df[hour] df.index.hour df[weekday] df.index.dayofweek df[month] df.index.month df[is_holiday] df.index.isin(holiday_dates) # 小时周期编码避免线性模型觉得23点和0点很远 df[hour_sin] np.sin(2 * np.pi * df[hour] / 24) df[hour_cos] np.cos(2 * np.pi * df[hour] / 24) # 历史负荷滞后特征 df[lag_1h] df[load].shift(1) df[lag_24h] df[load].shift(24) df[lag_168h] df[load].shift(168) # 滚动平均值 df[mean_3h] df[load].rolling(3).mean() df[mean_24h] df[load].rolling(24).mean() return df逻辑说明shift(1)是取上一小时负荷shift(24)是前一天同一时刻shift(168)是前一周同一天同一时刻。rolling(3).mean()是最近3小时均值能平滑短时波动rolling(24).mean()是最近24小时均值代表最近一段时间的整体水平。周期编码里2 * np.pi * hour / 24把0到23映射到0到2π之间。参数说明滞后窗口的选择可以先用自相关图确认小时级负荷通常在24小时和168小时出现明显峰值所以滞后24和滞后168往往是树模型里重要性最高的特征。移动平均窗口不宜太短否则会跟前1小时滞后特征高度重迭也不宜太长超过48小时会把太久远的信息混进来。如果用线性模型还建议对标准化后的特征做方差膨胀因子检查避免共线性把系数推断带偏。3. 模型选型与建模从线性基线与树模型起步模型选型不需要一开始就追求复杂。负荷预测是典型的表格回归问题特征以时间、温度、历史负荷为主机器学习的常用方案里线性回归和梯度提升树是最稳的两个起点。这一章讲清楚怎么用基线模型建立参照再切换树模型提升精度以及怎么选择评估指标。3.1 线性回归与岭回归基线必须先做基线模型的价值是给后续模型一个参照系。如果岭回归在验证集上的误差已经不错说明当前特征和负荷的关系接近线性再去调树模型的收益可能很小如果岭回归误差明显偏大说明存在非线性特征交互树模型才有发挥空间。很多人跳过高漂回归直接上XGBoost结果模型跑完都不知道提升到底来自模型结构还是来自特征工程这样很难做工程决策。岭回归是线性模型里最实用的选择它通过L2正则化控制系数向零收缩避免高维特征下的共线性和过拟合。唯一需要调的主参数是alpha它控制正则化强度。alpha太小模型接近普通最小二乘方差大alpha太大所有系数都被压向零偏差增加。我通常在0.1到100之间取对数网格搜索。使用线性模型时特征标准化是必需的。特征里既有“小时”这种量级小于100也有“负荷”这种上千的量级如果不标准化正则化会按特征尺度不均地约束系数。注意标准化要用训练集的均值和方差验证集和测试集上不能重新计算否则就泄漏了分布信息。from sklearn.linear_model import Ridge from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline pipe Pipeline([ (scaler, StandardScaler()), (model, Ridge(alpha10.0)) ]) pipe.fit(X_train, y_train) y_pred pipe.predict(X_valid)逻辑说明Pipeline把标准化和岭回归串在一起确保验证和推理都套用同一套标准化参数。alpha10.0是初始值真实场景要在验证集上通过网格搜索确定。标准化器会在整体数据上计算均值和方差要求传入的X必须只包含建模用的数值特征。参数说明如果特征数量只有几十个alpha不用设得太大否则模型的偏差会明显尤其在温度影响强烈的季节。我用的搜索范围是[0.1, 1, 10, 50, 100]选验证集MAE最小的值。线性回归的误差出了异常点会变差可以先看残差图确认不要急着换成非线性模型。3.2 树模型LightGBM 与 XGBoost 的优势和参数梯度提升树在电力负荷预测里是目前最稳妥的机器学习选择。它对特征量纲不敏感不需要标准化能自动处理非线性关系和特征交互而且对缺失值有一定鲁棒性。在我接触的项目里LightGBM和XGBoost最终精度差别不大LightGBM训练更快XGBoost在小样本上更稳各有适用场景。树模型和线性模型的关键差异在于它能处理复杂的局部规律。比如温度对负荷的影响在拐点前后斜率不同树模型可以通过多次分裂把温度区间切成多段每段学习不同斜率而线性模型必须手动构造拐点特征。再比如某个工厂的检修让某段时期负荷形态异常树模型能把这段时期单独分到一个叶子节点避免影响其他时段。参数中最重要的四个是learning_rate、max_depth、n_estimators、min_child_samples。learning_rate控制每一步更新的步长越小越稳定但需要的迭代次数越多max_depth控制树的深度太深容易把噪声当成规律n_estimators是树的棵数通常和learning_rate配合调整min_child_samples限制叶子节点最少样本数防止极端值落在样本量过小的叶子节点上。LightGBM里还有一个容易忽略的细节它直方图算法对连续特征的切分和XGBoost的预排序不同在缺失值处理上也有差异但默认参数下两者差异不大不需要刻意调整。如果训练数据超过百万量级LightGBM的优势会体现得更明显。import lightgbm as lgb model lgb.LGBMRegressor( objectiveregression, learning_rate0.05, max_depth6, n_estimators600, subsample0.8, colsample_bytree0.8, min_child_samples20, random_state42 ) model.fit( X_train, y_train, eval_set[(X_valid, y_valid)], callbacks[lgb.early_stopping(50)] )逻辑说明subsample0.8是每次迭代随机抽取80%样本训练colsample_bytree0.8是每次建树只用80%的特征这两个子采样参数能显著降低过拟合并加速训练。early_stopping(50)在验证集误差连续50轮不下降时停止训练返回最优迭代轮数。训练结束后可以通过model.best_iteration_查看实际用得上的树的数量。参数说明max_depth6对小时级负荷数据通常足够树太深会把节假日的个别天当作长期规律来学。min_child_samples20是经验起点如果验证误差曲线早期就开始反弹优先调高到40而不是降低learning_rate。如果数据量只有几千行n_estimators可以设到300以内配合早停基本够用。3.3 评估指标别只盯 RMSE峰值时段才是痛点负荷预测的评估如果只看RMSE很可能会掩盖真实痛点。RMSE对异常点敏感适合衡量大偏差但它会把凌晨低谷的小误差和傍晚峰值的大误差混合在一起MAE更稳健但无法突出峰值时段的系统性偏差MAPE在负荷接近零时会虚高凌晨时段的绝对误差不大百分比却能到20%以上。我常用的做法是把验证集误差按小时分层统计分别看早高峰、晚高峰和白天的MAE。这样的原因很简单负荷预测的价值大多体现在峰值时段峰值时段如果系统性偏低机组备用不足的风险就会上升。评估时我会区分“全天MAE”和“高峰时段MAE”目标是让两个指标同时下降而不是只优化其中一个。MAPE计算还要避免除零。当真实负荷很低时即使绝对误差只有0.5 MWMAPE也可能超过20%这个数字会污染整体报告。我习惯在MAPE计算里给分母加一个下界并且额外统计负荷高于第25百分位时的MAPE这样得到的百分比误差更稳定。import numpy as np from sklearn.metrics import mean_absolute_error, mean_squared_error def evaluate(y_true, y_pred, hourNone): mae mean_absolute_error(y_true, y_pred) rmse np.sqrt(mean_squared_error(y_true, y_pred)) safe_true np.maximum(y_true, 1.0) mape np.mean(np.abs((y_true - y_pred) / safe_true)) * 100 p95 np.percentile(np.abs(y_true - y_pred), 95) result {MAE: mae, RMSE: rmse, MAPE: mape, P95: p95} if hour is not None: mask hour 8 result[MAE_peak] mean_absolute_error(y_true[mask], y_pred[mask]) return result逻辑说明np.maximum(y_true, 1.0)是给MAPE的分母加了下界避免负荷接近0时产生夸张的百分比。p95表示95%的绝对值误差都小于这个值比RMSE更直接地反映尾部风险。hour参数用于指定关注时段比如早上8点可自行换成晚高峰。参数说明评估前要把负荷还原到原始单位。如果训练时对目标做了归一化预测值也要还原后再算指标否则MAE和RMSE失去物理意义。对比不同模型时要固定同一时间段和同一指标口径不要A模型用MAPE、B模型用MAE这样没法定位差距。4. 从离线模型到可上线预测验证划分、滚动窗口与调优模型训练只是第一步真正落地负荷预测还要处理验证划分、预测窗口和模型更新这几个工程关键点。时间序列问题比普通回归问题更容易踩到“指标好看、上线翻车”的坑所以要提前把验证框架搭对。4.1 时间序列验证随机打乱在预测里是大忌普通回归任务随机划分训练集和测试集没有问题但时间序列数据如果随机打乱会让模型看到测试集所在时间段的信息考察的不是外推能力。更严重的是负荷数据有季节周期如果训练集和测试集来自同一时期的随机样本模型实际上学到了数据分布的整体形态预测的难度被严重低估。正确的做法是按时间顺序划分。最简单的方案是前70%训练、后30%验证但这样只能验证一段连续时间如果那段验证期恰好处于平季误差会好于全年平均。更可靠的方案是walk-forward验证让窗口不断向前滚动把每个窗口的验证误差累积起来取平均。sklearn的TimeSeriesSplit可以直接使用它保证每次划分的训练集都在验证集之前而且验证集之间不重叠。使用时还要考虑是否包含时间特征带来的边界效应比如在切分后训练和验证集各自独立构造滞后特征不要跨切分线取滞后值。from sklearn.model_selection import TimeSeriesSplit tscv TimeSeriesSplit(n_splits5) for train_idx, valid_idx in tscv.split(X): X_train, X_valid X.iloc[train_idx], X.iloc[valid_idx] y_train, y_valid y.iloc[train_idx], y.iloc[valid_idx] model.fit(X_train, y_train) y_pred model.predict(X_valid) print(mean_absolute_error(y_valid, y_pred))逻辑说明TimeSeriesSplit(n_splits5)会把数据切分成5段每段循环里训练集位于验证集之前验证集互不重叠。这样得到的5个MAE取平均比单次划分更能反映模型在不同时间段的稳定性。参数说明n_splits的选择取决于历史长度。两年以上的小时级数据可以设5到6折如果只有几个月数据3到4折更安全因为训练集太短时模型学不到季节规律。还可以考虑每次训练集的起点如何处理比如固定起点不更新或者用滑动窗口只保留最近365天。4.2 滚动预测与多步预测警惕误差累积单步预测是基础但业务上经常需要未来24小时甚至更长的曲线。多步预测的常用方案有三种递归预测、直接预测、多输出预测。递归预测把上一时刻的预测值作为下一时刻的滞后特征循环预测24步。它的优点是只训练一个模型缺点是误差会随着步长累积。比如第一步误差3%第二步在此基础上再叠加3%到了第24步曲线可能严重偏移尤其在温度突变时。直接预测是为每个预测步长训练一个独立模型预测小时0用一个模型预测小时1用另一个模型。每个模型只用真实历史特征避免了误差在时间步之间传递。缺点是训练成本高24步就要训练24个模型。实际中不需要为每个步长都建一个可以把24小时分成几个区间比如预测1到6小时用递归7到24小时用直接模型。多输出预测是利用回归器的multi_output能力同时输出未来多个时刻的预测值。对树模型来说每个输出列是独立建模的本质上是多个模型并行的直接预测不会引入误差累积。但输出之间存在相关性模型无法利用它们之间的约束。离线回测滚动预测时要特别注意特征边界。预测起点为t那么 t 时刻及之前的历史负荷都是真实值t1及之后如果还用滞后特征就要用预测值替换。如果在回测时不小心用了后续真实值误差会被严重低估。def backtest(model, X, y, predict_start, horizon24): model.fit(X.loc[:predict_start], y.loc[:predict_start]) y_pred [] current_pred None for step in range(horizon): # 预测步长大于1时滞后特征需要滚动替换 if step 0: X_step X.loc[predict_start:].iloc[[0]] else: X_step X.loc[predict_start step].copy() X_step[lag_1h] current_pred current_pred model.predict(X_step)[0] y_pred.append(current_pred) return np.array(y_pred)逻辑说明这个回测循环只是演示了滚动预测的思路第0步使用预测起点的真实历史特征第1步开始把上一步的current_pred填入lag_1h特征。注意X里其他时间特征和温度特征仍使用真实遍历值这在线下回测中是允许的因为预测时这些外部特征来自预报。参数说明递归步数太长时建议不要超过24步超过的话误差累积会很明显。如果必须预测更长时间可以分成两段前24小时用递归模型后续用日均值或趋势外推。horizon24是针对小时级数据的常见选择如果预测15分钟级建议设为96步但每一步对应的滞后特征要从小时级粒度换算。4.3 超参数调优与特征筛选让模型不容易过拟合树模型的参数多一个一个手动试很浪费时间。我习惯分两步调参先用较低learning_rate固定迭代次数然后调整树的深度和叶子节点最小样本数最后再调子采样比例。这种策略比一次性网格搜索更高效也更不容易被随机噪声干扰。使用sklearn的RandomizedSearchCV时要注意交叉验证必须使用时间序列切分方式不能默认用随机KFold。否则调出来的参数在时序外推时依然会偏乐观。搜索过程本身也要控制时间n_iter建议在30以内每次训练把n_estimators降低到200选完参数再加回来。特征筛选方面树模型的特征重要性可以作为线索。LightGBM的特征重要性有split和gain两种口径split表示特征被选为分裂点的次数gain表示特征带来的平均增益。我通常看gain因为它更直接反映对损失的贡献。把gain低的特征删掉后模型精度往往不变训练速度反而更快。from sklearn.model_selection import RandomizedSearchCV param_dist { max_depth: [4, 6, 8, 10], min_child_samples: [10, 20, 40], subsample: [0.7, 0.8, 0.9], colsample_bytree: [0.7, 0.8, 0.9] } search RandomizedSearchCV( lgb.LGBMRegressor(learning_rate0.05, n_estimators200), param_distributionsparam_dist, n_iter30, cvtscv, scoringneg_mean_absolute_error, random_state42 ) search.fit(X, y)逻辑说明RandomizedSearchCV从参数分布中随机抽取30组组合用前面定义的TimeSeriesSplit做交叉验证以负MAE作为评分。搜索完成后通过search.best_params_查看最优参数再用这个参数配合更大的n_estimators重新训练。参数说明n_iter30是速度与覆盖范围的折中。如果数据集大每组训练耗时长可以减到20如果数据集较小可以增加到50。搜索时先固定learning_rate0.05选完参数后再根据需要调整学习率。评分用负MAE是因为sklearn的搜索默认取最大值MAE越小越好所以要取负。5. 负荷预测避坑指南五个高频翻车点这一章记录的是实际项目中反复出现的问题。每条按“现象、原因、解决”展开我自己至少碰到过其中四条每一条都值得在上线前排查。5.1 短期预测误差不大但早晚峰值时段系统性偏低现象整体MAE看着不错把误差按小时统计后发现早上7点到9点、晚上18点到22点预测负荷普遍比实际值低1到2个百分点曲线波峰被削平。原因训练样本里峰值时段只占一天的少数小时模型为了最小化平均损失会更倾向把平滑曲线拟合好而不是去追逐峰值。再加上峰值时刻通常叠加了更强的温度和生产活动因素特征交互不够时模型学不到峰值抬升的机制。解决最直接的做法是给峰值时段的样本在损失函数里加权比如把9点和18到20点的样本权重设为1.5到2。也可以单独训练一个峰值时段模型只在峰值时段做预测主模型负责其余时段。目标函数也可以换成按负荷水平的相对误差让峰值时段权重自然提高。实测中峰值时段MAE能下降10%到15%。5.2 节假日预测崩溃误差放大好几倍现象普通日预测稳定一旦到春节、国庆这类长假预测误差变成平时的3倍以上有的树模型在长假首日直接把负荷预测低了30%。原因节假日样本在训练集里占比不到2%模型几乎没见过这种负荷形态。春节长假期间工厂停工会让工业负荷消失商业和居民负荷成为主导与普通日负荷结构完全不同模型只能按普通日的规律外推。解决先把节假日标签做成特征并提高节假日样本的训练权重。更进一步是把节假日的相对日期做成特征比如“距春节前5天”“春节第3天”“假期结束后第2天”让模型学习长假前后的负荷变化过程。如果历史数据超过三年可以用过去三年的同期数据单独微调一个节假日模型避免污染普通日模型。5.3 离线指标虚高上线后误差突然变大现象离线回测MAE只有2%部署上线后MAE变成6%而且偏差集中在预测起点附近。原因特征构造时泄漏了未来信息。最常见的是用当天日均温度预测当天逐时负荷或者在构建滞后特征时测试阶段的lag_1h竟然来自真实未来值。离线验证时这些信息是存在且完整的所以指标好看上线时预测起点之后的真实负荷根本拿不到模型只能依赖不完整的特征。解决严格检查特征时间戳。所有特征必须早于或等于预测起点温度特征要使用预测时刻之前发布的气象预报不能用事后观测值。构造代码时分出训练和预测两个分支预测分支以预测起点为边界只允许使用起点时刻已经存在的数据。写完特征函数后可以用一个简单测试在特征里加入“当天真实负荷”作为特征如果模型指标大幅提升说明其他特征里混入了类似的信息需要排查。5.4 每周重训一次效果反而越来越差现象模型每隔一周用最近数据重训一次头几天误差下降然后某一天误差暴涨持续好几天才恢复。原因滚动重训练频率过高让模型把最近一两周的极端天气或者临时事件当成了长期规律。比如上周某两天工厂减产导致负荷偏低模型重新训练后记住了这个现象而这周负荷恢复正常模型反而预测偏低。还有一种情况是训练集窗口设得太短只用了最近一两个月数据丢失了季节模式。解决给重训练设置最小训练集长度比如至少保留过去365天。每次重训练前后用固定的最近30天验证集做检查如果验证误差相比上一版明显升高就回滚到上一版。线上更新要有灰度发布意识可以先让旧模型和新模型并行运行几天对比后再切换。5.5 MAPE在凌晨时段爆炸报告没法看现象白天MAPE在3%左右凌晨2点到5点的MAPE突然到20%但绝对误差可能只有几百千瓦。原因MAPE的分母是真实负荷凌晨低谷时负荷很小同样的绝对误差会被放大成很大的百分比。模型如果用MAPE做早停低负荷时段的梯度会主导整个验证过程导致模型为了降低凌晨百分比误差而牺牲高峰时段的精度。解决改用对称MAPE公式里同时考虑真实值和预测值的关系。如果只是评估可以排除凌晨低负荷时段或者按负荷分位数分层计算MAPE。训练时建议使用加权MAE或加权MAPE给高峰时段更高权重。报告里同时给出MAE和RMSE避免只报一个MAPE。6. 再进一步分位数预测与两模型融合的实用做法当单点预测稳定后下一步值得做的是输出预测区间和简单模型融合这两个技巧对实际业务帮助很大。6.1 用分位数回归输出预测区间调度部门需要的不只是一个期望值还需要知道负荷可能落在哪个范围以便安排备用容量。LightGBM支持分位数回归通过设置objectivequantile和alpha就能拟合指定分位数。lower_model lgb.LGBMRegressor(objectivequantile, alpha0.1, learning_rate0.05, n_estimators300) upper_model lgb.LGBMRegressor(objectivequantile, alpha0.9, learning_rate0.05, n_estimators300) lower_model.fit(X_train, y_train) upper_model.fit(X_train, y_train) y_lower lower_model.predict(X_test) y_upper upper_model.predict(X_test)逻辑说明alpha0.1拟合第10百分位alpha0.9拟合第90百分位。两个模型独立训练预测时输出一个80%区间。分位数回归比残差法更适合负荷数据因为负荷在高峰时段波动更大区间也应该随之变宽。参数说明分位数回归对异常值更敏感learning_rate建议比回归模型调低一点比如0.03到0.05否则少数尖峰会主导损失。训练后可以统计测试集里真实值落在区间内的比例控制在80%附近。6.2 线性模型加树模型做简单融合我试过几种融合方式最实用的是让岭回归和LightGBM各出一个预测再做一次线性加权。岭回归擅长整体趋势树模型擅长局部形态两者互补性比同类型模型融合更强。权重可以用验证集网格搜索从0到1之间按0.05步长取组合选验证MAE最小的一组。手工设定也可行比如树模型0.7、线性模型0.3。融合前要确保两个模型使用完全相同的验证区间误差口径一致。我这些年做负荷预测最深的感受是模型复杂度不是关键预测任务定义和验证边界才是决定成败的环节。之前有一个项目花了大量时间在调树模型参数却一直没发现温度特征用了事后观测值离线指标漂亮但线上始终对不上后来把特征时间戳修正模型没做大改动误差反而明显下降。另一个习惯是每次模型迭代前先写一页验证计划写清训练区间、验证区间、评估指标和更新频率再动手写代码。这个习惯帮我规避了很多无效调参。希望帮到你。本文还有配套的精品资源点击获取