机器学习预测工业用电量:从数据到部署的完整方案
简介这份资源面向制造业能源管理与数据分析方向的学习者聚焦工业用电量的机器学习预测问题帮助读者理解如何用数据科学手段识别高能耗环节、优化能效管理。压缩包共15个文件以11个Python脚本为主涵盖数据读取与预处理、多模型对比实验及图形界面展示另含3张预测结果与数据可视化图片和1个模型训练检查点文件整体约175KB体量轻便、便于本地复现。内容围绕XGBoost、随机森林、逻辑回归、LightGBM、AdaBoost、SVM、KNN等模型展开横向对比并配有Transformer时间序列预测结果可直观比较不同算法在用电量预测任务上的表现差异。已有234人学习适合希望掌握完整建模流程、对照实验设计与结果可视化思路的读者参考借鉴。1. 从一张对不上的电费单说起这套预测方案到底解决什么问题某制造企业的能源管理岗每个月都要做一件事把下个月的电费预算报上去。过去这套流程靠的是老师傅翻台账、看去年同期、再拍脑袋加个安全系数结果常常是预算批下来和实际账单差出一大截年底一算偏差累积起来够买一条产线的小设备。问题不在于人不认真而在于工业用电量本身受排产计划、季节温度、设备检修、班次调整多重因素叠加影响人脑很难同时把这些变量捋顺。这套「机器学习预测工业用电量」的方案就是要把这件靠经验的事变成靠模型的事用历史用电数据加上生产与气象特征训练出能给出未来月度、周度用电量预测值的模型并配套一套可复现的训练与评估流程。它适合两类人——正在做数据类毕设或课设、需要一套完整可交付方案的学生以及要给工厂做能源预算、需要落地一套预测工具链的从业者。制造场景下的用电预测不是学术玩具它直接连着预算准确率和能耗考核所以方案从第一天就得按「能验收」的标准来搭。2. 需求与数据底座先把预测目标和特征口径定死2.1 预测粒度与预测窗口怎么选动手写代码之前第一件要定死的事是预测粒度和预测窗口。粒度指模型输出的时间单位常见的有小时级、日级、月级窗口指提前多久给出预测。工业用电场景里这两个参数不是拍脑袋定的而是由业务用途倒推如果是给月度电费预算用粒度取日、窗口取提前一个月最合适因为预算审批周期就是月如果是给车间做错峰生产调度用粒度要细到小时、窗口缩到提前一天甚至几小时。我一般会建议学生项目先做日粒度、提前 7 天和提前 30 天两套窗口既覆盖了课程设计对「多步预测」的要求又不至于把数据量撑到跑不动。粒度定得太细而样本不足模型学到的全是噪声这是很典型的翻车点。确定粒度后要同步确定评估口径。回归预测不能只看一个指标通常的做法是同时报 MAE、RMSE 和 MAPE 三个MAE 告诉你平均差多少度电直观RMSE 对大误差更敏感能暴露偶发的极端偏差MAPE 是百分比方便跨月份、跨产线横向比较。三个指标一起看才能判断模型是「整体偏」还是「偶尔崩」。2.2 数据表结构与特征工程口径工业用电预测的数据底座一般由三张表拼起来用电量表、生产排产表、气象表。用电量表是主表字段包括日期、表计编号、有功电量、峰平谷分时电量排产表提供产量、班次数、设备开机台数气象表提供日均温度、湿度。三张表按日期对齐形成宽表。下面是一个最小可用的建表与特征构造示例用 SQL 写方便直接落到数据库里-- 用电主表按日聚合保留分时结构 CREATE TABLE fact_power_daily ( stat_date DATE NOT NULL, -- 统计日期 meter_id VARCHAR(32) NOT NULL, -- 表计编号 energy_kwh DECIMAL(12,2), -- 当日总有功电量 peak_kwh DECIMAL(12,2), -- 峰段电量 flat_kwh DECIMAL(12,2), -- 平段电量 valley_kwh DECIMAL(12,2), -- 谷段电量 PRIMARY KEY (stat_date, meter_id) ); -- 特征宽表用电 排产 气象按日对齐 CREATE TABLE feat_power_daily AS SELECT p.stat_date, p.meter_id, p.energy_kwh, p.peak_kwh, p.flat_kwh, p.valley_kwh, s.output_qty, -- 当日产量 s.shift_cnt, -- 班次数 s.machine_on, -- 开机台数 w.avg_temp, -- 日均温度 w.avg_humidity, -- 日均湿度 DAYOFWEEK(p.stat_date) AS weekday, -- 星期几捕捉周周期 MONTH(p.stat_date) AS month -- 月份捕捉季节周期 FROM fact_power_daily p LEFT JOIN fact_production_daily s ON p.stat_date s.stat_date AND p.meter_id s.meter_id LEFT JOIN dim_weather_daily w ON p.stat_date w.stat_date;这段 SQL 的关键设计点有三个。第一用电量保留峰平谷分时结构而不是只留总量因为分时电量里藏着生产班次信息是强特征。第二排产表和气象表都用 LEFT JOIN保证用电主表的每一行都保留缺失的生产或气象数据后续在 Python 侧统一填充避免在 SQL 阶段就把样本丢掉。第三weekday 和 month 两个派生字段是周期特征的显式编码工业用电有非常明显的周内节律周末减产和季节节律夏季降温负荷把这两个周期显式喂给模型比让模型自己从日期里猜要稳得多。提示特征宽表建好后先做一次缺失率和异常值体检温度缺失超过 5% 的月份要单独标记否则模型会把「没数据」误学成「用电低」。2.3 技术选型为什么是梯度提升树而不是深度学习选型上这个场景我一般直接上梯度提升树LightGBM 或 XGBoost而不是 LSTM 那类时序深度模型。原因很实在工业用电的样本量通常是「几年 × 若干表计」撑死几千到几万行深度模型在这个量级上很容易过拟合调参成本还高而梯度提升树对中小样本、混合类型特征数值 类别天然友好训练快、可解释性强特征重要性还能直接拿去做业务解释答辩时被问「为什么这个特征重要」能答得上来。只有当数据量到十万级以上、且需要做很细粒度的多步时序建模时才值得考虑深度模型。这个取舍判断本身就是方案里要写清楚的一段别跳过。3. 总体架构与模块划分从原始表到预测值的四层链路3.1 四层架构与模块职责整套方案按数据流分成四层每层职责单一方便单独调试和替换。第一层是数据接入层负责从数据库或 CSV 拉取原始表并做时间对齐第二层是特征工程层负责缺失填充、异常处理、周期编码和滞后特征构造第三层是建模层负责训练、验证、超参搜索和模型持久化第四层是预测与评估层负责滚动预测、指标计算和结果落表。四层之间用中间文件或数据表衔接任何一层出问题都能单独定位不会牵一发动全身。模块划分上我习惯拆成五个 Python 模块data_loader.py管接入feature_builder.py管特征trainer.py管训练与验证predictor.py管滚动预测evaluator.py管指标。每个模块对外只暴露一个主函数输入输出都是 DataFrame这样单元测试好写答辩演示时也能一层层跑给评委看。3.2 特征工程模块的实现要点特征工程是这套方案里最影响效果的一环也是最容易被学生做薄的一环。除了前面 SQL 里的周期字段还要构造滞后特征和滚动统计特征滞后 1 天、7 天、30 天的用电量以及过去 7 天、30 天的均值和标准差。滞后特征让模型能利用近期水平滚动统计让模型感知波动幅度。下面这段是特征构造的核心实现import pandas as pd import numpy as np def build_features(df: pd.DataFrame) - pd.DataFrame: df df.sort_values([meter_id, stat_date]).copy() # 按表计分组做滞后避免不同表计的数据串行 grp df.groupby(meter_id)[energy_kwh] for lag in (1, 7, 30): df[flag_{lag}] grp.shift(lag) # 滚动均值与标准差窗口 7 和 30 for win in (7, 30): df[froll_mean_{win}] grp.shift(1).rolling(win).mean().reset_index(level0, dropTrue) df[froll_std_{win}] grp.shift(1).rolling(win).std().reset_index(level0, dropTrue) # 缺失填充滞后特征用前向填充滚动统计用中位数兜底 lag_cols [c for c in df.columns if c.startswith((lag_, roll_))] df[lag_cols] df.groupby(meter_id)[lag_cols].ffill() df[lag_cols] df[lag_cols].fillna(df[lag_cols].median()) return df这段代码有两个必须讲清的设计点。第一所有滞后和滚动特征都先shift(1)再计算确保预测目标日 t 的特征只用到 t 之前的信息这是防止数据泄漏的红线很多毕设模型指标虚高就是因为把当天数据也算了进去。第二分组用meter_id因为不同表计之间没有可比性混在一起做滞后会把 A 表计的用电量错配到 B 表计上。滚动标准差用中位数兜底而不是均值是因为用电序列里偶发的高值会把均值拉偏中位数更稳。3.3 训练与验证模块时间序列不能随机切分训练模块的核心不是调参而是验证方式。时间序列数据绝对不能随机切分训练集和测试集否则模型会「看到未来」指标好看但上线就崩。正确做法是按时间顺序切前 70% 做训练中间 15% 做验证调参最后 15% 做测试测试集只在最后评估时用一次。下面是一个按时间切分并训练 LightGBM 的骨架import lightgbm as lgb from sklearn.metrics import mean_absolute_error, mean_squared_error def time_split(df, train_ratio0.7, val_ratio0.15): dates sorted(df[stat_date].unique()) n len(dates) tr_end dates[int(n * train_ratio)] va_end dates[int(n * (train_ratio val_ratio))] train df[df[stat_date] tr_end] val df[(df[stat_date] tr_end) (df[stat_date] va_end)] test df[df[stat_date] va_end] return train, val, test def train_model(train, val, feature_cols): params dict( objectiveregression, metricmae, learning_rate0.05, num_leaves31, min_data_in_leaf20, feature_fraction0.8, bagging_fraction0.8, bagging_freq5, verbose-1 ) dtrain lgb.Dataset(train[feature_cols], labeltrain[energy_kwh]) dval lgb.Dataset(val[feature_cols], labelval[energy_kwh], referencedtrain) model lgb.train( params, dtrain, num_boost_round2000, valid_sets[dval], callbacks[lgb.early_stopping(100), lgb.log_evaluation(200)] ) return model参数上learning_rate0.05配合early_stopping(100)是中小样本的稳妥组合学习率再低训练慢、再高容易欠拟合min_data_in_leaf20是防止叶子节点过细导致过拟合的关键样本量小的时候这个值要往上调。feature_fraction和bagging_fraction都设 0.8是给模型加一点随机性提升泛化。这些参数不是抄来的默认值而是按「几千行样本、几十个特征」这个量级调的换数据量要重新试。3.4 预测与评估模块滚动预测怎么落地预测模块要解决的是「用训练好的模型按天往前滚输出未来 N 天预测值」。难点在于滞后特征在预测期是未知的必须用预测值回填再继续往前推这叫递归多步预测。实现上要维护一个滑动窗口每预测一天就把预测值塞回历史序列再构造下一天的特征。评估模块则把预测值和真实值对齐按月度、按表计分别算 MAE、RMSE、MAPE输出一张评估表。这张表是验收时最有说服力的材料比任何口头解释都管用。4. 避坑与排查五个最容易翻车的地方4.1 指标虚高数据泄漏的典型症状现象是验证集 MAPE 低到 3% 以下测试集一跑就飙到 20% 以上。原因几乎都是特征里混进了未来信息最常见的是滚动统计没做shift(1)或者把目标当天的排产数据也当成了已知特征。解决办法是把特征构造函数单独抽出来做一次「时间穿越测试」随机抽一天检查它的所有特征是否只依赖该天之前的数据发现依赖当天的就改。这个测试我每次都会写进单元测试里。4.2 缺失值填错方向把停产日填成了正常日现象是模型在春节、检修期这类停产日附近预测值明显偏高。原因是缺失填充用了全局均值或前向填充把停产日的用电量填成了正常生产水平。解决办法是区分「数据缺失」和「真实低负荷」停产日如果有排产表记录产量为 0就应该保留 0 而不是填充只有排产数据也缺失时才走填充逻辑。填充策略要按业务含义分情况不能一刀切。4.3 表计混算不同产线数据串行现象是某条产线的预测误差特别大其他产线正常。原因是特征构造时没有按表计分组滞后特征把别的表计数据错配过来。解决办法是所有涉及shift、rolling、groupby的操作都显式带上meter_id分组并在特征宽表里保留表计维度训练时要么按表计分别建模要么把表计作为类别特征喂进去。4.4 极端天气样本太少模型没见过就不会预测现象是夏季连续高温那几天的预测偏差远大于平时。原因是历史数据里极端高温样本占比很低模型对这类尾部情况学得不够。解决办法有两个方向一是给样本按温度分桶做加权让极端天气样本权重高一些二是保留一个基于规则的兜底修正比如温度超过历史 95 分位时在模型输出上叠加一个经验修正系数。纯靠模型硬扛尾部在中小样本下不现实。4.5 评估口径不一致答辩时数字对不上现象是自己算的 MAPE 和评委复算的对不上。原因通常是 MAPE 的分母处理不一致真实值为 0 的停产日怎么算、是按天算还是按月聚合后再算不同口径结果差很多。解决办法是在方案里把评估口径写死MAPE 只在真实值大于某个阈值的样本上计算月度指标先按月聚合再算百分比并在评估脚本里把口径注释清楚。口径写清楚答辩时被追问也能当场解释。5. 验收与答辩用一张对照表把方案讲透验收这套方案我一般不看模型多花哨只看三件事能不能说清楚预测准不准、为什么准、不准的时候怎么办。具体做法是准备一张「基线对照表」把三种方法放在一起比朴素基线直接用去年同期值、移动平均基线过去 30 天均值、本方案的梯度提升树模型。三种方法在同一测试集上算同一套指标表格一摆提升幅度一目了然。评委最认这种对照因为它证明你的模型不是自说自话。方法MAE度RMSE度MAPE去年同期基线待填待填待填30 天移动平均待填待填待填梯度提升树模型待填待填待填表格里的数字要自己跑出来填别编。答辩时按「需求 → 数据 → 特征 → 模型 → 对照 → 局限」六步讲每步控制在两分钟内重点放在特征设计和防泄漏上因为这两块最能体现你是不是真懂时序预测。局限部分主动讲比如极端天气样本不足、新产线冷启动没有历史数据主动暴露问题比被问出来强。还有一个具体技巧把某一天的特征向量和预测过程打印出来现场演示「输入什么、模型输出什么、和真实值差多少」。这种可复现的演示比 PPT 上的曲线图有说服力得多评委一看就知道这套东西是真跑通的。血泪经验是我早期做这类项目时总想着把模型调得更复杂结果答辩被问「你这个复杂模型比移动平均强多少」答不上来。从那以后我每次做预测类方案都强制先跑通基线对照表再谈模型优化基线打不过的复杂模型一律不上。希望这套结构能帮到你把方案搭起来、把数字跑出来剩下的就是讲清楚。本文还有配套的精品资源点击获取