2026年数学建模国赛备赛期已经可以开始了。不管是第一次参赛还是拿过奖的老队伍竞赛里最耗时的永远不是模型推导本身而是问题分析、数据处理、图表绘制这三个环节来回返工。很多队伍两天下来真正用于建模和论文的时间不到三分之一剩下的时间都耗在数据清洗、变量定义不清、图表改了一遍又一遍上。这次我们把这套流程整理成模块化求解 skill让每个环节都有标准流程、可复用脚本和验收清单。这里说的 skill不是简单的一句提示词而是一套由说明文件、Python 脚本、检查清单组成的技能包。拿到赛题后先跑问题分析 skill 完成题目拆解再通过数据处理 skill 把原始数据清洗成标准化表格最后由图表绘制 skill 直接产出论文级图表。整个过程人可以介入AI 也可以按同一套流程执行既适合备赛阶段训练也适合比赛现场快速出结果。下面直接给核心能力和落地步骤。1. 核心能力速览能力项说明解决目标将数模国赛中的问题分析、数据处理、图表绘制三个环节标准化、模块化模块划分问题分析 skill、数据处理 skill、图表绘制 skill输出产物赛题拆解文档、标准化数据表格、论文级图表、批量处理结果运行环境Python 3.8 及以上依赖 pandas、numpy、matplotlib、seaborn、openpyxl是否需要 GPU不需要这套 skill 以数据处理为主CPU 即可运行启动方式命令行逐模块执行或封装为 HTTP API 服务是否支持批量任务支持通过批量脚本遍历输入目录自动处理是否支持接口 API支持可封装为 FastAPI 服务供团队共享适用对象数模国赛参赛队伍、建模实验课程、需要快速出图出表的科研团队扩展方向接入 AI 助手后可让 AI 按同一套 SOP 自动执行各模块从功能上看这套方案不依赖昂贵的硬件也不依赖某个特定的在线平台所有脚本都可以在本地测试通过后直接用于比赛场景。核心价值是把“凭感觉做”变成“按流程做”把重复劳动压缩到最小。2. 适用场景与使用边界这套 skill 最适合下面几类人第一次参加数模国赛的队伍。队伍里如果有人熟悉 Python按照本文的脚本和 SOP 把三个模块跑通比赛时就不用手忙脚乱。已经参赛过但总在数据环节返工的队伍。数据清洗和图表绘制统一成脚本后换一套数据也能快速产出结果。需要批量复现实验结果的场景。比如需要同时处理多份实验数据、多组调查问卷、多张表格手动操作容易出错脚本批量处理更稳定。它能解决的问题也很明确问题分析阶段不会拆题拿到题目不知道先做什么数据处理阶段反复清洗同一份数据代码写一次丢一次图表绘制阶段风格不统一论文插图很难看。但这套 skill 不能替代真正的建模能力。它负责流程标准化不负责替你决定用哪个模型、怎么写一篇有竞争力的论文。如果队伍本身对微分方程、线性规划、统计分析这些基础模型不熟悉先补数学基础再谈 skill 提效。另外竞赛对 AI 辅助参赛通常有明确规则使用任何自动化工具或 AI 生成内容前务必阅读当年赛区发布的参赛规则按要求完成必要的声明和合规操作。数据使用也有边界。清洗和绘图的数据必须来自合法渠道涉及个人信息的要先脱敏涉及企业或单位数据要确认授权。图表导出后如果用于论文或公开发布需要确保数据来源和引用说明完整。3. 环境准备与项目目录规划3.1 本地环境检查这套 skill 只需要一个相对干净的 Python 环境。推荐使用 3.8 及以上版本安装依赖时用虚拟环境隔离避免和系统 Python 冲突。如果你的机器上已经装了 Anaconda可以直接创建一个独立环境# 创建并激活虚拟环境命令在 Windows、Linux、macOS 上通用 python -m venv skill_env source skill_env/bin/activate # Windows 使用 skill_env\Scripts\activate然后安装基础依赖pip install pandas numpy matplotlib seaborn openpyxlpandas 负责表格读取与清洗numpy 负责数值计算matplotlib 和 seaborn 负责图表绘制openpyxl 用来读写 Excel 文件。如果后面要封装 HTTP API再额外安装pip install fastapi uvicorn python-multipart3.2 推荐目录结构比赛环境文件多且乱强烈建议在拿到赛题的第一时间就建立统一目录。下面是一个可以直接套用的结构project/ ├── data/ │ ├── inputs/ # 原始数据放这里 │ ├── outputs/ # 清洗后的数据 │ └── raw.csv # 单份数据也可以直接放在 data 下 ├── outputs/ │ └── figs/ # 图表输出目录 ├── skills/ │ ├── problem_analysis/ # 问题分析 skill │ ├── data_process/ # 数据处理 skill │ └── plot/ # 图表绘制 skill ├── scripts/ │ ├── data_clean.py │ ├── plot_charts.py │ └── batch_run.py └── README.md把原始数据、清洗数据、图表输出分开存放最大的好处是比赛最后写论文时能快速找到素材不会出现“图在哪、数据是哪一版”的混乱。每一份数据修改后另存为新文件不要覆盖原始文件。4. skill 模块设计与配置文件skill 模块化设计的核心是一份说明文件加若干可执行脚本。说明文件让 AI 或队友理解这个模块是做什么的、输入输出是什么、验收标准是什么脚本负责把流程跑起来。下面给出一个通用 skill 配置模板路径和参数需要按实际项目调整。4.1 skill 文件结构skills/ ├── problem_analysis/ │ ├── SKILL.md │ └── analysis_template.md ├── data_process/ │ ├── SKILL.md │ └── data_clean.py └── plot/ ├── SKILL.md └── plot_charts.py4.2 以数据处理 skill 为例的 SKILL.md# 数模国赛-数据处理Skill ## 功能定位 将竞赛中的原始数据清洗、转换、特征工程标准化输出可直接用于建模的表格。 ## 输入 - 原始数据文件CSV / Excel - 数据说明文档可选 ## 处理流程 1. 加载数据并检查字段类型 2. 处理缺失值数值列用均值或中位数填充类别列用众数填充 3. 去重、去全空列 4. 异常值检测使用 3σ 原则或 IQR 方法 5. 输出标准化编码数据 ## 调用方式 bash python scripts/data_clean.py --input data/raw.csv --output data/processed.csv ## 验收标准 - 无全空列、无重复行 - 数值列无字符串混入 - 输出文件编码为 UTF-8有了这份 SKILL.md无论是队友手动执行还是 AI 调用都能按同一套标准完成数据处理不会出现两个人洗出两份完全不同的表的尴尬情况。5. 问题分析 skill赛题拆解与验收测试5.1 为什么需要单独做一个问题分析 skill很多队伍拿到赛题后直接把题目丢给 AI让 AI 给一个模型就开写。这样做的结果是论文读起来“没有灵魂”题目其实没有被真正拆透。问题分析 skill 要做的是把拆题变成一个可重复、可验收的动作链先把题目背景压缩成三句话再列出关键变量、约束条件和需要假设的点最后给出至少两种建模路线并对复杂度做预判。5.2 问题分析流程模板下面是一个可以直接复制到团队的 analysis_template.md 的模板# 赛题拆解模板 ## 1. 问题背景 用 3 句话概括题目场景确保队伍所有人对题目理解一致。 ## 2. 问题重述 用自己的语言复述要解决什么问题禁止直接抄题目原文。 ## 3. 变量定义表 | 变量名 | 含义 | 类型 | 单位 | | --- | --- | --- | --- | ## 4. 约束条件 - 硬约束题目中不可违反的条件 - 软约束可以通过目标函数权衡的条件 ## 5. 假设清单 每个假设都写明对结果的影响方便后期在论文中说明局限性。 ## 6. 建模路线对比 | 路线 | 模型 | 输入 | 输出 | 复杂度 | 风险点 | | --- | --- | --- | --- | --- | --- |5.3 验证问题分析是否达标判断问题分析 skill 是否跑通的标志很简单队伍里任何一个人不看题目原文只看拆解文档也能复述出这道题要做什么、数据从哪里来、输出结果应该是什么样。如果拆解文档里变量表是空的、约束条件只有一条、假设清单混乱说明还没有完成。建议在拿到赛题后 2 到 3 小时内完成问题分析不要在这个阶段纠结具体模型公式。拆题越清楚后面的数据清洗和建模越顺利。这个阶段产出的变量定义表要保留到论文写作阶段避免前后不一致。6. 数据处理 skill清洗脚本与效果验证6.1 功能说明数据处理 skill 是整个流程里最容易标准化、也最容易出问题的一环。竞赛中拿到的数据普遍存在列名不规范、单位混用、缺失值、重复记录、文本数字混在一起等问题。下面提供一个通用清洗脚本它会把 CSV 或 Excel 读进来去掉全空行和全空列去重然后把数值类型的文本列自动转成数字。# scripts/data_clean.py # 通用数据清洗脚本读取原始数据输出标准化表格 import pandas as pd from pathlib import Path def load_data(path: str) - pd.DataFrame: path Path(path) if path.suffix .csv: return pd.read_csv(path, encodingutf-8-sig) if path.suffix in (.xlsx, .xls): return pd.read_excel(path) raise ValueError(f不支持的文件格式: {path.suffix}) def clean(df: pd.DataFrame, drop_duplicates: bool True) - pd.DataFrame: # 去除全空列和全空行 df df.dropna(axis1, howall).dropna(axis0, howall) if drop_duplicates: df df.drop_duplicates() # 数值列统一转为 float非数值列保留为对象 for col in df.columns: if df[col].dtype object: numeric pd.to_numeric(df[col], errorscoerce) if numeric.notna().sum() 0.8 * df[col].notna().sum(): df[col] numeric return df def fill_missing(df: pd.DataFrame) - pd.DataFrame: for col in df.columns: if df[col].dtype in (float64, int64, float32, int32): df[col] df[col].fillna(df[col].median()) else: df[col] df[col].fillna(df[col].mode()[0] if not df[col].mode().empty else 未知) return df if __name__ __main__: df load_data(data/raw.csv) df_clean fill_missing(clean(df)) df_clean.to_csv(data/processed.csv, indexFalse, encodingutf-8-sig) print(f清洗完成共 {len(df_clean)} 行{len(df_clean.columns)} 列)这个脚本不是银弹。业务含义明显的数据不能盲目填充中位数比如某列是“是否发生故障”0 和 1 的缺失值用中位数填充就没有意义。使用时要根据题目说明文档判断每个字段应该怎么处理。6.2 效果验证方法假设你有一份 data/raw.csv里面混了空行、重复行和字符串形式的数字运行python scripts/data_clean.py如果输出清洗完成共 120 行5 列并且用 pandas 重新读取 processed.csv 后没有报类型错误说明清洗通过。更严格的验证方式是打印每一列的数据类型和缺失值比例import pandas as pd df pd.read_csv(data/processed.csv, encodingutf-8-sig) print(df.info()) print(df.isna().sum())正常情况下 processed.csv 应该没有全空列数值列的类型是 float64 或 int64缺失值数量为 0。如果输出仍有缺失值说明 fill_missing 阶段没有覆盖所有列需要回去检查填充逻辑。6.3 常见失败场景清洗脚本最常见的问题是编码。很多比赛数据会用 GBK 编码保存直接用 utf-8-sig 读取会报 UnicodeDecodeError。这时可以把读取参数改成pd.read_csv(path, encodinggbk)或者使用 pandas 的自动编码识别在读取前用 chardet 检测文件编码。另一个问题是数字列里混着“暂无”“-”这类占位符to_numeric 会把这些转成 NaN后续填充逻辑要能容忍这种情况。7. 图表绘制 skill论文级图表与验证7.1 论文图表的基本要求数模论文里的图表不只是展示结果更是论文评审的重要依据。图表绘制 skill 要解决两个问题一是风格统一二是输出尺寸满足论文排版需求。一套统一风格包含同一字体、同一种配色、统一分辨率、坐标轴标签完整。下面给出一个通用绘图配置脚本包含折线图和相关性热力图两个最常用的图表类型。# scripts/plot_charts.py # 配置化图表绘制每个图表由一组配置驱动 import pandas as pd import matplotlib.pyplot as plt import seaborn as sns plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False def plot_line(df: pd.DataFrame, x: str, y: list, output: str line.png): fig, ax plt.subplots(figsize(10, 5)) for col in y: ax.plot(df[x], df[col], labelcol, markero) ax.set_xlabel(x) ax.set_ylabel(数值) ax.set_title(f{x} 与 {, .join(y)} 的关系) ax.legend() ax.grid(True, alpha0.3) fig.tight_layout() fig.savefig(output, dpi150) plt.close(fig) def plot_corr(df: pd.DataFrame, output: str corr.png): numeric df.select_dtypes(includenumber) fig, ax plt.subplots(figsize(8, 6)) if len(numeric.columns) 1: sns.heatmap(numeric.corr(), annotTrue, cmapcoolwarm, axax) fig.tight_layout() fig.savefig(output, dpi150) plt.close(fig) if __name__ __main__: data pd.read_csv(data/processed.csv, encodingutf-8-sig) numeric_cols data.select_dtypes(includenumber).columns.tolist() if len(numeric_cols) 1: plot_line(data, data.columns[0], numeric_cols[:3], outputs/figs/line.png) if len(numeric_cols) 2: plot_corr(data, outputs/figs/corr.png) print(图表绘制完成结果输出到 outputs/figs 目录)7.2 图表绘制测试运行python scripts/plot_charts.py然后检查 outputs/figs 目录是否生成 line.png 和 corr.png。打开图片重点看三处中文字体是否乱码、坐标轴标签是否完整、图例是否遮挡数据。中文字体问题最常见如果系统上没有 SimHei可以换成“Microsoft YaHei”或者系统自带的其他中文字体或者直接把字体文件路径写进配置import matplotlib.font_manager as fm font fm.FontProperties(fname/path/to/font.ttf) plt.rcParams[font.family] font.get_name()7.3 图表验收清单判断图表是否达到论文标准可以对照这份清单图片分辨率是否达到 150dpi 以上图中所有文字是否清晰可读坐标轴是否有单位和标签图例是否说明每个系列的含义颜色方案是否统一整篇论文不超过 2 到 3 个配色图片文件名是否与论文中的图编号对应。比赛时时间紧张不建议临时手写绘图代码。把常用图表模板提前准备好比赛时只改数据和标签是最稳妥的做法。8. 批量任务、接口 API 与运行效率8.1 批量处理多个数据文件竞赛中经常出现多张数据表需要相同处理流程的情况。比如题目给了 5 年的数据、每个年份一个文件或者多个省份的观测数据这时手工逐个跑一遍效率太低。批量脚本可以遍历输入目录自动处理所有文件并输出对应结果。# scripts/batch_run.py # 批量处理遍历输入目录逐文件执行数据清洗和图表绘制 from pathlib import Path import pandas as pd from data_clean import load_data, clean, fill_missing from plot_charts import plot_line, plot_corr def process(path: Path): print(f开始处理{path.name}) df fill_missing(clean(load_data(str(path)))) out_sub Path(outputs) / path.stem out_sub.mkdir(parentsTrue, exist_okTrue) df.to_csv(out_sub / processed.csv, indexFalse, encodingutf-8-sig) numeric_cols df.select_dtypes(includenumber).columns.tolist() if len(numeric_cols) 2: plot_corr(df, str(out_sub / corr.png)) if len(numeric_cols) 1: plot_line(df, df.columns[0], numeric_cols[:3], str(out_sub / line.png)) print(f完成{path.name}) if __name__ __main__: inputs Path(data/inputs) for f in sorted(inputs.glob(*.csv)) sorted(inputs.glob(*.xlsx)): process(f)批量任务要注意两个问题。第一单个文件处理失败不能中断整个流程建议在 process 函数里加 try/except失败时打印错误信息并跳过。第二输出目录要按文件名区分避免文件覆盖。上面的脚本已经把每个文件的输出放在以文件名命名的子目录里。8.2 封装为 HTTP API 服务如果队伍人数多需要多人共用一套数据处理和绘图能力可以把脚本封装成 FastAPI 服务。这样团队里不熟悉 Python 的同学也能通过网页或接口直接上传数据、获取结果。# scripts/api_service.py # 示例将数据清洗和绘图封装为 HTTP API需要按实际项目调整 from fastapi import FastAPI, UploadFile import pandas as pd from data_clean import clean, fill_missing from plot_charts import plot_corr app FastAPI() app.post(/clean) async def clean_file(file: UploadFile): df pd.read_csv(file.file, encodingutf-8-sig) cleaned fill_missing(clean(df)) return { rows: len(cleaned), columns: len(cleaned.columns), missing: int(cleaned.isna().sum().sum()), sample: cleaned.head(3).to_dict(orientrecords) } app.post(/plot) async def create_plot(file: UploadFile): df pd.read_csv(file.file, encodingutf-8-sig) cleaned fill_missing(clean(df)) plot_corr(cleaned, outputs/api_corr.png) return {status: ok, output: outputs/api_corr.png}启动服务uvicorn scripts.api_service:app --host 127.0.0.1 --port 8000然后可以用 curl 验证接口curl -X POST http://127.0.0.1:8000/clean \ -F filedata/raw.csv接口返回 JSON 格式的行数、列数、缺失值数量和样例数据说明接口已经正常工作。封装 API 时要注意只监听 127.0.0.1不要暴露到公网避免别人直接往你服务器上传数据。8.3 运行效率与资源占用观察数据处理和图表绘制的资源占用不像深度学习模型那么夸张但也不是完全不需要关注。当数据量达到几十万行、列数有几十列时内存占用会明显上升。观察方法有两种一是在命令行用 time 命令统计脚本总耗时二是用 psutil 或系统任务管理器观察内存变化。time python scripts/data_clean.py降低内存占用的常用手段只读取需要的列不要全表读入把不用的列在清洗后立刻删除用 pd.to_numeric 压缩数据类型数据量过大时用分块读取chunks pd.read_csv(data/large.csv, chunksize10000) result [] for chunk in chunks: result.append(clean(chunk)) df pd.concat(result, ignore_indexTrue)比赛期间如果遇到数据文件特别大先处理成小文件再建模不要一上来就全量加载。9. 常见问题与排查方法问题现象可能原因排查方式解决方案读取 CSV 报 UnicodeDecodeError文件编码不是 UTF-8用记事本或 vim 查看文件编码将读取参数改为 gbk或先用文本编辑器另存为 UTF-8清洗后列数变少dropna(axis1) 把部分缺失列删掉了打印删除前的列名确认全空列定义是否符合预期必要时改为手动删除指定列数值列变成 object 类型列中混入文本占位符打印该列取值分布先替换占位符为 NaN再做 to_numeric 转换中文字体显示为方块系统缺少对应字体查看 matplotlib 字体警告指定系统中文字体文件路径图例遮挡数据图例位置不合理打开图片观察设置 locupper left 或调整 figsize批量任务一个文件报错中断没有 try/except 保护查看错误堆栈在循环内部捕获异常并跳过接口返回 500 错误上传文件格式不支持查看服务日志检查接口是否只支持 CSV扩展支持 Excel文件被覆盖输出路径重复检查目录结构按输入文件名建立子目录清洗后数据量骤减去重逻辑太激进比较去重前后行数把 drop_duplicates 限定在关键列上比赛现场找不到输出文件目录结构混乱检查工作目录使用绝对路径并统一 outputs 目录上面这些问题前三个在数据处理中最常见中文字体问题在图表绘制中最常见。建议比赛前一天把脚本在比赛环境完整跑一遍确认没有路径或编码问题后再封箱。10. 最佳实践与使用建议10.1 第一天先完整跑通一条流程拿到赛题后先不要急着读论文或套模型。按照问题分析 skill 完成拆题然后把题目数据跑一遍数据处理和图表绘制的默认脚本确认输出正常。这样即使后面换模型、换思路你手里已经有一份干净的标准化数据和一组可用的基础图表。10.2 版本管理比想象中重要比赛三天代码和数据会改很多次。建议用 Git 管理项目至少做到“当天结束前提交一次”。如果不熟悉 Git也可以用最简单的办法每次修改前把文件复制一份文件名带上日期和版本号。这个习惯能避免比赛最后一天出现“改完数据处理脚本后原图消失”的情况。10.3 把 skill 文档写进团队协作流程SKILL.md 不只是给 AI 看的也是给队友看的。建议队伍里负责写作的同学也读一遍数据处理和图表绘制两个 skill 的说明这样他在写论文时知道手上的表是哪一步生成、图表是怎么画的写出来的分析才有依据。问题分析 skill 产出的变量定义表要一直沿用到最后论文的模型假设和符号说明章节。10.4 合规使用工具和数据如果要在比赛中借助 AI 工具一定要确认竞赛规则是否允许、需要不需要申报。数据处理脚本生成的图表如果引用外部数据要在论文中注明数据来源。涉及未公开数据的不要擅自上传到在线平台优先使用本地脚本处理。10.5 下一步扩展方向这套 skill 目前覆盖了数据竞赛中最高频的三个模块。后续可以继续扩展把常用统计检验做成单独的 skill 模块把论文排版规范固化到 LaTeX 模板里把数据标准化与归一化封装成可配置参数甚至把整套流程接入团队自己的 API 服务参赛时所有成员统一调用。先把基础流程跑顺再逐步叠加新模块是最务实推进方式。建议把这套方案在模拟赛上完整跑一遍把踩到的坑提前排掉。