ARTICLE DETAIL

资讯详情

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

用Python机器学习打造能源管理系统:负荷预测与智能调度实战

用Python机器学习打造能源管理系统:负荷预测与智能调度实战 先说这个项目的来源。去年春天一个在工业园做能源管理的朋友找我他们厂区手里攒了两年多的电表采集数据粒度细到15分钟一条设备包括注塑机、空压机、制冷机组另外还配了一套500kWh的储能电池。厂子规模不小但每个月电费大几十万峰段电费尤其扎眼。他问得很直接能不能用AI把这部分成本压下来。后来我们就把整套能源管理系统从零搭起来了核心就两件事第一用Python加机器学习建模把未来24小时甚至未来3天的电力负荷预测准第二基于预测结果用优化调度引擎告诉现场每台设备什么时候开、什么时候停储能什么时候充、什么时候放。这篇文章就是那次实战的完整复盘。我会把从数据清洗、特征工程、模型训练到调度建模、系统部署的完整链路写出来所有核心代码都能直接用也会把实际踩过的坑一并交代清楚。不管你是后端转数据、做能耗管理的工程师还是刚入门想找一个完整AI落地项目的同学这篇文章应该能帮你少走不少弯路。1. 项目整体设计与技术选型1.1 业务需求拆解这个项目到底在解决什么问题很多刚接触能源管理的朋友第一反应是“做个预测模型不就完事了”。实际上一个能真正省钱的系统至少要拆成三层来看。第一层是预测层。它要回答“未来一段时间用电量是多少”这个问题。厂区负荷不是一条平直线它有明显的日内周期性——白天生产用电高夜里低也有周内规律——周末产线停一批还有温度敏感性——夏天制冷机组一开负荷立刻往上跳。预测层的任务就是把这些规律用数据学出来输出一条未来24小时的负荷曲线。第二层是决策层也就是调度。拿到预测曲线之后我们需要回答“怎么安排设备运行最省钱”。这里面存在一个核心矛盾生产任务必须完成但峰时电价可能是谷时的三倍。如果能在预测的指导下把一部分弹性负荷挪到低价时段同时用储能做低充高放就能在不影响生产的前提下把成本打下来。第三层才是执行层。再好的调度方案如果现场操作人员看不懂、系统没法接那就等于零。所以系统最终要输出类似“10点到11点3号空压机降载到60%”这种可直接执行的操作建议甚至可以对接PLC实现自动下发。这个项目里我们给厂区定的目标很朴素在不减产、不搞大基建投入的前提下把每月电费降低10%到15%。所有技术选型都围绕这个目标展开不是为了炫技纯粹是为了解决问题。1.2 技术选型为什么是Python为什么是这套AI组合这个项目整个技术栈选了Python一方面因为团队里大家最熟的就是这套另一方面也是因为能源数据分析和AI建模这两块Python生态几乎没对手。数据处理用pandas和numpy处理15分钟粒度的时序数据非常顺手。机器学习这边主力模型选了LightGBM。为什么不选深度学习或者更复杂的模型因为厂区负荷预测本质上是一个“表格型数据强时序特征”的问题LightGBM这类GBDT模型在这种场景下训练快、效果稳、调参成本低而且对缺失值和异常值有一定鲁棒性。后面我们也跑了LSTM做对照实验结果在同样的特征条件下LSTM并没有比LightGBM准多少训练时间却多了几十倍。调度模块也做了两套方案。第一套用PuLP做混合整数规划适合小规模精确求解第二套用DEAP做遗传算法应对设备数量多、约束复杂的场景。接口层用了FastAPI部署用Docker。数据库选的是PostgreSQL加TimescaleDB插件时序数据的存储和查询效率比普通MySQL好不少。有一点值得单独说开发环境建议用VSCode配MiniCondaPython版本固定在3.10以上。这个组合在Windows和Linux下都稳定不会出现什么奇奇怪怪的依赖冲突。1.3 整体架构数据从哪来调度指令到哪去先看数据流它决定了整个系统怎么搭。数据采集端厂里的智能电表和支持Modbus TCP的电力监控网关会每15分钟上报一次电压、电流、功率和电能读数。网关把数据推给系统系统做解析后存入数据库。历史数据有两年多的积累这是做预测模型的基础。预测模块每天定时从数据库读历史负荷、天气API取温度湿度、节假日表取日期属性然后计算出特征矩阵再调用训练好的模型推理生成未来24小时负荷预测值。调度模块拿到预测值之后结合电价曲线、储能SOC状态、设备参数和生产任务约束求解出未来24小时每台设备和储能的运行计划。求解结果写入调度结果表同时推送给Web界面展示也可以通过Modbus TCP下发到现场控制器。整个架构分四层采集层、存储层、算法层、应用层。这样拆分的好处是每一层都能独立升级比如预测模型从LightGBM换成其他模型调度模块和存储层都不用动。项目做大了之后这种解耦的收益会越来越明显。2. 电力负荷预测模块把未来24小时算准确2.1 数据清洗与预处理先把脏东西清掉我见过太多项目模型还没开始跑数据就已经不能看了。这个项目的原始数据来自厂里几台电表和控制器的历史记录问题不少一部分时间戳重复一部分功率值直接是0还有几条数据明显异常——比如一台200kW的设备功率曲线突然跳到几千千瓦一看就是采集端信号干扰。第一步是做时间对齐。因为多个数据源的采样时钟不完全一致需要把所有数据统一重采样到15分钟间隔用pandas的resample方法按时间升采样缺失值用前向填充加插值的方式兜底。第二步是清洗异常值。我用的是组合策略单点超过设备额定功率上限的直接标记为异常连续多个点为0但前后有正常值的按采集断线处理用前后均值填补还有一些跳变特别剧烈但没超上限的点用滑动窗口的z-score方法筛掉。核心逻辑很简单但写起来要小心不能把真实的生产负荷波动误杀。import pandas as pd import numpy as np def clean_load_series(df, max_power1000, window12, z_thresh3.5): df df.sort_index() df df.resample(15min).mean() df[load] df[load].interpolate(methodlinear, limit_directionboth) # 过滤超过物理上限的异常点 df.loc[df[load] max_power, load] np.nan # 用滚动窗口z-score过滤突变点 rolling_mean df[load].rolling(window, centerTrue, min_periods5).mean() rolling_std df[load].rolling(window, centerTrue, min_periods5).std() zscores (df[load] - rolling_mean) / rolling_std.replace(0, np.nan) df.loc[zscores.abs() z_thresh, load] np.nan df[load] df[load].interpolate(methodlinear) return df清洗完之后一定要做可视化对比把处理前后的曲线叠在一起看一遍确认没有把正常的负荷尖峰给削掉。这一步花的时间不会少但非常值得后面模型效果会有立竿见影的差别。2.2 特征工程预测准不准七分看特征模型选得再花哨特征喂得不对照样白搭。电力负荷预测的特征我一般分成四类时间特征、气象特征、历史负荷特征、外部事件特征。时间特征是基础。小时、星期几、是否周末、是否节假日这几个特征看着简单但对负荷曲线的影响非常直接。厂里工作日白天的负荷可能到800kW周末直接掉到300kW以下这种规律模型必须能学到。气象特征对温度敏感型用户尤其重要。我把最高温度、最低温度、平均温度、湿度都放进特征集里还构造了一个“体感温度”特征。为什么这么做因为空调、制冷设备的负荷跟温度存在明显非线性关系直接用原始温度往往拟合不够体感温度综合了湿度和风速效果会更稳定。历史负荷特征是预测模型的主力。常见做法是构造滞后特征lag_1表示1小时前负荷lag_24表示昨天同时刻负荷lag_168表示上周同时刻负荷。再加上滑动窗口统计量比如过去6小时的均值、最大值、最小值、标准差。下面是一段特征工程的代码骨架。def build_features(df, weather_df, holiday_calendar): df df.copy() df[hour] df.index.hour df[weekday] df.index.weekday df[is_weekend] (df.index.weekday 5).astype(int) df[is_holiday] df.index.date.isin(holiday_calendar).astype(int) df[temp] weather_df[temp].reindex(df.index, methodffill) df[humidity] weather_df[humidity].reindex(df.index, methodffill) df[feels_like] 1.04 * df[temp] - 0.2 * df[humidity] - 2.7 df[lag_1h] df[load].shift(4) df[lag_24h] df[load].shift(96) df[lag_168h] df[load].shift(672) df[rolling_mean_6h] df[load].rolling(24, min_periods1).mean() df[rolling_max_6h] df[load].rolling(24, min_periods1).max() df[rolling_std_6h] df[load].rolling(24, min_periods1).std() df df.dropna() return df我自己的经验是滞后特征直接决定模型的下限时间特征决定模型能不能抓住周期气象特征决定模型在极端天气下会不会翻车。四个维度都补齐了模型基本不会差。2.3 模型构建与训练LightGBM为主LSTM做对照主力模型选了LightGBM因为它在这种带大量表格特征的时序任务上表现非常稳。训练时要做时序交叉验证不能直接用普通的K折否则会让模型“偷看”到未来的数据验证结果会虚高。我用TimeSeriesSplit把数据集按时间顺序切成5份每次用前面4份训练、最新1份验证。LightGBM本身训练速度快5折下来也就几分钟。import lightgbm as lgb from sklearn.model_selection import TimeSeriesSplit params { objective: regression, metric: mae, boosting_type: gbdt, learning_rate: 0.05, num_leaves: 31, feature_fraction: 0.8, bagging_fraction: 0.8, bagging_freq: 1, verbose: -1, n_jobs: -1 } tscv TimeSeriesSplit(n_splits5) best_model None best_mae float(inf) for train_idx, val_idx in tscv.split(X): X_train, X_val X.iloc[train_idx], X.iloc[val_idx] y_train, y_val y.iloc[train_idx], y.iloc[val_idx] model lgb.train( params, lgb.Dataset(X_train, y_train), num_boost_round1000, valid_sets[lgb.Dataset(X_val, y_val)], callbacks[lgb.early_stopping(50), lgb.log_evaluation(100)] ) val_mae model.best_score[valid_0][l1] if val_mae best_mae: best_model model best_mae val_mae作为对照我们也用TensorFlow搭了一个LSTM。时序模型的思路是把过去48小时负荷序列作为输入预测未来24小时负荷。这里有个工程上的细节要注意LSTM对数值范围非常敏感训练前必须对负荷做归一化推理完成后再反归一化而且归一化的scaler必须用训练集的统计量不能用全量的否则会有数据泄漏。from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense from sklearn.preprocessing import MinMaxScaler scaler MinMaxScaler() y_scaled scaler.fit_transform(y_train.values.reshape(-1, 1)) def make_sequences(data, input_steps96, output_steps96): X, y [], [] for i in range(len(data) - input_steps - output_steps 1): X.append(data[i:i input_steps]) y.append(data[i input_steps:i input_steps output_steps]) return np.array(X), np.array(y) X_lstm, y_lstm make_sequences(y_scaled.flatten(), input_steps96, output_steps96) model_lstm Sequential([ LSTM(64, return_sequencesTrue, input_shape(X_lstm.shape[1], 1)), LSTM(32), Dense(96) ]) model_lstm.compile(optimizeradam, lossmae) model_lstm.fit(X_lstm, y_lstm, epochs50, batch_size32, validation_split0.1)最终实验下来在同样的验证集上LightGBM的预测MAPE在6%左右LSTM在7%到8%之间。如果只追求精度和工程性价比LightGBM是更好的选择。2.4 效果评估与调参从9%到6%的调优过程评估指标一般用三个MAE、MAPE、RMSE。MAPE最容易跟业务人员解释就是“预测值跟实际值平均偏了多少百分比”。最开始我用默认参数跑出来的LightGBM模型MAPE在9.5%左右其实已经能用了但远谈不上好。后来做了一轮调优效果提升明显。第一步是加特征。把滞后24小时和滞后168小时特征加进去之后MAPE直接从9.5%降到7.8%。周末和节假日的偏差明显减小因为模型终于能区分工作日和休息日的负荷形态了。第二步是调参。重点调num_leaves、learning_rate、feature_fraction这几个这里可以直接用LightGBM自带的cv函数做一次网格搜索不需要太复杂的框架。第三步是修正节假日数据。国内节假日对负荷的影响非常大五一、十一这种长假厂区几乎停产模型很容易翻车。光靠is_holiday这个0/1特征不够我还加了一个“距节假日天数”的连续特征让模型能感知假期的前奏和余波。这一轮下来MAPE降到了6.3%左右。这里有个很重要的心得模型调优不要一上来就钻超参数先把特征做扎实。特征每加一个有效维度效果都是几个百分点的提升超参数优化折腾半天往往只能挤出一个百分点以内的收益。3. 智能调度模块让预测结果变成省钱策略3.1 调度问题建模设备、储能、电价一个都不能少预测模型本身不会直接省钱真正把模型输出转化成真金白银的是调度模块。调度问题的本质是一个优化问题在满足生产任务和设备运行约束的前提下决定未来24小时内每一台设备每个时段的功率设定值以及储能的充放电策略让总电费最低。这里用一个简化的场景来说明建模过程。假设厂里有三台可调设备一台空压机、一台注塑机、一台制冷机组每台设备有最小运行功率和最大运行功率但都要求全天完成一定的生产任务量。储能系统容量500kWh最大充放电功率200kW充放电效率大约90%。电价是峰平谷三段峰段每度1.2元、平段0.8元、谷段0.4元。调度周期按15分钟划分一天96个时段。目标函数可以写成minimize sum( price[t] * (fixed_load[t] sum(P[d][t]) charge[t] - discharge[t]) )其中fixed_load是固定负荷P[d][t]是设备d在时段t的功率charge和discharge分别是储能的充放电功率。约束条件包括每台设备每个时段的功率必须在最小和最大之间每台设备全天的总产量必须达到要求也就是所有时段的功率之和等于任务总量储能SOC每个时段在0到500kWh之间充放电不能同时进行一天结束时的SOC要和开始时的SOC保持一致这个模型建好之后不需要发明新的算法直接交给求解器去解。3.2 基于PuLP的精确求解混合整数规划落地PuLP是Python里一个非常好用的线性规划库建模语法直观适合快速验证。针对上面的场景建模代码大概是下面这样。import pulp T 96 devices { compressor: {min: 50, max: 200, task: 2400}, injection: {min: 30, max: 150, task: 1800}, chiller: {min: 0, max: 100, task: 800}, } # 电价峰1.2 / 平0.8 / 谷0.4 price [] for t in range(T): h t // 4 if 10 h 12 or 18 h 20: price.append(1.2) elif 7 h 9 or 13 h 17 or 21 h 22: price.append(0.8) else: price.append(0.4) prob pulp.LpProblem(smart_scheduling, pulp.LpMinimize) P { d: [pulp.LpVariable(fP_{d}_{t}, lowBounddevices[d][min], upBounddevices[d][max]) for t in range(T)] for d in devices } charge [pulp.LpVariable(fcharge_{t}, lowBound0, upBound200) for t in range(T)] discharge [pulp.LpVariable(fdischarge_{t}, lowBound0, upBound200) for t in range(T)] soc [pulp.LpVariable(fsoc_{t}, lowBound0, upBound500) for t in range(T)] # 固定基础负荷 base_load [180 30 * (t % 24) for t in range(T)] prob pulp.lpSum(price[t] * ( base_load[t] pulp.lpSum(P[d][t] for d in devices) charge[t] - discharge[t] ) for t in range(T)) for d in devices: prob pulp.lpSum(P[d][t] for t in range(T)) devices[d][task] prob soc[0] 100 for t in range(1, T): prob soc[t] soc[t-1] charge[t-1] * 0.9 - discharge[t-1] / 0.9 for t in range(T): prob soc[t] 50 prob soc[t] 500 prob charge[t] 200 * (1 - discharge[t] / 200) # 避免同时充放 prob discharge[t] 200 * (1 - charge[t] / 200) prob soc[T-1] 100 # 日末回到初始SOC附近 solver pulp.PULP_CBC_CMD(msgTrue, timeLimit60) result prob.solve(solver) print(pulp.LpStatus[result]) print(总电费: %.2f元 % pulp.value(prob.objective))求解出来之后把P[d][t]按时间画成负荷曲线就能非常直观地看到调度策略的效果。正常情况下可调设备会倾向于在谷段多出力在峰段少出力甚至停机储能会在谷时充电、峰时放电整体用电曲线被压得“平”且“低”。3.3 大规模场景的启发式算法DEAP遗传算法怎么用PuLP的精确求解在设备数量少、时间段短的时候很好用但如果设备有上百台约束条件一复杂CBC求解器可能几分钟都算不出来。这时候就得换启发式算法。DEAP是Python生态里比较成熟的进化计算框架。用遗传算法做调度的基本思路是把一天96个时段的设备功率编码成一个个体用目标函数加上惩罚项来评估个体好坏然后不断做选择、交叉、变异逼近最优解。import random from deap import base, creator, tools, algorithms creator.create(FitnessMin, base.Fitness, weights(-1.0,)) creator.create(Individual, list, fitnesscreator.FitnessMin) def decode(individual): # individual按设备逐时段编码解码成P矩阵 return P_matrix def eval_schedule(individual): P decode(individual) total_cost 0 penalty 0 for t in range(T): load base_load[t] sum(P[d][t] for d in device_list) charge[t] - discharge[t] total_cost price[t] * load # 任务量约束惩罚 for d in device_list: task_actual sum(P[d][t] for t in range(T)) penalty 1000 * abs(task_actual - task_required[d]) # SOC越界惩罚 soc soc_init for t in range(T): soc soc charge[t] * 0.9 - discharge[t] / 0.9 if soc 0 or soc 500: penalty 10000 return total_cost penalty, toolbox base.Toolbox() toolbox.register(individual, tools.initRepeat, creator.Individual, random.uniform, nlen(devices) * T) toolbox.register(population, tools.initRepeat, list, toolbox.individual) toolbox.register(evaluate, eval_schedule) toolbox.register(mate, tools.cxBlend, alpha0.5) toolbox.register(mutate, tools.mutGaussian, mu0, sigma10, indpb0.05) toolbox.register(select, tools.selTournament, tournsize3) pop toolbox.population(n100) result_pop, log algorithms.eaSimple(pop, toolbox, cxpb0.7, mutpb0.2, ngen200, verboseTrue)遗传算法不保证最优但只要目标函数和惩罚项设得合理通常能在一个可接受的时间内找到“够好”的解。在这个项目里当设备数量超过20台时我们就会切到遗传算法方案。3.4 实测效果一个模拟场景省了多少电费调度算法开发完成后我们先把历史某一天的负荷数据重放了一遍跑对比实验一种是完全按原来现场的方式运行另一种是按调度建议运行。为了让对比公平生产任务总量设成完全相同天气、设备参数也都一致。结果非常有说服力。原始运行方式下全天总电费大约2.86万元加上预测和调度之后总电费降到2.42万元节省约15.4%。其中主要的降本来源有两个一是峰会时段的设备负荷被明显削低二是储能在谷时充电、峰时放电单靠峰谷价差就赚了不少。从负荷曲线看原始曲线在上午10点到12点出现一个很高的尖峰而调度后的曲线把这个尖峰削平了把一部分负荷挪到了下午和夜间。对电网来说这种“削峰填谷”的行为本身也有价值可以减少变压器扩容需求这是能源管理里被低估的收益。4. 系统集成与部署从Notebook走向生产环境4.1 用FastAPI把模型封装成服务模型和调度算法不能一直躺在Notebook里需要变成别人可以调用的服务。这里我用FastAPI封装了两个核心接口一个是负荷预测接口接收开始时间和预测步长返回未来负荷曲线另一个是调度接口接收预测结果和设备参数返回调度计划。FastAPI的好处是代码量少、自带OpenAPI文档、性能也不错。下面是一个预测接口的示例。from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class PredictRequest(BaseModel): start_time: str horizon: int 24 app.post(/predict) def predict_load(req: PredictRequest): features build_features_for_start(req.start_time, req.horizon) pred load_model.predict(features) return {start_time: req.start_time, load_forecast: pred.tolist()} class ScheduleRequest(BaseModel): base_load: list price: list device_config: dict app.post(/schedule) def schedule(req: ScheduleRequest): plan run_scheduling(req.base_load, req.price, req.device_config) return {schedule_plan: plan}这里有个工程细节模型文件比较大每次启动FastAPI都加载一遍很耗时间。解决办法是用lru_cache或者全局变量延迟加载让模型只加载一次后续请求直接复用。4.2 定时任务与数据更新让系统自己跑起来预测模型不是训练一次就完事的需要定期用新数据重新训练才能跟得上厂区用电行为的变化。我建议的更新节奏是每天凌晨2点用前一天的数据增量训练每周做一次全量重训。如果不想引入太重的任务编排框架Linux自带的crontab就能满足绝大多数场景。我一般这样安排定时任务# 每天凌晨2点执行增量训练和未来24h预测 0 2 * * * cd /opt/energy-mgmt /opt/miniconda3/envs/energy/bin/python scripts/daily_train.py logs/train.log 21 # 每天凌晨5点生成当天调度计划 0 5 * * * cd /opt/energy-mgmt /opt/miniconda3/envs/energy/bin/python scripts/daily_schedule.py logs/schedule.log 21如果后续要处理多工厂、多任务、失败重试这些更复杂的场景可以上Celery加Redis。但对于单厂区的项目crontab加Python脚本是最简单可靠的方案别为了架构好看而过度设计。4.3 Docker部署与资源控制Docker是这类项目的标配。把Python环境、依赖、代码打成一个镜像部署到新服务器上可以直接跑省去一堆环境配置的麻烦。下面是一份简单的Dockerfile。FROM python:3.10-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . RUN mkdir -p /app/logs EXPOSE 8000 CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000]构建和启动命令也很简单docker build -t energy-mgmt:latest . docker run -d --name energy-mgmt -p 8000:8000 \ -v /data/energy:/app/data \ -v /app/logs:/app/logs \ --memory4g --cpus2 \ --restartalways \ energy-mgmt:latest部署时有几个点要特别注意。一是内存限制LightGBM加载模型之后占内存不大但如果同时跑训练和预测建议把内存上限设到4GB以上防止OOM。二是数据卷挂载历史数据和模型文件要放到宿主机持久化目录否则容器一删数据全没了。三是日志容器内的应用日志一定要挂载到宿主机目录不然排障根本无从下手。5. 常见问题与排查技巧实录5.1 预测不准先怀疑数据再怀疑模型项目上线后遇到最多的投诉就是“今天预测怎么差这么多”。排查这类问题我有一套固定的思路。第一步看数据质量。如果是当天凌晨的预测看最近几小时的数据有没有缺失或异常。厂里电表偶尔会断网数据不上报这时候模型拿到的是残缺的近期序列预测值自然不靠谱。解决方法是数据链路加一个完整性检查发现缺失率超过阈值就告警而不是静默地往下走。第二步看业务变化。厂里临时接了新产线、天气突然高温、订单暴增导致加班这些都会让当天的负荷偏离历史规律。遇到这种情况别说模型人拍脑袋也预测不准。所以系统里一定要有人工修正机制让站长可以手工上传第二天的生产安排作为附加特征送进模型。第三步才轮到看模型。如果连续一周的偏差都稳定在一个方向上比如每天预测值都偏高那大概率是模型有偏置需要用最新数据重训。我们的系统里专门做了一个每日回测任务自动计算滚动MAE超过阈值就在企业微信群里推送提醒。5.2 调度无解或超时别死磕精确解调度模块上线初期CBC求解器在设备数量少的时候很快但后来把光伏、储能、多套产线都加进来约束条件一多偶尔会出现求解超时甚至无解的情况。无解的常见原因是约束条件之间互相冲突比如要求设备在某个时段必须停机同时又要求全天的产量必须达到一个很高的值这两个约束在数学上就矛盾了。排查方法是把所有约束逐条注释掉重新求解用二分法定位是哪个约束组导致的冲突。超时的原因是搜索空间太大。应对策略有两个一是缩小决策粒度把15分钟一个时段改成1小时一个时段决策点从96个降到24个求解速度会提升很多但代价是调度精度下降二是采用滚动优化只用精确求解器算未来4小时每15分钟滚动一次兼顾速度和精度。5.3 部署层那些坑部署阶段踩过不少小坑最典型的几个第一个是时区问题。服务器默认时区是UTC数据库存的时间戳也是UTC但现场电表上报的是北京时间。如果系统内部没有约定统一用带时区的时间戳预测接口出来的时间轴就会整体偏8个小时。我们的解决办法是数据库和API全部统一用ISO 8601带时区格式只在前端展示时转成本地时间。第二个是依赖版本问题。LightGBM对numpy版本有一定要求新版本numpy可能导致LightGBM导入报错。解决方法是把requirements.txt里的主要依赖版本锁定别随便升级。第三个是接口超时。第一次调用调度接口时如果遗传算法要跑200代接口可能会等很久。前端如果设置了超时时间很容易直接报错。解决办法是把调度结果缓存或者改成异步任务前端轮询获取结果。5.4 避坑清单速查表问题现象根因解决方案预测值整体偏高连续多日MAPE偏大模型未及时重训增加每日增量训练节假日预测翻车长假前后偏差极大仅用0/1节假日特征增加距假期天数特征调度求解超时接口响应超过10秒决策变量太多用滚动优化或遗传算法调度无解求解器返回infeasible约束互相冲突逐条注释约束定位冲突时序错位预测曲线整体平移时区未统一统一使用带时区时间戳模型打开报错导入LightGBM失败numpy版本不兼容锁定依赖版本后来我把这套避坑清单打印出来贴在工位上团队里新同学排查问题时基本都是先拿着清单过一遍省了很多无效沟通的时间。最后分享几点个人体会。第一能源管理项目的成败百分之六十取决于数据质量模型反而其次。数据链路不稳定后面的预测和调度做得再漂亮都是空中楼阁。第二不要一上来就做大而全的调度优化先把预测做准让客户看到预测曲线有参考价值再慢慢加上调度建议落地阻力会小很多。第三这类系统最不值得炫耀的其实是算法真正难得的是让现场操作人员愿意用。系统做完之后我去现场看师傅们的使用情况发现他们最关心的不是曲线好不好看而是“今天哪个时段别开空压机”能不能一句话说清楚。所以后来我把调度建议从各种图表改成了一张非常直白的时间表几点到几点哪些设备停绿色表示开、灰色表示停。这个改动上线三个月厂里才真正形成了按调度计划执行的习惯。技术上的事都可以学但这个“让系统接地气”的坎是我在这个项目里收获最大的一点。
返回列表