尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

电工杯数模备赛:赛题预测、建模思路与可复现代码全攻略

发布时间:2026/9/24 19:48:49

资讯中心
01
ARTICLE

电工杯数模备赛:赛题预测、建模思路与可复现代码全攻略

电工杯数模备赛:赛题预测、建模思路与可复现代码全攻略
每年5月电工杯数学建模竞赛的通知刚挂出来备赛群基本就炸了刷屏的内容永远是三样赛题预测、完整思路、能直接跑的代码。作为一个连续带过三届电工杯的老选手我很清楚大家真正慌的不是“不会用模型”而是拿到赛题那一刻手忙脚乱——不知道从哪下手、不知道代码写到什么程度算够、更不知道论文和代码怎么对得上。这篇内容就围绕这几个核心痛点展开从赛题预判、建模思路到可复现代码一次性讲透。这篇内容适合三类人看第一类是第一次参加电工杯、连AB题题型都没摸清的新手建议从头到尾读一遍把框架接住第二类是已经做过一两次数模、但想冲更高奖项的队伍重点看第2章的思路拆解和第3章的代码写法第三类是只需要“临时抱佛脚”的队伍可以直接跳到第4章把自己最容易踩的坑提前避掉。1. 先看战斗规则2026电工杯的赛题趋势预判1.1 “全网最全”到底全在哪很多人以为“全网最全”就是资料包里有几百篇优秀论文、几十G的代码仓库但我带赛这几年后的体会是资料堆得再多拿到赛题时该卡还是卡。真正的“全”应该是把备战路径上的每一个环节都覆盖到——赛题预测、数据预处理、建模思路、代码模板、论文写作、评阅偏好缺一坏一环最后都会吃亏。所以这篇文章的结构很明确先讲2026年大概率考什么方向这是战略层再讲拿到题后怎么拆解AB题思路这是战术层然后给出一套可以直接改改就用的代码框架这是执行层最后把我在实际比赛里踩过的坑整理成清单这是保分层。四层叠起来才算对得起“最全”这两个字。关于电工杯和其他数学建模竞赛的区别我得单独说一句它和国赛、华为杯都不太一样电工杯的主办方更偏向电气工程领域赛题经常跟电力系统、新能源、电机控制、智能电网这些场景深度绑定。你如果照搬国赛那套通用建模套路很可能在数据理解和模型落地上吃亏。反过来如果你懂一点电气背景在赛题解读上会有天然优势。1.2 AB题的常见方向与出题逻辑电工杯的赛题通常分A、B两题A题偏数据驱动B题偏运筹优化这个格局已经延续了好多年2026年延续下来的概率极高。A题常见的题材是光伏出力预测、风电功率预测、负荷预测这类“给历史数据、建预测模型”的问题B题则偏爱机组组合优化、检修计划安排、储能调度、电力市场竞价这类“给约束条件、求最优决策”的问题。这两种题型的考察逻辑完全不同。A题说白了比的是“特征工程模型调优”数据是唯一的出发点你的模型精度决定了你的得分下限B题比的是“数学建模能力求解技巧”你要把现实问题抽象成数学表达式还要能让求解器算得动、算得快、算得出合理结果。很多人把这两类题混在一起准备最后两头都没顾上。从我这些年的观察来看电工杯出题有一个隐性的特点即使是同一个方向每年都会融入一些当年的热点。2026年如果延续规律AI大模型、新型电力系统、虚拟电厂、碳交易这类的关键词大概率会出现在背景描述里。但注意这些只是“包装”核心建模任务还是脱不开预测和优化这两大块不要被花哨的背景吓到。1.3 2026年AB题的预测支点先说预测依据我翻了过去几年的赛题走向A题几乎都是“数据时序预测”的结构D题方向越来越偏向新能源消纳和电力系统经济调度。2026年的A题我预判大概率围绕“分布式光伏出力预测”或者“区域负荷短期预测”展开数据形式通常是按15分钟或1小时间隔的时间序列附带天气、温度、湿度等外部特征B题则大概率是一个“源网荷储协同优化”的决策问题可能是包含储能系统的机组组合也可能是考虑需求响应的调度优化。不过说实话在题目真正放出来之前谁都没法100%押中我心里很清楚预测只是“概率事件”。所以我不打算只给一个答案而是给你一套能迁移的解法只要A题是带时间的回归问题套用第2章的数据预测框架就行只要B题是带约束的决策问题就用第3章的整数规划框架去打。这也是我带队这么多年实践下来最稳的做法——靠框架取胜不靠押题取胜。2. 拿到赛题后的完整建模路线2.1 A题数据驱动的电气场景预测如果2026年A题又是预测类问题那恭喜你这类题的套路是最好复用的。拿到数据后的第一件事不是急着训练模型而是先做数据体检时间范围是什么、时间间隔是多少、有没有缺失值、有没有明显异常值、特征之间有没有强共线性。很多队伍一上来就跑模型结果数据里全是空洞和离群点模型精度自然上不去后面再怎么调参都白搭。数据体检之后核心工作就落在特征工程上。以光伏出力预测为例除了原始的时间戳和出力值我通常会构建这三类特征第一类是时间特征比如小时、星期、是否节假日因为光伏出力受光照周期影响明显第二类是滞后特征用过去1小时、24小时的出力值作为新的自变量让模型看到“历史状态”第三类是滚动统计特征比如过去3小时的滑动平均、滑动标准差用来刻画短期内出力的变化趋势。这三类特征加进去模型精度的提升是肉眼可见的。模型选型上我推荐你按“基线到进阶”的顺序去做。基线模型用线性回归或者决策树先把整套流程跑通拿到一个能接受的分数进阶模型用XGBoost或者LightGBM在特征工程做扎实的基础上这两个模型通常能拿到很不错的效果如果时间充裕再叠加一个简单的时间序列模型比如ARIMA做对比。不要一上来就上深度学习样本量不够时LSTM很容易过拟合反而拖后腿。评价指标也要提前想清楚。电气场景预测常用的指标有RMSE、MAE、MAPE其中RMSE对大的误差点更敏感MAPE则要考虑实际值是否接近0。如果题目问“预测精度达到多少”你必须在论文里写清楚用了什么指标、怎么计算的最好附上公式和代码输出截图评阅老师很喜欢看到这种细节。2.2 B题运筹优化与决策模型B题的难点不在“用什么算法”而在“怎么把题目翻译成数学语言”。以机组组合问题为例题目会给你若干台机组的参数最大最小出力、爬坡速率、启动成本、运行成本然后让你安排未来24小时每台机组的启停状态和出力大小目标是总成本最低同时要满足负荷平衡、备用容量、机组出力上下限等一系列约束。解题的第一步是明确三要素决策变量是什么、目标函数是什么、约束条件是什么。决策变量一般有两类一类是0-1变量表示机组开还是不开一类是连续变量表示机组出多少电。目标函数就是把所有成本加起来约束条件则要一条条从题目里抠出来写清楚。这一步做完建模工作其实就完成了一大半。求解方式上我强烈建议先尝试精确求解也就是用混合整数线性规划MILPPython里可以直接用Pulp或者OR-Tools来建模。很多同学一听“整数规划”就发怵但实际上Pulp的语法非常友好半小时就能上手。精确解的优点是结果有最优性保证评委看了也认可。只有当问题规模实在太大、求解时间太久的时候才考虑用遗传算法、粒子群这类启发式算法而且要用的时候必须说明为什么精确解不可行。这里要特别提醒一个很多队伍都会犯的错B题不是把模型建完就结束了一定要做敏感性分析或者方案对比。比如需求上调10%后成本变化多少、储能容量增加后总成本下降多少这些分析才是论文拿高分的加分项因为它能证明你的模型不仅能用还能指导决策。2.3 拿到赛题后的前三小时决策表很多队伍输在起跑线上拿到赛题后三个人围在一起读了仨小时题讨论了半天方向结果第一天啥也没干出来。我带队的时候规定拿到题目后的前三小时必须按固定流程走谁负责什么都提前分工好。具体安排是这样的——第一个小时三个人各自快速通读两题然后分别写一段“我认为A题在考什么、B题在考什么”的简短分析互相对齐认知第二个小时确定选题然后立即把任务拆解为数据负责人、建模负责人、论文负责人三条线数据负责人马上去看数据文件的结构和完整度建模负责人开始画模型草图论文负责人把摘要框架、目录结构、题目关键词全部搭好第三个小时全队开一个短会确认建模方向、定下第一版算法选型然后开始写第一个能跑的基线代码。这个流程看起来很机械但实测下来非常管用。它最大的价值不是让每个人都忙起来而是确保队伍在“方向认知”上尽早达成一致避免出现后面写着写着发现建模和数据对不上、论文和结果对不上的大返工。3. 可直接复用的核心代码实现3.1 A题基线数据清洗与特征工程先把A题的数据处理代码给你一套。下面这个例子假设你已经有一份CSV文件包含时间列和出力列外加一些气象特征。第一步是读数据、看结构、补缺失值。import pandas as pd import numpy as np # 读取数据 df pd.read_csv(train.csv, parse_dates[time]) df df.sort_values(time).reset_index(dropTrue) # 缺失值检查 print(df.isnull().sum()) # 时间序列缺失处理先线性插值再向前填充兜底 df[power] df[power].interpolate(methodlinear, limit_directionboth) df[temp] df[temp].fillna(methodffill) # 异常值处理用3sigma原则清洗 mean_p df[power].mean() std_p df[power].std() df df[(np.abs(df[power] - mean_p) 3 * std_p)] # 构造时间特征 df[hour] df[time].dt.hour df[weekday] df[time].dt.weekday df[is_weekend] (df[weekday] 5).astype(int)这段代码有三个细节值得说。第一缺失值处理选择线性插值而不是直接删行是因为电力负荷数据通常存在很强的连续性插值能保留时间序列的走势第二异常值用3σ规则处理适合大多数分布比较均匀的预测场景如果数据有明显的周期性可以考虑分时间段分别计算均值和标准差第三时间特征里hour这个特征对光伏、负荷预测都是非常重要的因为它直接捕捉了昼夜规律。数据清洗完再构造滞后特征和滚动特征。这里要注意滞后窗口的选取光伏预测常用24小时、48小时这样的日周期滞后负荷预测常用1小时、24小时、168小时一周的滞后。# 构造滞后特征 df[lag_1h] df[power].shift(1) df[lag_24h] df[power].shift(24) df[lag_168h] df[power].shift(168) # 构造滚动统计特征 df[rolling_mean_3h] df[power].rolling(window3).mean() df[rolling_std_3h] df[power].rolling(window3).std() # 删除构造特征产生的空值 df df.dropna().reset_index(dropTrue) # 特征列与标签列 feature_cols [hour, weekday, is_weekend, temp, lag_1h, lag_24h, lag_168h, rolling_mean_3h, rolling_std_3h] X df[feature_cols] y df[power] # 按时间顺序切分避免随机切分造成的数据泄露 split_idx int(len(df) * 0.8) X_train, X_test X.iloc[:split_idx], X.iloc[split_idx:] y_train, y_test y.iloc[:split_idx], y.iloc[split_idx:]这里最容易被忽略的是“按时间顺序切分”这一点。如果你用train_test_split随机打乱数据模型相当于偷看了未来的信息测试集上的精度会虚高比赛阅卷时很容易被打回。这个问题我见过的次数太多了一定要留意。3.2 A题进阶XGBoost预测模型特征准备好以后直接上XGBoost。下面这个代码是完整的训练预测评估流程赛场上可以直接改路径、改列名后运行。import xgboost as xgb from sklearn.metrics import mean_squared_error, mean_absolute_error model xgb.XGBRegressor( n_estimators300, max_depth5, learning_rate0.05, subsample0.8, colsample_bytree0.8, random_state42 ) model.fit(X_train, y_train) y_pred model.predict(X_test) rmse mean_squared_error(y_test, y_pred, squaredFalse) mae mean_absolute_error(y_test, y_pred) mape np.mean(np.abs((y_test - y_pred) / y_test)) * 100 print(fRMSE: {rmse:.4f}) print(fMAE: {mae:.4f}) print(fMAPE: {mape:.2f}%)参数上我给的是比较稳妥的默认组合。max_depth设成5是因为电力数据特征量不大太深容易过拟合learning_rate设成0.05配合300棵树训练速度快精度也能保证。实测下来这个组合在绝大多数电气负荷和光伏数据上表现都不差。如果比赛中时间紧张不需要做太复杂的调参优先用网格搜索粗调两个参数就够。from sklearn.model_selection import GridSearchCV param_grid { max_depth: [3, 5, 7], n_estimators: [200, 300] } gs GridSearchCV( xgb.XGBRegressor(learning_rate0.05, random_state42), param_grid, cv3, scoringneg_mean_squared_error ) gs.fit(X_train, y_train) print(gs.best_params_)注意这里交叉验证用的是K折但如果你用普通的KFold而不是TimeSeriesSplit在时间序列上仍然可能有轻微泄露。好在XGBoost这类树模型对轻微泄露不敏感影响不大。如果你用的是LSTM这种强时序模型就必须用TimeSeriesSplit了。3.3 B题用Pulp求解整数规划B题我拿一个简化版的“机组组合”来演示怎么用Pulp建模。假设有3台机组要安排未来24小时每小时的总出力最小化发电成本同时满足每小时的负荷需求。import pulp as lp # 数据定义 hours range(24) units [0, 1, 2] # 机组参数最大出力、最小出力、单位发电成本、启动成本 P_max {0: 100, 1: 80, 2: 60} P_min {0: 20, 1: 15, 2: 10} cost {0: 50, 1: 60, 2: 70} start_cost {0: 100, 1: 80, 2: 50} # 负荷需求 load [80, 82, 85, 90, 95, 100, 110, 120, 130, 135, 140, 145, 150, 145, 140, 135, 130, 125, 120, 110, 105, 95, 90, 85] # 创建问题 prob lp.LpProblem(Unit_Commitment, lp.LpMinimize) # 决策变量 p lp.LpVariable.dicts(power, (units, hours), lowBound0) u lp.LpVariable.dicts(unit_on, (units, hours), catBinary) v lp.LpVariable.dicts(start_up, (units, hours), catBinary) # 目标函数运行成本 启动成本 prob lp.lpSum(cost[i] * p[i][t] for i in units for t in hours) \ lp.lpSum(start_cost[i] * v[i][t] for i in units for t in hours) # 约束1功率上下限 for i in units: for t in hours: prob p[i][t] P_max[i] * u[i][t] prob p[i][t] P_min[i] * u[i][t] # 约束2每小时负荷平衡 for t in hours: prob lp.lpSum(p[i][t] for i in units) load[t] # 约束3启动变量逻辑本时段开机且上一时段关机才计一次启动 for i in units: for t in hours: if t 0: pass else: prob v[i][t] u[i][t] - u[i][t-1] # 求解 prob.solve() # 输出结果 print(fStatus: {lp.LpStatus[prob.status]}) print(fTotal Cost: {lp.value(prob.objective):.2f})这段代码虽然做了很多简化但完整的机组组合框架已经成型。实际比赛里你只需要把机组数量改成几十台、把约束补上爬坡约束、最小启停时间、备用容量约束代码结构不用动。Pulp的解算速度在小规模问题上非常快几十台机组24小时的规模也就是几秒钟的事。值得多说一句的是很多队伍的B题代码会遇到“求解器跑不出来”的情况。如果Pulp默认的CBC求解器太慢可以换Gurobi或SCIPPulp只需要指定solver参数就行。但Gurobi需要许可证比赛前最好提前在队伍电脑上配好。3.4 可视化让论文一眼看懂代码能跑通只是第一步评委看论文的时候第一眼扫过的是图表而不是公式。所以可视化至少要完成三件事画数据分布、画预测效果、画优化结果。import matplotlib.pyplot as plt # A题预测值与真实值对比 plt.figure(figsize(12, 4)) plt.plot(y_test.values, labelTrue, linewidth1) plt.plot(y_pred, labelPredict, linewidth1, alpha0.7) plt.legend() plt.title(A题预测效果对比) plt.xlabel(样本序号) plt.ylabel(功率 (MW)) plt.savefig(a_forecast.png, dpi150, bbox_inchestight) plt.show()B题可视化最常见的是把每台机组的出力画成堆叠面积图或者画机组启停状态的甘特图。记住一点图不是越炫越好而是越容易读懂越好。评委看一张图能立刻get到你的结论这张图就是成功的。4. 常见问题与避坑实录4.1 数据预处理阶段的常见坑第一坑时间戳解析失败。中文日期格式比如“2026/5/15 8:00”在pandas的read_csv里大概率会被读成字符串你需要手动指定parse_dates和日期格式否则后面的滞后特征全部错位。用pd.to_datetime(df[time], format%Y/%m/%d %H:%M)强制转换一次一劳永逸。第二坑缺失值处理策略一刀切。有些同学看到空值就全部用0填充这在电气数据里很致命。光伏夜间出力本来就是0白天突然灭成0那叫故障。我建议分情况短时间连续缺失用插值长时间大段缺失考虑剔除气象特征缺失可以用前一天同时刻的数据填充。没有固定模板一定要先看数据再选策略。第三坑特征泄露。构造lags和rolling特征时如果没有shift或rolling操作不当容易把当前时刻的信息混进特征里造成数据泄露。判断方法很简单特征里任何一行如果“用到了自己那一行的目标值”就是泄露了。在训练测试划分之前反复检查。4.2 代码运行与调试的实用经验比赛中最崩溃的时刻不是模型不会建而是代码报错找不到原因。我分享一个很笨但很有效的排查方法把错误信息复制下来逐行读报错堆栈先找“最后一行是你自己代码”的位置那基本就是错误根源。电气方向的同学经常遇到Python环境问题。今天缺numpy明天缺sklearn比赛现场又没有网非常麻烦。建议赛前用pip freeze requirements.txt把当前环境依赖固定下来同时在U盘里备份一个离线安装包或者直接用conda创建完整环境。另外很多人不知道“代码诊断插件”这类工具在跑数模代码时也能派上用场。遇到CtrlC、CtrlV别人的代码后运行报错的情况插件能帮你快速定位到语法错误和重复定义这类低级问题。不过我的建议是别人的代码最好自己手打一遍碰到问题能加深理解纯复制粘贴到赛场上是跑不通的。B题求解器报错的频率也不低常见提示是“no solution found”。这时候不要慌有50%的可能是约束条件写错了导致可行域为空还有50%的可能是问题本身规模太大一时半会儿解不出来。先检查约束有没有相互矛盾再尝试松弛部分约束、加一个松弛变量输出一个带惩罚项的目标函数往往就能解出来。4.3 论文与代码一致性决定得分上限的细节电工杯的评审流程中评委虽然主要看论文但代码如果有明显问题奖项等级会受影响。我带赛时一直强调一个原则论文里出现的每一个数字都必须能在代码输出结果里找到来源。很多队伍论文写得天花乱坠结果评委一问或者一看附录代码跑出来的图跟论文里的图对不上这种低级失分会非常可惜。所以建议这样做每跑出一个关键结果立刻截图或导出为CSV保存并标注好是哪一次运行的结果论文里所有表格数据都从这些输出文件里取不要手动改数。手动改数这件事绝对不要做一是评委可能会复现二是自己后续改需求时数据会对不上。附录代码部分不用贴全部代码但要把核心模型的代码放进去并加注释说明“这是XX模型的训练代码”“这是XX约束的实现”。评委翻到附录时能快速找到对应代码对你建模工作的信任度会高很多。最后再分享一个我自己的习惯每次比赛最后半天我一定抽出一个小时干一件事把从数据读取到最终结果输出的完整流程从头到尾再跑一遍确保换一台电脑、只用一份文档也能复现。这个习惯救过我很多次——有一回提交前发现训练脚本里写死了本地路径提交到服务器直接报错就因为提前跑了一遍才及时发现。你赛场上不一定遇到同样的问题但“可复现”这三个字在电工杯的评分体系里真的比想象中重要。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。