
大家好今天这篇内容想跟所有正在准备数学建模竞赛、特别是瞄准“华数杯”这类赛题的朋友认真聊一聊 A 题从审题到成文的完整闭环。每年比赛季我都会看到不少队伍陷入同一个困境题目能读懂模型能说出名字但一写代码就卡住一写论文就毫无重点。网上能找到的资料要么是零散代码片段要么是只有结论没有过程的“优秀论文”真正能拿来就用的完整流程反而很少。所以这篇文章不打算只讲某一个具体赛题而是针对数学建模 A 题最常见的题型特征拆解一套可以复用的方法论。内容包括A 题到底在考什么、如何把题目转化成数学模型、Python 代码怎么写才不容易崩、论文每一部分该怎么填充、以及最后提交前必须检查的细节。无论你是第一次参赛的新手还是已经打过一两场比赛、想提升论文质量的进阶选手这篇内容都值得收藏备用。下面我们直接进入正题。1. 背景与核心概念数学建模 A 题到底在考什么1.1 什么是数学建模 A 题数学建模竞赛的题目一般分为 A、B、C 等若干题不同赛题对应不同的风格。以华数杯华数杯全国大学生数学建模竞赛为例A 题通常偏向“机理分析 数据处理 优化求解”的综合题型和国赛的 A 题风格比较接近。这类题目的特点是背景叙述很长常常附带大量实际场景描述。数据不一定直接给全有时需要选手自行查找或构造合理数据。问题往往有多个小问前一问的结果会作为后一问的输入。最终答案需要落地到具体的数值结果、图表和方案建议上。通俗一点说A 题不是考你记住了多少公式而是考你在面对一个半结构化问题时能不能把它拆解成可计算的数学模型并且用代码和论文把整个过程表达清楚。1.2 A 题和 B 题、C 题的区别这里简单做一个区分方便你快速判断自己更适合哪一题题型典型特征常用方法适合人群A 题机理分析、物理过程、复杂系统微分方程、优化模型、仿真、数值计算工科、理科背景喜欢建模和编程B 题数据处理、统计分析、决策评价回归、聚类、综合评价、机器学习统计、经管、数据类背景C 题大数据、信息处理、预测判别特征工程、机器学习、深度学习对数据挖掘和编程较熟练的队伍需要注意的是不同年份、不同赛事的题目风格会有调整以上只是大多数情况下的规律。选题时不要只看题目难度更要看队伍成员擅长的方向。1.3 为什么“论文 代码”缺一不可很多新手有一个误区以为比赛就是“建个模、算个结果”就完事了。实际上评委拿到手的最终成果是论文而不是你的代码。但代码的作用同样不可替代代码是验证模型正确性的唯一途径。所有论文里的图、表、数值结果都必须从代码运行结果中产生。代码写得好不好直接决定了你在比赛最后一天还能不能改得动模型。所以一个合格的作品 逻辑严密的论文 规范可复现的代码 清晰美观的图表。三者缺一不可。2. 环境准备与版本说明2.1 语言与工具选择数学建模竞赛中Python 是目前最主流的选择其次是 MATLAB。如果你还在犹豫用哪个我建议优先 Python原因有三个数据处理生态完善Pandas、NumPy 几乎覆盖所有数据清洗需求。可视化工具丰富Matplotlib、Seaborn 能快速产出论文级图表。机器学习、优化算法库齐全Scikit-learn、SciPy、Gekko 等都能直接调用。版本方面Python 3.8 以上即可不需要追求最新版本。本文所有示例代码均以 Python 3 为基准依赖库版本如下实际以你本机环境为准库名称建议版本用途numpy1.24数值计算pandas2.0数据处理matplotlib3.7绘图scipy1.10插值、拟合、优化scikit-learn1.2机器学习模型2.2 运行环境推荐使用 Jupyter Notebook 或 VS Code 进行开发。Jupyter 的优点是每个单元格单独运行适合比赛期间反复调试VS Code 的优点是工程结构更清晰适合写完整脚本。建议目录结构如下A题项目目录/ ├── data/ # 存放原始数据和预处理后数据 │ ├── raw/ # 原始数据 │ └── processed/ # 处理后的数据 ├── code/ # 所有脚本 │ ├── data_preprocess.py │ ├── model_1.py │ ├── model_2.py │ └── draw.py ├── figures/ # 论文配图 ├── output/ # 输出结果表格 └── paper/ # 论文写作相关这个结构的好处是每个环节的产物都有固定位置后面写论文找数据、找图时不会手忙脚乱。2.3 必装库命令pip install numpy pandas matplotlib scipy scikit-learn openpyxl其中openpyxl用于读写 Excel 文件比赛中很多数据都以.xlsx格式提供。3. 核心建模思路从题目到数学模型的完整拆解3.1 审题先画流程图不要急着写公式拿到 A 题后最忌讳的事情就是立刻开始翻书找公式。正确的做法是先花 30 到 60 分钟通读题目然后在草稿纸上画出问题的逻辑链条。例如一道典型的 A 题可能包含以下链条数据输入 - 数据清洗 - 机理建模 - 参数辨识 - 模型验证 - 优化求解 - 结果分析每一个箭头都对应着论文中的一个章节。把这条链条画清楚你的论文框架就有了雏形。3.2 建模从简单模型开始逐步加复杂度A 题最大的坑是“想一步到位”。比如看到物理过程就直接上偏微分方程看到优化问题就直接上遗传算法结果模型复杂到自己都解释不了参数含义。更稳妥的路径是先建立最简单、最粗糙的模型确保能跑通。观察结果与真实数据的差距。逐步增加约束条件、修正参数让模型逼近真实情况。每一步修改都要记录结果变化这些记录写进论文就是很好的“模型改进”素材。一句话先做出来再做好。能算出一个有误差的结果远远好过搭建一个永远跑不出来的完美模型。3.3 常用模型速查表针对 A 题常见问题这里整理一个初步的模型选择参考问题类型推荐模型/方法适用场景数据拟合/预测最小二乘、灰色预测、回归分析数据量少、趋势明显物理过程描述微分方程、差分方程运动轨迹、热量传导、流体问题多目标优化加权法、NSGA-II成本最低、效率最高的方案设计路径规划/调度Dijkstra、A*、遗传算法、模拟退火物流、巡检、排班问题图像/几何计算坐标变换、几何公式推导轨迹、形态、尺寸测量这些方法并不需要你在赛前全部精通但至少要做到“看到题目能想到该用哪类模型”。3.4 为什么说灵敏度分析是 A 题论文的加分项很多队伍建完模、出完结果就结束了忽略了“如果参数变化结果会怎样变化”这个问题。但在评委眼中灵敏度分析是检验模型稳定性的重要指标。最简单的做法是选定一个关键参数在基准值上下各浮动 5%、10%、20%重新运行模型记录结果变化然后画一张折线图或误差条图。如果结果变化在可接受范围内说明模型稳定性较好如果结果剧烈震荡则说明模型对这个参数很敏感论文里需要给出合理解释。后面实战案例中会给出具体的灵敏度分析代码。4. 完整实战案例从数据生成到模型求解的一站式流程为了让大家看到一套完整代码是怎么组织起来的我们这里构造一个简化版的 A 题场景。假设题目要求根据一组观测数据建立某个物理量与时间的关系模型并求解模型参数最终给出预测结果和优化建议。4.1 创建项目结构首先在本地创建如下文件夹demo_a/ ├── data/raw/ ├── data/processed/ ├── code/ ├── figures/ ├── output/ └── paper/然后在code文件夹下新建四个 Python 文件data_preprocess.pymodel_fit.pymodel_predict.pydraw_figure.py下面逐个文件编写。4.2 数据预处理真实比赛中最容易翻车的地方数据预处理这一步是最被低估、最容易出错的地方。很多队伍花 80% 的时间调模型却不肯花 20% 时间检查数据最后结果跑偏都不知道为什么。code/data_preprocess.py完整代码如下# 文件路径demo_a/code/data_preprocess.py import pandas as pd import numpy as np from pathlib import Path # 获取项目根目录 ROOT Path(__file__).parent.parent RAW_DIR ROOT / data / raw PROCESSED_DIR ROOT / data / processed # 创建输出目录 PROCESSED_DIR.mkdir(parentsTrue, exist_okTrue) def load_data(file_name: str) - pd.DataFrame: 加载原始数据 file_path RAW_DIR / file_name if file_path.suffix .xlsx: df pd.read_excel(file_path) elif file_path.suffix .csv: df pd.read_csv(file_path) else: raise ValueError(仅支持 .xlsx 和 .csv 格式) return df def clean_data(df: pd.DataFrame, drop_cols: list None) - pd.DataFrame: 数据清洗 1. 删除全为空值的列 2. 填充或删除缺失值 3. 删除重复行 if drop_cols: df df.drop(columnsdrop_cols) # 删除全为 NaN 的列 df df.dropna(axis1, howall) # 缺失值处理数值列用均值填充类别列用众数填充 for col in df.columns: if df[col].dtype in [float64, int64]: df[col] df[col].fillna(df[col].mean()) else: df[col] df[col].fillna(df[col].mode()[0]) # 删除重复行 df df.drop_duplicates() return df def save_processed_data(df: pd.DataFrame, file_name: str) - None: 保存预处理后的数据 output_path PROCESSED_DIR / file_name if file_name.endswith(.xlsx): df.to_excel(output_path, indexFalse) else: df.to_csv(output_path, indexFalse) print(f数据已保存至{output_path}) if __name__ __main__: # 示例加载并清洗数据 df_raw load_data(observation.xlsx) df_clean clean_data(df_raw) save_processed_data(df_clean, observation_clean.csv)这段代码做的事情非常朴素但很重要load_data兼容了 Excel 和 CSV 两种常见格式。clean_data做了缺失值处理、重复值删除、全空列删除。所有处理后的数据统一存放到processed目录保证下一步建模使用的数据是干净、可追溯的。4.3 编写核心建模代码最小二乘拟合 参数求解建模阶段我们假设观测数据符合一个带噪声的指数衰减过程也就是物理中常见的y a * exp(-b * t) c我们需要根据观测数据反推出 a、b、c 三个参数。code/model_fit.py完整代码如下# 文件路径demo_a/code/model_fit.py import numpy as np import pandas as pd from scipy.optimize import curve_fit from pathlib import Path ROOT Path(__file__).parent.parent PROCESSED_DIR ROOT / data / processed OUTPUT_DIR ROOT / output OUTPUT_DIR.mkdir(parentsTrue, exist_okTrue) def load_processed_data(file_name: str) - pd.DataFrame: 读取预处理后的数据 return pd.read_csv(PROCESSED_DIR / file_name) def exp_decay_model(t, a, b, c): 指数衰减模型 y a * exp(-b * t) c return a * np.exp(-b * t) c def fit_model(t, y, p0None): 使用 scipy 的 curve_fit 进行最小二乘拟合 p0 是参数初始值提供合理的初值有助于收敛 if p0 is None: p0 [1.0, 0.1, 0.0] # least_squares 里返回参数协方差矩阵 params, cov curve_fit(exp_decay_model, t, y, p0p0, maxfev5000) return params, cov def evaluate_fit(t, y, params): 计算拟合误差RMSE 和 R² y_pred exp_decay_model(t, *params) residuals y - y_pred rmse np.sqrt(np.mean(residuals ** 2)) ss_res np.sum(residuals ** 2) ss_tot np.sum((y - np.mean(y)) ** 2) r_squared 1 - (ss_res / ss_tot) return rmse, r_squared if __name__ __main__: # 读取数据 df load_processed_data(observation_clean.csv) t_data df[t].values y_data df[y].values # 拟合 params, cov fit_model(t_data, y_data) a, b, c params rmse, r2 evaluate_fit(t_data, y_data, params) print(f拟合参数a{a:.4f}, b{b:.4f}, c{c:.4f}) print(fRMSE {rmse:.4f}, R² {r2:.4f}) # 保存参数到 output 目录 param_df pd.DataFrame({ 参数: [a, b, c, RMSE, R_squared], 值: [a, b, c, rmse, r2] }) param_df.to_csv(OUTPUT_DIR / model_params.csv, indexFalse)这里需要注意几个细节curve_fit需要给定初始值p0。初值给得太离谱可能收敛到局部最优解。通过maxfev5000提高最大迭代次数防止数据量较大时迭代不足。输出 RMSE 和 R²这两个指标会直接写进论文的“模型检验”部分。4.4 生成预测与灵敏度分析有了拟合参数后还需要对未来时刻进行预测并验证模型对参数的敏感程度。code/model_predict.py完整代码如下# 文件路径demo_a/code/model_predict.py import numpy as np import pandas as pd import matplotlib.pyplot as plt from model_fit import exp_decay_model from pathlib import Path ROOT Path(__file__).parent.parent OUTPUT_DIR ROOT / output FIGURES_DIR ROOT / figures FIGURES_DIR.mkdir(parentsTrue, exist_okTrue) def predict_future(t_start, t_end, params, num_points100): 生成未来时间范围内的预测值 t_future np.linspace(t_start, t_end, num_points) y_future exp_decay_model(t_future, *params) return t_future, y_future def sensitivity_analysis(t, y, params, param_index1, percent0.1): 灵敏度分析 将指定的参数上下浮动 percent例如 0.1 表示 10% 重新计算 RMSE观察模型误差的变化。 base_rmse, _ evaluate_fit(t, y, params) sensitivities {} for direction in [-1, 1]: perturbed_params params.copy() perturbed_params[param_index] * (1 direction * percent) rmse, _ evaluate_fit(t, y, perturbed_params) # 灵敏度系数 (RMSE变化率) / (参数变化率) sensitivity ((rmse - base_rmse) / base_rmse) / percent key f参数{param_index}_{direction * percent:.0%} sensitivities[key] sensitivity return sensitivities from model_fit import evaluate_fit if __name__ __main__: # 读取参数 param_df pd.read_csv(OUTPUT_DIR / model_params.csv) params param_df.loc[param_df[参数].isin([a, b, c]), 值].values.astype(float) # 预测未来区间 t_future, y_future predict_future(10, 30, params) # 输出预测表格前 20 行 pred_df pd.DataFrame({t: t_future[:20], y预测: y_future[:20]}) pred_df.to_csv(OUTPUT_DIR / predict_results.csv, indexFalse) print(pred_df.head(10)) # 灵敏度分析 sens sensitivity_analysis( tnp.linspace(0, 10, 100), yexp_decay_model(np.linspace(0, 10, 100), *params), paramsparams, param_index1, percent0.1 ) print(灵敏度分析结果, sens)实际比赛时t和y都来自真实观测数据这里构造数据只是为了演示 API 的用法。你在自己项目中直接把np.linspace部分替换成真实数据即可。4.5 绘图论文配图的规范写法论文配图不是“能看出趋势就行”而是要清晰、无歧义、不用读正文也能理解。code/draw_figure.py完整代码如下# 文件路径demo_a/code/draw_figure.py import pandas as pd import numpy as np import matplotlib.pyplot as plt from model_fit import exp_decay_model, load_processed_data from model_predict import predict_future from pathlib import Path ROOT Path(__file__).parent.parent FIGURES_DIR ROOT / figures OUTPUT_DIR ROOT / output # 全局设置中文字体避免乱码 plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, PingFang SC] plt.rcParams[axes.unicode_minus] False def plot_model_fit(t, y, params, save_pathNone): 绘制原始数据点和拟合曲线 t_fit np.linspace(t.min(), t.max(), 300) y_fit exp_decay_model(t_fit, *params) plt.figure(figsize(8, 5)) plt.scatter(t, y, label观测数据, colorblue, alpha0.7, s30) plt.plot(t_fit, y_fit, label拟合曲线, colorred, linewidth2) plt.xlabel(时间 t) plt.ylabel(观测值 y) plt.title(模型拟合效果) plt.legend() plt.grid(True, linestyle--, alpha0.5) plt.tight_layout() if save_path: plt.savefig(save_path, dpi300) plt.show() if __name__ __main__: # 读取数据 df load_processed_data(observation_clean.csv) t_data df[t].values y_data df[y].values # 读取参数 param_df pd.read_csv(OUTPUT_DIR / model_params.csv) params param_df.loc[param_df[参数].isin([a, b, c]), 值].values.astype(float) # 绘图并保存 plot_model_fit(t_data, y_data, params, save_pathFIGURES_DIR / fit_curve.png)论文中所有图片建议统一使用dpi300保存这样插入 Word 或 LaTeX 后不会模糊。每张图都要有坐标轴标签、图例、网格线这是最基本的规范。4.6 运行与验证在命令行中按顺序执行cd demo_a/code python data_preprocess.py python model_fit.py python model_predict.py python draw_figure.py预期的运行结果大致如下拟合参数a2.3412, b0.1543, c0.1021 RMSE 0.0234, R² 0.9936R² 接近 0.99 说明模型解释能力很强RMSE 很小说明拟合误差较低。这部分内容后续可以直接写进论文的“模型检验”小节。4.7 结果说明通过以上流程你实际上已经完成了一篇建模论文最核心的“建模-求解-检验”闭环。后续要做的就是把这个过程写成论文并补充问题重述、模型假设、符号说明等内容。5. 论文写作完整结构与写作技巧5.1 摘要决定你能不能获奖的第一道关卡评委在初筛时会先看摘要摘要不过关正文质量再高也可能被淹。摘要建议按以下结构展开第一句针对什么问题建立了什么模型。第二到四句分别概括每个小问的建模方法和求解结果。最后一句模型验证结果和核心结论。例如针对城市新能源公交充电策略优化问题本文构建了基于充电负荷预测的多目标优化模型。 针对问题一采用灰色 GM(1,1) 模型对充电负荷进行预测并通过残差检验验证模型精度平均相对误差为 3.2%。 针对问题二建立了以充电成本和电网峰谷差最小化的双目标优化模型采用 NSGA-II 算法求解得到 Pareto 最优解集相比固定策略总成本降低 18.6%。注意避免两个误区不要写“本文使用了多种模型最终取得了较好效果”这种模糊表述。不要出现“大概”“可能”“或许”等不确定词汇。5.2 问题分析画出逻辑图比写一千字更管用很多队伍把“问题分析”写成了题目复述这是完全错误的。正确做法是用自己的话重新描述题目要解决的问题。拆解每个小问之间的联系。说明你打算用什么思路去解决。这里最推荐的方式是配合一个清晰的逻辑流程图或表格让评委一眼看出你的建模思路。5.3 模型假设与符号说明模型假设不是随便写几条“无风无雨”就完事而是要对正文模型中的简化条件负责。常见的假设有假设数据缺失项符合均值水平。假设系统在短时间内的参数变化可忽略。假设各变量之间满足线性/非线性关系。符号说明建议用表格列出符号含义单位t时间变量hy观测值mma, b, c待定参数无量纲5.4 模型建立与求解论文最核心的部分这一部分要详细写出模型的数学表达式。每个符号的定义。模型的推导过程或简化依据。求解所用的方法最小二乘、遗传算法等。每一步计算得到的关键数值结果。注意公式用公式编辑器统一编号方便后文引用。每一问的结果最好都配一张图或表。代码不要大段贴进论文核心算法可以给出伪代码完整代码作为附录。5.5 灵敏度分析与模型优缺点灵敏度分析不是可选内容而是体现你考虑周全的关键环节。正文中可以这样描述为了检验模型对参数 b 的依赖程度将 b 在基准值基础上分别上下浮动 10%重新计算 RMSE 变化率结果如表 5 所示。可以看出当参数 b 浮动 10% 时RMSE 变化率小于 5%模型具有较强的稳定性。优点和缺点要写得具体。例如优点模型结构简洁计算效率高。参数具有明确的物理意义便于解释。缺点模型假设条件较为理想未考虑随机扰动。对初值敏感性较高实际应用中需要结合数据确定合理初值。5.6 参考文献给评委留下严谨印象参考文献至少要列出 5 到 8 篇且尽量包含近年文献。格式上参考国标 GB/T 7714 即可。注意论文中引用了哪篇文献正文里就一定要有标注不能“引而不标”。6. 常见问题与排查思路比赛过程中会遇到各种各样的报错和模型问题下面整理一份高频问题清单。问题现象常见原因解决思路训练模型时结果严重偏离实际数据中存在异常值或量纲不一致先做 EDA查看数据分布统一数据量纲curve_fit 拟合不收敛初值设置不合理根据数据范围手动估算初值或者用多次随机初值尝试图表中文乱码未设置中文字体设置plt.rcParams[“font.sans-serif”]代码运行到一半报 KeyError列名拼写错误或列名有空格打印df.columns检查实际列名结果与别人差距很大边界条件/参数设置不同回归题目原文检查假设条件和范围设置论文查重率过高大段复制教材或论文原文用自己的话重写引用务必标注如果遇到未知报错最直接的排查方式是先看报错信息最后一行定位错误的文件和行号。检查变量名、数据类型、数组维度。用print()打印中间结果缩小问题范围。不要把时间花在“猜为什么报错”上直接用最小用例测试单个函数。7. 最佳实践与工程建议7.1 代码层面每个脚本只做一件事。数据预处理、模型拟合、绘图、预测尽量拆开避免一个大文件几百行。不要带着情绪写注释。注释写清楚“这段代码做了什么、为什么这么做”就足够了不要让注释变成流水账。关键结果及时落盘。每次运行模型把参数、误差、预测结果保存为 CSV 或 Excel方便写论文时查阅。运行前确认数据路径。最怕的一种情况是代码在自己的电脑上跑通了换一台电脑或者换一个目录就找不到文件。7.2 时间管理层面三天比赛时间建议这样分配时间段任务第 1 天上午选题、审题、收集数据第 1 天下午画逻辑链、确定模型框架第 2 天全天建模、写代码、跑结果第 3 天上午论文初稿、图表制作第 3 天下午修改摘要、补充灵敏度分析、排版第 3 天晚上全文校对、提交材料确认很多队伍失败的原因是第一天没有确定模型方向到了第三天还在“换模型”。一旦模型确定只要结果不太离谱就不要中途推翻重来而是通过增加约束和修正参数来优化。7.3 学术诚信层面这一点必须强调论文和代码必须是队伍自己完成的内容。可以参考别人的开源代码但要在参考文献中说明。严禁购买代写论文、倒卖所谓“完整答案”等行为。参加数学建模竞赛的核心收获是训练解决实际问题的能力而不是那张证书本身。如果为了获奖而走捷径就失去参赛的意义了。8. 总结与后续学习路线这篇文章重点梳理了数学建模 A 题的完整流程从审题拆解、模型选择、代码实现到论文撰写和灵敏度分析每一个环节都有对应的操作建议和代码示例。基于本文的内容你可以按照下面的路径继续深入找一套往年 A 题用本文代码框架完整跑一遍先求“做出来”再求“做得好”。针对自己不熟悉的模型类型单独花时间补充学习。例如不熟悉优化算法就尝试用scipy.optimize跑通一个简单的最优化问题。练习论文写作重点打磨摘要和问题分析两个部分因为这两部分是评委最先看的内容。熟悉常见可视化图表学会用一张图讲清楚一个结论。建模能力不是看几篇文章就能提升的关键在于动手练。哪怕每天只花两个小时把一个小问题完整建模、求解并写成报告坚持一个月也比临时抱佛脚有效得多。如果你正在准备 2026 年的华数杯或同类数学建模竞赛希望这篇文章能作为你赛前的一个“检查清单”。建议收藏备用比赛间隙遇到卡点时再翻出来对照排查。祝大家建模顺利论文高分。