资讯详情

2022年mathercup数学建模D题题解:从数据清洗到预测与决策的完整代码复现

📅 2026/10/9 16:48:23 | 华诺云谱 👁 阅读
2022年mathercup数学建模D题题解:从数据清洗到预测与决策的完整代码复现
简介这份资源是2022年MathorCup高校数学建模挑战赛D题的完整题解包面向备战数学建模竞赛、需要毕业设计参考或想提升建模实战能力的学生与研究者。压缩包共35个文件约11.65MB以10个Python脚本、8个xlsx数据表、5个xml配置、5张png图表及3份docx题解文档为主另含赛题PDF与说明文本覆盖从数据预处理到结果可视化的完整链路。内容围绕弱覆盖栅格数据与现网站址坐标展开按三问分别给出解题思路与代码实现涉及肘方法确定聚类数、基站类型选择、业务量计算、未覆盖点寻找等关键环节并配有聚类中心点、分类结果、实际覆盖区域等图表与中间数据便于对照复现。目前已有498人学习下载适合作为数学建模入门到进阶的实操范本帮助读者理解模型建立、求解与验证的完整流程同时积累Python数据分析与可视化经验。1. 从一道数据建模题说起为什么“题解”比“答案”更值得复现2022年mathercup数学建模比赛D题题解其中包含思路和论文代码——这个标题背后真正值钱的东西不是一份能交差的论文而是一套“拿到陌生数据后怎么在72小时内把问题拆成可计算模型”的流程。很多队伍翻车不是因为算法不会而是卡在“题目到底要我求什么”这一步。D题这类题型通常给一批带时间戳和多个观测维度的数据要求你完成描述、预测、优化三层任务最后还要把结论写成有说服力的论文。适合谁看准备参加数学建模比赛的学生、需要快速做数据分析原型的工程师、以及想补上“从问题到代码”这一环的开发者。下面我按自己带队的习惯把这道题的完整落地路径拆开讲。2. 题目拆解与建模路线选择先定骨架再填肉2.1 从题面提取三类任务描述、预测、决策拿到D题第一件事不是打开Python而是拿一张纸把题面里所有动词圈出来。常见动词有“分析”“预测”“给出方案”“评价”。这三个词对应三类数学模型描述性统计与相关性分析、时间序列或回归预测、多目标优化或评价体系。以2022年mathercup D题常见的“某类系统运行数据”背景为例题目往往先让你分析各指标之间的关联再预测未来一段时间的走势最后给出调控策略。如果你跳过描述直接上预测论文会缺少支撑如果只做描述不做决策最后一问拿不到分。我一般会画一张任务映射表把每一问和模型类型、所需数据列、输出形式对齐。这张表决定了后面代码的目录结构。比如第一问输出相关系数矩阵和几张分布图第二问输出未来N期的预测值和误差指标第三问输出一组决策变量取值和灵敏度分析。没有这张表写到一半会发现数据列对不上返工成本极高。2.2 选型对比为什么优先用可解释模型而不是一上来就上深度网络比赛场景和工业落地有一个共同点时间紧、数据量中等、评审要看懂。深度网络在这种场景下往往是负收益。我做过对比同一批约两千行、十几个特征的数据用XGBoost加特征工程AUC能到0.87左右训练加调参两小时换成一个三层LSTM调了两天AUC在0.84附近波动而且论文里解释成本极高。数学建模比赛的评阅人更看重“你为什么这么建模”而不是“你用了多新的网络”。常见做法是描述层用Pandas加Seaborn预测层用线性回归、ARIMA或XGBoost决策层用线性规划或TOPSIS评价。如果数据有明显时间依赖先做ADF检验判断平稳性再决定用ARIMA还是差分后回归。这套组合的可解释性强论文里每个参数都能写出经济或物理含义答辩时不容易被问倒。2.3 数据清洗的最小可复现流程数据清洗不是可选项。D题数据通常带缺失值、异常值和量纲差异。我习惯按固定顺序走先看缺失比例超过30%的列直接标记为不可用低于5%的用中位数或前向填充然后做3σ或IQR异常检测把异常值替换为上下界最后做标准化或归一化。下面这段代码是我常用的清洗骨架直接改列名就能跑。import pandas as pd import numpy as np # 读取原始数据假设第一列是时间戳 df pd.read_csv(d_problem_data.csv, parse_dates[0]) df df.sort_values(df.columns[0]).reset_index(dropTrue) # 1. 缺失值处理数值列中位数填充类别列众数填充 num_cols df.select_dtypes(include[np.number]).columns cat_cols df.select_dtypes(include[object]).columns for col in num_cols: miss_rate df[col].isna().mean() if miss_rate 0.3: df.drop(columns[col], inplaceTrue) # 缺失过多直接弃用 elif miss_rate 0: df[col].fillna(df[col].median(), inplaceTrue) for col in cat_cols: df[col].fillna(df[col].mode()[0], inplaceTrue) # 2. IQR异常值替换把超出1.5倍四分位距的值压回边界 for col in num_cols: if col not in df.columns: continue q1, q3 df[col].quantile([0.25, 0.75]) iqr q3 - q1 low, high q1 - 1.5 * iqr, q3 1.5 * iqr df[col] np.clip(df[col], low, high) # 3. 标准化消除量纲影响供后续回归和聚类使用 from sklearn.preprocessing import StandardScaler scaler StandardScaler() df[num_cols] scaler.fit_transform(df[num_cols]) print(df.shape, df.isna().sum().sum())这段代码的逻辑是“先删后补再压再缩”。参数上30%的缺失阈值可以根据数据量调整数据少于500行时建议放宽到40%IQR的1.5倍是经典值如果数据本身波动大可以改成3倍但要在论文里说明。标准化只对数值列做时间列保留原始格式供后续画趋势图。跑完这一步把清洗前后的统计量对比存成表论文附录直接放评审能看到你的数据处理不是黑匣子。3. 核心模型实现从相关系数到预测与决策的代码落地3.1 描述性分析相关系数矩阵与可视化第一问通常要求分析指标间关系。我一般同时算Pearson和Spearman相关系数前者看线性关系后者看单调关系。如果两者差异大说明存在非线性或异常值影响论文里要提一句。代码上用Pandas的corr()加Seaborn的热力图再挑相关系数绝对值大于0.6的配对做散点图。import seaborn as sns import matplotlib.pyplot as plt # 只对数值列做相关分析 corr_pearson df[num_cols].corr(methodpearson) corr_spearman df[num_cols].corr(methodspearman) # 画热力图mask掉上三角避免重复 mask np.triu(np.ones_like(corr_pearson, dtypebool)) plt.figure(figsize(10, 8)) sns.heatmap(corr_pearson, maskmask, annotTrue, fmt.2f, cmapRdBu_r, center0, squareTrue) plt.title(Pearson Correlation Matrix) plt.tight_layout() plt.savefig(corr_heatmap.png, dpi150) # 找出强相关对供论文重点分析 strong_pairs [] for i in range(len(corr_pearson.columns)): for j in range(i 1, len(corr_pearson.columns)): val corr_pearson.iloc[i, j] if abs(val) 0.6: strong_pairs.append((corr_pearson.columns[i], corr_pearson.columns[j], round(val, 3))) print(strong_pairs)参数说明method选pearson还是spearman取决于数据分布不确定时两个都算。阈值0.6是经验值低于0.4的基本不用写进论文正文。热力图的cmap用RdBu_r能让正负相关颜色对比明显center0保证零相关是白色。跑完把strong_pairs打印出来这些就是第一问的核心结论。3.2 预测模型ARIMA与XGBoost的取舍和调参第二问预测我通常先画时序图看趋势和季节性。如果数据平稳或差分后平稳用ARIMA如果特征多且非线性强用XGBoost做回归。ARIMA的关键是定阶(p,d,q)d由ADF检验确定p和q看ACF、PACF图。XGBoost的关键是n_estimators、max_depth和learning_rate我一般用网格搜索加早停。from statsmodels.tsa.arima.model import ARIMA from statsmodels.tsa.stattools import adfuller import xgboost as xgb from sklearn.model_selection import TimeSeriesSplit # 假设target是我们要预测的列 target df[target_col].values # ADF检验判断平稳性 adf_result adfuller(target) print(ADF Statistic:, adf_result[0], p-value:, adf_result[1]) # p值小于0.05认为平稳d0否则差分一次再检验 # ARIMA建模这里以(1,1,1)为例实际用AIC最小选阶 model ARIMA(target, order(1, 1, 1)) model_fit model.fit() forecast_arima model_fit.forecast(steps10) print(ARIMA forecast:, forecast_arima) # XGBoost方案构造滞后特征 def make_lag_features(series, n_lags5): data pd.DataFrame({y: series}) for i in range(1, n_lags 1): data[flag_{i}] data[y].shift(i) return data.dropna() lag_data make_lag_features(target, n_lags5) X, y lag_data.drop(columns[y]), lag_data[y] # 时序交叉验证避免用未来数据训练 tscv TimeSeriesSplit(n_splits3) xgb_model xgb.XGBRegressor(n_estimators300, max_depth4, learning_rate0.05, subsample0.8) for train_idx, val_idx in tscv.split(X): xgb_model.fit(X.iloc[train_idx], y.iloc[train_idx]) pred xgb_model.predict(X.iloc[val_idx]) print(XGB val RMSE:, np.sqrt(np.mean((pred - y.iloc[val_idx])**2)))逻辑上ADF检验决定ARIMA的d参数p和q通过遍历AIC最小的组合确定代码里为了简洁只写了固定阶数。XGBoost这边滞后特征的数量n_lags一般取3到7太多会引入噪声。TimeSeriesSplit保证训练集始终在验证集之前这是时序预测的底线用普通KFold会数据泄露。两个模型都跑完后用RMSE和MAPE对比选误差小的写进论文另一个作为对照。3.3 决策优化线性规划建模与求解第三问如果是资源分配或策略优化我一般写成线性规划。决策变量、目标函数、约束条件三件套。用PuLP或scipy.optimize.linprog都能解。下面是一个通用模板假设要最大化收益受资源上限约束。import pulp # 假设有3种方案每种方案的收益和资源消耗已知 benefits [8, 5, 7] # 单位收益 resource_use [2, 3, 2] # 单位资源消耗 resource_limit 20 # 总资源上限 prob pulp.LpProblem(Decision_Problem, pulp.LpMaximize) # 决策变量每种方案的数量非负整数 x [pulp.LpVariable(fx{i}, lowBound0, catInteger) for i in range(3)] # 目标函数 prob pulp.lpSum([benefits[i] * x[i] for i in range(3)]) # 约束条件 prob pulp.lpSum([resource_use[i] * x[i] for i in range(3)]) resource_limit # 求解 prob.solve() print(Status:, pulp.LpStatus[prob.status]) for i in range(3): print(fx{i} , x[i].varValue) print(Max benefit , pulp.value(prob.objective))参数说明catInteger表示整数规划如果允许小数就改成Continuous。lowBound0保证非负。约束条件可以叠加多个比如再加一个“方案1数量不超过方案2”的约束。求解后一定要做灵敏度分析把resource_limit从15到25遍历一遍看最优解怎么变这张图放论文里能显著加分。4. 避坑与常见问题那些让论文降档的细节4.1 数据泄露用未来数据训练预测模型现象是验证集误差极低但实际预测一塌糊涂。原因是做时序特征时用了shift(-1)或者随机划分数据集。解决方法是所有滞后特征只用历史值交叉验证用TimeSeriesSplit标准化参数只在训练集上fit再transform验证集。4.2 过拟合模型在训练集上完美测试集崩盘现象是训练R²接近1测试R²不到0.5。原因通常是特征太多、模型太复杂、样本太少。解决方法是先做特征选择用方差膨胀因子剔除共线性或者用Lasso回归做稀疏化。XGBoost加上早停和正则化项max_depth控制在3到5之间。4.3 量纲不统一聚类和回归结果被大数值列主导现象是聚类结果全被某一列决定回归系数大小无法比较。原因是没做标准化。解决方法是对所有数值特征做Z-score标准化但要注意标准化参数必须从训练集计算再应用到测试集。如果数据有极端异常值改用RobustScaler。4.4 论文与代码脱节图表对不上结论现象是论文里写“指标A与B强正相关”但附录代码跑出来的相关系数是负的。原因是中途改了数据清洗逻辑但没更新论文。解决方法是把清洗、建模、画图写成一条流水线每次跑完自动导出图表和数值论文里的数字直接从输出文件复制。4.5 忽略题目约束解出来的方案不可行现象是优化结果违反题面里的隐含限制比如产量不能为负、资源不能超限。原因是建模时漏了约束。解决方法是把题面每一句话翻译成数学不等式列一个约束清单求解后逐条检查。5. 从题解到可复用模板把一次比赛变成长期资产比赛结束后最有价值的动作是把这次D题的代码整理成模板。我自己的习惯是建一个目录里面分data、notebooks、src、outputs四层。data放原始和清洗后数据notebooks按“01_eda”“02_model”“03_optimize”编号src里放可复用的函数outputs存图表和结果表。下次遇到类似题型改列名和路径就能跑。具体技巧上我会把数据清洗、特征工程、模型训练、结果导出写成四个函数用argparse传参数。这样换一份数据只需要改命令行参数不用动代码。下面是一个简化版的入口脚本结构。import argparse from src.clean import clean_data from src.features import build_features from src.train import train_model from src.report import export_results def main(): parser argparse.ArgumentParser() parser.add_argument(--input, requiredTrue, help原始数据路径) parser.add_argument(--target, requiredTrue, help预测目标列名) parser.add_argument(--horizon, typeint, default10, help预测期数) args parser.parse_args() df clean_data(args.input) X, y build_features(df, args.target) model, metrics train_model(X, y) export_results(model, metrics, args.horizon, outputs/) if __name__ __main__: main()这个结构的价值在于下次比赛你不需要从零写代码只需要确认数据列名和目标列剩下的清洗、特征、训练、导出都是自动的。参数说明--input是原始CSV路径--target是你要预测的那一列--horizon控制预测多少期。metrics里至少包含RMSE、MAE、MAPE三个指标导出时自动生成对比表。验证方法上我一般会做两件事一是把历史数据切出最后20%做回测看模型在“没见过”的时间段表现如何二是做敏感性分析把关键参数上下浮动10%看结论是否稳定。如果结论对参数不敏感论文的说服力会强很多。最后说一个我踩过的坑有一次比赛我花了大量时间调模型结果论文里忘了写模型假设和符号说明被扣了不少格式分。从那以后我养成了一个习惯建模前先写符号表建模后先写假设再补结果。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑