在备赛数模国赛的过程中,C题往往是最容易出成绩、也最容易翻车的题目。很多队伍一眼看到 C 题的数据表格和业务场景,觉得“不就是数据分析吗”,结果做下去才发现:数据量巨大、指标口径复杂、模型解释要求高,三天时间一大半耗在数据清洗和结果调参上。本文从 C 题命题特征出发,完整拆解备赛知识框架、标准建模流程、常用算法实战代码、模型创新思路以及 AI 辅助工具的正确用法,帮助你搭建一套可持续复用的参赛体系。
本文适合正在备赛全国大学生数学建模竞赛、尤其是主攻 C 题的本科生和研究生阅读。无论你是第一次参赛还是想冲击国奖,只要按文章顺序把每个环节的代码和思路吃透,就能在赛场上少走很多弯路。
1. 国赛C题到底考什么
1.1 C题的定位与命题特征
全国大学生数学建模竞赛的题目分为 A、B、C 等题组,不同题目的侧重点差异很明显。A 题偏物理机理和连续问题,通常需要建立微分方程或偏微分方程模型;B 题往往涉及离散优化、图论和运筹学;而 C 题是典型的数据分析题,题目会提供一份或多份实际业务数据,要求参赛者完成数据预处理、特征分析、模型构建、结果解释和决策建议。
从近年题目来看,C 题的命题风格非常稳定,核心是“用数据说话”。例如某年题目是蔬菜类商品的自动定价与补货决策,数据包含多个品类商品的销量、价格、损耗率等;另一年题目是垃圾焚烧厂炉温预测,数据来自燃烧工况的传感器记录。这些题目的共同点有三个:
- 数据量大,通常有几十万甚至上百万条记录。
- 业务背景强,需要理解行业术语和数据口径。
- 结果要求落地,不仅要对历史数据建模,还要给出未来预测或经营决策建议。
这一点决定了 C 题的备赛重点不是背模型公式,而是熟练掌握数据处理、特征工程、机器学习建模和结果可视化这套完整流程。
1.2 C题与其他题目的区别
很多参赛队伍在选题时犹豫不决,其实只要认清 C 题特点,选择就变得容易了。
A 题需要较强的物理和数学功底,如果集训时没有积累偏微分方程数值解的实战经验,赛场上临时推导很容易卡住。B 题对算法设计能力要求较高,常见的是整数规划、动态规划或者复杂启发式算法,代码工程量也不小。C 题则更适合具有以下特点的队伍:
- 熟悉 Python 和 pandas、numpy、sklearn 等数据处理库。
- 擅长对业务数据做快速探索性分析。
- 能在较短时间内把模型结果转化为可读的图表和结论。
需要提醒的是,C 题虽然入门门槛低,但获奖门槛并不低。因为绝大多数队伍都会选择 C 题,评审时的竞争非常激烈。想要冲击国奖,单纯套用一个随机森林模型远远不够,必须在一两个环节做出亮点,比如数据处理方法的严谨性、特征构造的业务依据、模型组合的创新性,或者决策建议的可操作性。
1.3 C题备赛必须掌握的技能矩阵
根据近年来的赛题要求,我将 C 题需要的能力拆分为六个维度:
| 维度 | 具体技能 | 优先级 |
|---|---|---|
| 数据处理 | pandas 数据清洗、缺失值处理、异常值检测、多表合并 | 极高 |
| 数据分析 | EDA 可视化、相关性分析、分布分析 | 极高 |
| 特征工程 | 特征构造、编码转换、标准化、特征筛选 | 极高 |
| 建模能力 | 回归、分类、聚类、时序预测、综合评价模型 | 高 |
| 模型检验 | 交叉验证、混淆矩阵、残差分析、敏感性分析 | 高 |
| 论文写作 | 摘要提炼、图表排版、结果解释、附录代码规范 | 极高 |
1.4 C题拿奖的评分点在哪里
关于 C 题评分标准,可以从本科组获奖论文和评阅要点中总结出几条规律。评阅老师首先看摘要和结论,摘要必须清晰回答“做了什么、怎么做的、得到什么结果、结果是否可靠”。其次看数据处理过程是否完整,很多队伍直接把 Excel 数据读进来就建模,缺失值随便填、异常值不处理,这种论文在评阅时会被扣分。最后看模型是否真的解决了业务问题,而不是模型本身多高深。
换句话说,C 题拿高分的关键是“完整、合理、可解释”,不是说一定要用最前沿的深度学习方法。
2. 备赛环境与团队准备
2.1 编程语言与工具链
C 题的主流工具是 Python。相比 MATLAB,Python 在数据处理和机器学习生态上更成熟,尤其是 pandas、scikit-learn、matplotlib 这三个库组合在一起,可以覆盖从数据读取到结果可视化的全部环节。
在版本选择上,建议使用 Python 3.9 以上版本,安装 Anaconda 作为基础环境,这样可以直接获得 numpy、pandas、scipy、matplotlib 等常用库。如果比赛需要使用机器学习库,建议再安装 scikit-learn、xgboost、lightgbm。时序预测方向可能用到 statsmodels、prophet;微分方程数值解相关的不作为 C 题重点,但有时会作为辅助模型出现。
我建议在赛前固定使用一个项目虚拟环境,避免因依赖冲突浪费比赛时间:
conda create -n mathmodel python=3.11 conda activate mathmodel conda install numpy pandas matplotlib scipy scikit-learn pip install xgboost lightgbm statsmodels这里不要求版本号完全一致,重点是保持环境稳定,比赛期间不要频繁升级依赖。
2.2 推荐编辑器与项目管理
编辑器方面,PyCharm 和 VS Code 都是不错的选择。个人更推荐 VS Code,因为打开数据集和 Jupyter Notebook 比较流畅,插件体系也适合团队协作。比赛时推荐使用 Jupyter Notebook 做探索性分析,用.py脚本沉淀最终的模型文件。
为了方便复盘和排错,建议赛前就固定一套项目目录结构:
C_question/ ├── data/ │ ├── raw/ # 原始数据,只读不修改 │ ├── processed/ # 清洗后的数据 │ └── output/ # 结果输出 ├── code/ │ ├── preprocess.py # 数据预处理 │ ├── eda.ipynb # 探索性分析 │ ├── feature.py # 特征工程 │ ├── model.py # 模型训练与预测 │ └── utils.py # 公共函数 ├── paper/ │ └── figure/ # 论文图表 └── README.md2.3 团队分工与赛程安排
数学建模竞赛是三人三天,C 题的数据量大,团队分工尤其重要。根据 C 题特点,建议采用“1 建模 + 1 编程 + 1 写作”的分工方式,但又不能完全割裂。原因是写作同学如果不懂模型,就写不出清晰的模型解释;编程同学如果只写代码不看题目,就不知道特征构造的方向。
比较合理的赛程安排是这样的:
- 第一天上午:全体读题,每人独立列出关键问题和数据字段,然后集中讨论确定题目理解。
- 第一天下午至晚上:编程同学完成数据清洗和 EDA,建模同学开始设计整体模型框架,写作同学搭建论文模板并记录题目分析和假设。
- 第二天:建模与编程紧密配合完成主模型,写作同学同步撰写“模型建立”部分。
- 第三天上午:完成结果分析、模型检验、敏感性分析。
- 第三天下午:写作同学全力冲刺摘要和论文排版,其他两人负责图表校准和参考文献整理。
2.4 赛前训练建议
赛前训练不需要大量刷整套题目,重点是做专题拆解。比如用两到三天专门练习数据清洗,再用两到三天专门练特征工程,接着用一周时间集中练习常见模型,最后再找一套近年 C 题做三天完整模拟。每次模拟后必须花半天时间复盘,把“卡在哪个环节、为什么卡、下次怎么避免”记录下来。通过复盘沉淀出自己的工具箱和套路,赛场上会从容很多。
3. C题的标准解题流程
3.1 从题目描述到问题定义
拿到 C 题后,第一步不是读数据,而是反复读题,把题目中的业务目标转化成建模目标。C 题的题干往往包含销售、库存、定价、排放、能耗等业务名词,每个名词都可能对应数据表中的一个或多个字段。读题时要做的就是把主问题拆成若干子问题,例如“预测未来销量”和“制定补货计划”就是两个不同的子任务。
建议用表格把业务目标、数据字段、模型输出列出来:
| 业务问题 | 对应数据字段 | 模型输出 |
|---|---|---|
| 预测次日各品类销量 | 日期、品类、销量、促销标记 | 未来若干天的销量数值 |
| 制定补货决策 | 库存量、损耗量、供应商成本 | 每个品类的补货量 |
这一步听起来简单,却决定了后续所有工作的方向。方向错了,后面模型再精细也白搭。
3.2 数据清洗是C题的生死线
数据处理是 C 题的基础,也是拉开差距的关键环节。赛题数据往往存在明显问题,例如缺失值、重复记录、异常值、单位不统一、日期格式混乱、多表关联键不一致等。如果不认真处理,直接在原始数据上建模,哪怕模型本身没问题,预测结果也可能严重背离业务规律。
数据清洗应该遵循“先理解,再处理”的原则。拿到每张表后,先用df.info()和df.describe()看字段类型、缺失情况和分布;然后结合业务逻辑判断每个异常值是错误数据还是真实波动。比如销量出现负数,可能是退货记录,不能直接删除;价格出现极端值,可能是录入错误,需要进一步确认。
3.3 探索性数据分析和特征构造
EDA 的作用在于发现数据中的模式,为建模提供方向。通过绘制销量时间序列图、品类销量对比图、相关性热力图,可以直观看到周期性、趋势性和异常点。这些图形同样是论文中非常有说服力的素材。
特征工程则是把业务理解和数据信息转化为模型输入的过程。常见做法包括:
- 日期分解:年、月、日、星期、是否节假日、是否促销日。
- 历史统计:过去 7 天销量均值、标准差、最大值、最小值。
- 分组特征:同一品类或同一门店在不同维度上的均值。
- 编码转换:类别变量用独热编码或标签编码。
- 标准化:对量纲差异大的特征使用标准化或 MinMax 归一化。
3.4 模型选择、训练与结果解释
C 题常见模型可以归为几类:评价类(熵权法、TOPSIS、灰色关联分析)、预测类(线性回归、随机森林、XGBoost、LightGBM、时间序列模型)、优化类(线性规划、粒子群算法、模拟退火算法)。具体选哪一类,取决于题目问的是“好坏排序”还是“未来数值”还是“最优决策”。
模型训练时要特别注意防止过拟合。C 题数据经常时间跨度长,直接用全部数据训练再在同样时间段上验证,效果会很好看,但实际预测很差。正确做法是按时间划分训练集和验证集,或者使用 K 折交叉验证。模型完成后,还要分析特征重要性,说明哪些因素对结果影响最大,这可能是评阅老师最关心的内容。
结果解释不是把预测值贴出来就结束,而是要结合业务场景说明“为什么是这个结果”。例如预测某品类销量最高,论文里应说明是因为该品类历史销量基数大、近期促销活动频繁、季节性因素叠加等。
4. 数据预处理与EDA实战
4.1 读取数据与数据概览
先来看一个最简单的数据读取示例。假设赛题给出两张表,一张是销售明细表sales.csv,另一张是商品信息表products.csv:
# 文件路径:code/preprocess.py import pandas as pd import numpy as np sales = pd.read_csv('data/raw/sales.csv', parse_dates=['日期']) products = pd.read_csv('data/raw/products.csv') print(sales.shape) print(sales.info()) print(sales.head())shape可以快速看数据规模,info()可以检查每个字段的非空数量和类型,head()则让我们对数据长相有一个直观感受。读取后要检查两张表的关联键是否一致,例如商品编码在 sales 里是字符串,在 products 里是整数,合并前就需要统一类型。
4.2 缺失值与异常值处理
处理缺失值时,不要无脑用中位数或均值填充。先判断缺失比例,如果某字段缺失超过 80%,通常直接删除该特征;如果缺失比例较低,再根据字段含义选择填充方式。对于时间序列数据,前向填充有时候比均值填充更合理:
# 缺失值处理示例 # 情况1:数值型字段缺失比例较低,按组中位数填充 sales['单价'] = sales.groupby('品类')['单价'].transform(lambda x: x.fillna(x.median())) # 情况2:时间序列字段,使用前向填充 sales['库存量'] = sales['库存量'].ffill() # 异常值处理:用 IQR 方法标记极端值 Q1 = sales['销量'].quantile(0.25) Q3 = sales['销量'].quantile(0.75) IQR = Q3 - Q1 lower = Q1 - 1.5 * IQR upper = Q3 + 1.5 * IQR print('异常值数量:', ((sales['销量'] < lower) | (sales['销量'] > upper)).sum())需要注意的是,IQR 方法只是标记异常值的一种思路。对于销量这种业务字段,节假日峰值被标记为异常值非常常见,此时不能直接删除,而是要结合日期特征判断是否属于正常业务波动。
4.3 EDA可视化与洞察提炼
EDA 的目的是快速提炼业务规律。下面代码绘制某品类销量随时间的变化趋势,并输出整体统计描述:
# 文件路径:code/eda.ipynb import matplotlib.pyplot as plt import matplotlib.dates as mdates plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False # 按日期汇总销量 daily_sales = sales.groupby('日期')['销量'].sum().reset_index() fig, ax = plt.subplots(figsize=(12, 5)) ax.plot(daily_sales['日期'], daily_sales['销量'], linewidth=1) ax.set_title('每日销量趋势') ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d')) plt.tight_layout() plt.savefig('paper/figure/daily_sales.png', dpi=150) plt.show()图表的每个细节都可能影响论文观感。画图时务必注意中文显示问题,论文最终提交的图片建议统一设置为 150dpi 以上,尺寸清晰,坐标轴有标题,图例不遮挡数据。
EDA 后应形成几条明确的结论,例如“销量存在明显周周期性”“春节前后销量显著上升”“部分品类价格敏感度较高”。这些结论会直接指导后续特征构造,也是论文中“数据分析”章节的重要素材。
5. 核心算法精讲与代码实现
5.1 评价类模型:熵权法 + TOPSIS
C 题经常出现排序、评价类问题,例如对多个供应商、多个地区或多个方案进行综合评价。熵权法用于确定客观权重,TOPSIS 用于计算各评价对象与理想解的接近程度,两者组合非常经典。
熵权法的思路是:指标变异程度越大,说明信息量越大,权重越高。比如某个指标所有样本数值几乎相同,它对评价就没有区分度,权重应趋近于 0。
下面给出完整的熵权法 + TOPSIS 代码,输入是一个二维数组,每一行是一个评价对象,每一列是一个指标:
# 文件路径:code/evaluate.py import numpy as np def entropy_weight(X): """ 熵权法计算指标权重 X: shape (n_samples, n_features),已正向化处理 返回: 权重向量 """ X = np.array(X, dtype=float) # 归一化,这里采用比重法 P = X / X.sum(axis=0, keepdims=True) # 防止 log(0) P = np.where(P == 0, 1e-12, P) k = 1 / np.log(X.shape[0]) e = -k * (P * np.log(P)).sum(axis=0) d = 1 - e w = d / d.sum() return w def topsis(X, w): """ TOPSIS 法计算综合得分 X: 正向化且标准化的决策矩阵 w: 权重向量 """ # 规范化决策矩阵 norm = X / np.sqrt((X ** 2).sum(axis=0, keepdims=True)) # 加权规范化矩阵 V = norm * w # 正理想解和负理想解 Z_plus = V.max(axis=0) Z_minus = V.min(axis=0) D_plus = np.sqrt(((V - Z_plus) ** 2).sum(axis=1)) D_minus = np.sqrt(((V - Z_minus) ** 2).sum(axis=1)) score = D_minus / (D_plus + D_minus) return score # 示例数据:4个评价对象,3个指标,均为正向指标 X = np.array([ [85, 90, 78], [82, 88, 82], [91, 76, 85], [79, 93, 80] ]) w = entropy_weight(X) score = topsis(X, w) print('权重:', w) print('综合得分:', score)使用熵权法时要注意,实际赛题中的指标有正向指标和负向指标之分。正向指标数值越大越好,负向指标数值越小越好。在计算熵权之前,需要对负向指标做正向化处理,例如取倒数或取最大值减去原值。
5.2 预测类模型:随机森林与 XGBoost
预测未来数值是 C 题的另一个主力考查方向。随机森林作为集成学习模型,不需要过多调参就能获得不错的效果,适合作为基准模型。XGBoost 或 LightGBM 在数据量大、特征多时效果更优,但需要关注过拟合和参数调整。
下面以随机森林为例展示完整的预测流程:
# 文件路径:code/model.py import pandas as pd from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error, mean_squared_error # 假设 X 是特征矩阵,y 是标签 # 按时间顺序切分,前 80% 训练,后 20% 验证 df = pd.read_csv('data/processed/train_features.csv') feature_cols = [c for c in df.columns if c not in ['销量', '日期']] X = df[feature_cols].values y = df['销量'].values # 时间序列切分,禁止打乱 split_idx = int(len(X) * 0.8) X_train, X_val = X[:split_idx], X[split_idx:] y_train, y_val = y[:split_idx], y[split_idx:] model = RandomForestRegressor( n_estimators=300, max_depth=10, random_state=42, n_jobs=-1 ) model.fit(X_train, y_train) y_pred = model.predict(X_val) print('MAE:', mean_absolute_error(y_val, y_pred)) print('RMSE:', mean_squared_error(y_val, y_pred, squared=False)) # 特征重要性 importance = pd.Series(model.feature_importances_, index=feature_cols) print(importance.sort_values(ascending=False).head(10))这里强调按时间顺序切分数据集,而不是随机切分,是为了模拟真实的“用历史预测未来”场景。如果随机打乱,未来数据参与了训练,验证结果会严重虚高。
使用 XGBoost 时,同样需要先构造DMatrix格式数据,并可以设置验证集来观察训练轮数。比赛中不要盲目堆叠大模型,随机森林在几千条数据上往往已经能取得很不错的效果,而 XGBoost 更擅长处理几十万条以上的数据。
5.3 优化类模型:粒子群算法与模拟退火
部分 C 题会在预测之后追加决策优化问题,例如确定最优补货量、最优运输方案。对于变量不多、约束明确的优化问题,使用 scipy 的线性规划或整数规划即可;当问题复杂度较高、求解空间不光滑时,启发式算法是更通用的选择。
粒子群算法的核心思想是模拟鸟群觅食,每个粒子代表一个候选解,通过个体最优和全局最优更新自己的位置和速度。其优点是实现简单、收敛快,适合连续变量优化。下面给出一个用于函数最小化的粒子群算法示例:
# 文件路径:code/pso.py import numpy as np def pso_minimize(func, dim, bounds, num_particles=30, max_iter=100): """ func: 目标函数,输入一维数组,输出标量 dim: 变量维度 bounds: [(low, high), ...],每个变量的范围 """ lb = np.array([b[0] for b in bounds]) ub = np.array([b[1] for b in bounds]) # 初始化粒子位置和速度 X = np.random.uniform(lb, ub, (num_particles, dim)) V = np.random.uniform(-0.1, 0.1, (num_particles, dim)) pbest = X.copy() gbest = X[0].copy() for t in range(max_iter): for i in range(num_particles): if func(X[i]) < func(pbest[i]): pbest[i] = X[i].copy() if func(pbest[i]) < func(gbest): gbest = pbest[i].copy() w = 0.8 - 0.4 * t / max_iter # 惯性权重递减 c1, c2 = 1.5, 1.5 r1, r2 = np.random.rand(dim), np.random.rand(dim) V = w * V + c1 * r1 * (pbest - X) + c2 * r2 * (gbest - X) X = X + V X = np.clip(X, lb, ub) return gbest, func(gbest) fun = lambda x: (x[0] - 3) ** 2 + (x[1] + 2) ** 2 best_x, best_val = pso_minimize(fun, dim=2, bounds=[(-10, 10), (-10, 10)]) print('最优解:', best_x, '最优值:', best_val)粒子群算法的参数(粒子数、迭代次数、惯性权重)需要根据实际问题调整。赛题中如果时间紧张,可以用模拟退火算法作为备选方案,它的实现思路是先高温大范围搜索、再低温精细搜索,原理简单,收敛稳定。
5.4 模型检验与敏感性分析
模型建好后,不能直接写进论文,还要做充分的检验。对于预测类模型,要计算误差指标并绘制预测值与真实值对比图;对于评价类模型,要检查权重变化对排序结果的影响;对于优化类模型,要验证约束条件是否满足,并分析参数变化对最优解的影响。
敏感性分析是 C 题论文的一个加分项。比如在评价类问题中,可以将权重上下浮动 10% 重新计算排序,看排序是否发生剧烈变化;如果变化不大,说明模型鲁棒性好。
6. 模型创新点应该怎么设计
6.1 创新不等于冷门算法
很多队伍认为用 LSTM、深度学习就是创新,其实对于 C 题来说,深度学习既不好训练,又难解释,评阅时未必占优势。真正的创新点是“针对问题特征的适配性”,例如针对销售数据中的周周期性,在特征中构造星期交互项;针对时间序列的非平稳性,组合差分处理与机器学习模型。这些做法在论文里写出来,远比“我们使用了深度神经网络”更有说服力。
6.2 常见创新方向
第一个方向是组合模型。一段单独使用时间序列模型或机器学习模型,可以将二者组合,例如先用 XGBoost 预测基准值,再用 ARIMA 对残差进行修正,形成“残差修正组合预测模型”。
第二个方向是改进权重确定方式。前面的熵权法是客观赋权,层次分析法(AHP)是主观赋权,二者各有优劣。可以设计一种主客观组合赋权方法,通过距离函数计算组合系数,使最终权重兼顾业务经验和数据特征。
第三个方向是把业务约束融入模型。比如补货决策不仅要考虑销量预测,还要考虑库存成本、损耗率、供应商供货上限等约束,形成“预测 + 优化”的端到端方案。这种贴近业务实际的建模方式,往往比单纯调参更能打动评阅老师。
6.3 如何在论文中呈现创新点
创新点必须用一节专门写清楚,放在模型建立章节的开头。写法建议遵循“问题痛点 -> 现有方法不足 -> 本文改进 -> 改进效果验证”的逻辑。要让评阅老师一眼看出你的方法和常用方法有什么不同,而不是通篇只写模型公式,最后才提了一句“本模型具有创新性”。
7. AI辅助参赛的正确方式
7.1 AI能做什么、不能做什么
随着大语言模型工具的普及,AI 已经成为数模备赛和比赛中的有力辅助。它擅长的事情包括:快速生成数据处理模板代码、解释陌生算法原理、整理论文摘要、润色语言表达、排查报错信息。它可以帮你节省大量重复编码和文字整理时间。
但 AI 不能代替你完成建模思考。比赛题目千变万化,AI 不知道题目背后的业务逻辑,无法判断你构造的特征是否符合实际意义。直接复制 AI 生成的大段分析文字而不做修改,很容易出现空话套话,这在论文中反而适得其反。更重要的,比赛规则通常禁止直接使用未经训练的模型结果作为最终答案,所有 AI 生成内容必须经过人工验证和修改。
7.2 使用AI处理重复性数据处理任务
数据清洗是 C 题中最耗时、最重复的工作。对于“如何把某列时间字符串标准化”“如何合并多张表并保留指定列”这类明确指令,AI 往往能直接给出可用代码。下面是一个向 AI 提问的提示词示例:
我有一个销售明细表 sales.csv,字段包括:日期、品类、销量、单价、促销标记。 请帮我完成以下任务: 1. 读取数据并显示缺失值比例; 2. 日期列统一为 datetime 类型; 3. 销量列存在负数,请按业务逻辑提出处理建议; 4. 按品类分组计算销量均值、中位数、标准差。 要求代码使用 pandas,并添加必要注释。这类提示词的核心是“任务明确 + 数据字段清晰 + 输出要求具体”。给出的字段信息越清楚,AI 返回的代码就越贴近你的数据。
7.3 使用AI辅助算法理解与调参
当遇到不熟悉的算法时,AI 可以作为学习助手。比如问你“熵权法和层次分析法的区别”或“随机森林如何处理类别特征”,AI 的回答很快,可以帮助你快速建立知识框架。但调参部分不能完全交给 AI,因为 AI 不知道你的数据分布和模型性能。
更实用的做法是,用 AI 生成多组候选参数,然后通过交叉验证自行筛选。例如让 AI 列举 XGBoost 常用参数的含义和推荐范围,再在你自己的数据上进行网格搜索。
7.4 使用AI辅助论文写作与排版
论文写作阶段,AI 最大的价值是压缩语言和调整表达。写完一段摘要初稿后,可以让 AI 将摘要压缩到 300 字以内,同时保留关键数据结果。注意,摘要中的数字和结论必须来自自己的模型输出,不能用 AI 随意编造。
也可以用 AI 将冗长的模型推导过程改写为更简洁的段落:
以下是我写的模型建立部分,语言太啰嗦,请帮我优化表达, 保留技术细节,但压缩到原文一半长度,并保持学术语气: [粘贴你的内容]需要特别强调,比赛论文最重要的仍然是原创性和真实性。AI 的定位是助手,不是作者。所有关键结论必须由你亲自验证,所有代码必须能在你的环境中运行通过。
8. 论文写作与高分细节
8.1 摘要怎么写
摘要是整篇论文的“脸面”。评阅老师通常先用几分钟阅读摘要,再决定是否细看正文。一篇好的 C 题摘要应包括四个要素:研究问题、核心方法、主要结果、关键结论。写摘要时尽量用数字说话,例如“预测模型在测试集上的平均绝对误差为 5.2%”“优化方案相比原方案成本降低 8%”。
不要使用“本文对数据进行深入分析”这类空话。每个句子都应该包含具体的方法或结果。建议在比赛最后半天集中修改摘要,反复打磨到每个词都不可删。
8.2 图表规范
C 题论文中图表数量通常在 15 到 25 张之间。每张图必须有图号、图名和数据来源说明。图名不能只写“销量图”,要写清楚变量和时间范围,例如“2020-2023年某品类周销量时间序列图”。表格推荐使用三线表,表格内部不要出现过多颜色。所有图表在正文中第一次出现时,都要有一段话说明其结论。
8.3 模型假设与局限性
C 题数据复杂,论文必须写明模型假设。例如假设节假日影响可以量化为 0/1 变量,假设缺失值缺失机制为随机缺失,假设同一品类内商品具有相似销售规律等。这些假设看似简单,却能体现你对问题的理解深度。
模型局限性同样要写,这是模型检验的一部分。评阅老师认可“诚实说明局限”的写法,但要在局限性后补充“后续改进方向”,展示你还有进一步思考的空间。
9. 常见问题与排查清单
9.1 高频问题与解决思路
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 数据量太大,代码运行慢 | 特征冗余,数据未压缩 | 减少不必要特征,使用nunique()检查低方差特征,必要时抽样或分块处理 |
| 模型训练效果很好但验证很差 | 数据随机切分导致时间泄露 | 按时间顺序切分训练验证集,不使用未来信息 |
| 特征处理好后训练报错 | 特征存在 NaN 或无穷值 | 训练前检查数据,使用np.isinf和isna排查 |
| 图表中文显示乱码 | 缺少中文字体设置 | 使用plt.rcParams['font.sans-serif'] = ['SimHei'] |
| 论文写不完 | 时间分配不合理 | 提前规划写作模板,模型结果出来前先写问题分析部分 |
| 队友之间代码不统一 | 缺少版本管理 | 使用 git 或云同步工具,代码文件统一注释规范 |
9.2 赛场避坑清单
比赛时间紧张,很多错误是可以提前避免的。我结合备赛经验整理了下面这份避坑清单,建议赛前打印出来对照检查:
- 每天定时备份代码和论文,使用云同步或压缩包备份。
- 任何对原始数据的修改都必须另存为副本,不要直接覆盖原文件。
- 所有随机模型设置固定随机种子,保证结果可复现。
- 每次模型运行后记录参数和结果,避免重复调参。
- 论文引用的数据、图表、公式,都要能在附录里找到对应内容。
- 提交前检查最终论文是否有乱码、缺图、错别字问题。
9.3 遇到卡壳怎么办
比赛过程不可能一帆风顺。如果某个模型连续多次测试失败,不要死磕,可以先用手头已有的结果写论文,同时换一个更简单的方法作为后备方案。C 题最重要的不是模型多复杂,而是论文里每个结论都有数据支撑。哪怕最终使用的是基础模型,只要数据处理严谨、结果解释充分,依然可能取得不错的成绩。
10. 总结与进阶建议
本文围绕数模国赛 C 题展开,从命题特征、备赛环境、标准解题流程、数据预处理与 EDA 实战,到熵权法 TOPSIS、随机森林、粒子群算法等核心算法代码,再到模型创新点设计、AI 辅助参赛和论文写作高分细节,基本覆盖了 C 题从读题到提交的完整链路。
对于正在备赛的读者,我建议下一阶段按三条线推进:
第一,代码能力线。把本文涉及的数据清洗代码、评价模型代码、预测模型代码、粒子群代码全部在本地跑通,并尝试修改参数观察结果变化。代码只有自己运行过,赛场上才能顺手使用。
第二,论文写作线。不要等到比赛才开始写作,现在就应该整理一份自己的论文 LaTeX 或 Markdown 模板,把摘要、模型假设、模型建立、模型检验、灵敏度分析这些章节标题和小节逻辑预先写好骨架。
第三,真题模拟线。找一套近年 C 题,严格按照三天时间做一次完整模拟,重点体验数据读取、特征构造、模型训练和时间分配的节奏。
建模竞赛的结果固然重要,但备赛过程中养成的数据分析习惯、编程规范意识和团队协作能力,对后续科研和工作也很有帮助。希望本文能成为你备赛路上的一份实用手册。如果在实践过程中有更好的思路或代码,欢迎回来交流。