Files
MCM-ICM_Toolkit/docs/01-suggestion-review.md
T
guzhujushi 5319589dfd chore: 初始化 MCM/ICM Toolkit 仓库骨架
审查并精简 ChatGPT 的建库建议后落地的第一版骨架,只定接口不写实现。

- 建议审查:14 个包 → 7 个;约 250 个函数 → 约 40 个;5 个 Result 类 → 1 个
  (docs/01-suggestion-review.md)
- docs/:架构、路线图(含永久不做清单)、环境、Git 工作流、函数卡片模板
- src/mcm_toolkit/:core / data / stats / models / solve / decision / viz
  共 23 个模块,均为签名 + docstring + NotImplementedError
- tests/:9 个文件,其中 test_api_surface.py 已通过(20 passed)
- examples/ problems/ notebooks/ figures/ tables/ 骨架
- pyproject.toml(核心依赖 4 个 + 6 组 extras)、environment.yml
- scripts/:setup-venv.ps1(ASCII + LF)、setup-conda.ps1、doctor.ps1
- 环境:.venv(system-site-packages)与 conda 环境 mcm-toolkit 均已建好,
  数值栈版本与 base 完全对齐(numpy 2.4.6 / scipy 1.18.1 / pandas 3.0.6,MKL 后端)
2026-10-01 17:43:48 +08:00

13 KiB
Raw Blame History

ChatGPT 建库建议 · 审查与精简

被审查对象:仓库根目录 chatGPT_Suggestion.md(33 节,约 2.4 万字) 审查日期:2026-10-01


一、总裁决

方向对,量级错。

方向对的地方(保留):把比赛的即用代码沉淀成"竞赛层薄封装 + 高频算法自己实现 + 统一结果接口",而不是攒一堆题解。这个定位是全文最有价值的部分,也是这个仓库存在的理由。

量级错的地方(砍):原文给出 14 个子包、约 250 个函数、每个函数强制 10 项文档。这是一个人 6~12 个月的个人项目体量,不是支撑 4 天比赛的体量。按原文执行,最可能的结局是:前两周写完 core 和 data,然后在 optimization/ 的 6 个文件面前失去动力,仓库停在半成品——这比"只有一个 20 个函数的 mcm_toolkit.py"更糟,因为半成品既不能用于比赛,也不好看。

精简后的目标:

维度 ChatGPT 版 精简版
子包 14 7
函数(v0.1) ~250 ~40(其中第一周只做 12 个)
Result 类 5 1
单函数文档要求 10 项,全体强制 2 档,只有 ~15 个"招牌算法"做全卡片
预计完成周期 —— 4~6 周出可用 v0.1

二、必须保留的(原文的干货)

# 原文主张 为什么留
1 「不要重新造轮子。mcm_toolkit 做竞赛层封装,而不是替代 SciPy/sklearn/NetworkX」 全文最重要的一句。它同时是设计原则和防膨胀闸门
2 统一结果对象(result.params / metrics / success) 真实痛点。比赛时最烦的就是每个函数返回不一样的东西
3 依赖分层:核心 4 个包 + [project.optional-dependencies] 符合轻量化,且让 CI 和赛场安装都能可控
4 顶层 __init__ 不 import *,只导出子包 + 少量高频快捷函数 保留
5 「__all__ 是公开 API 清单,不是导出按钮」 保留,这条纪律要从第一版养成
6 problems/ 沉淀历年真题、notebooks/ 做探索 "每做一题反向沉淀一个通用函数"是这套东西能长大的唯一机制
7 save_figure(fig, path, dpi=300, formats=("png","pdf")) 美赛送稿硬需求,原文提了但严重低估——见第四节
8 参考库定位:SALib / NetworkX / statsmodels / pymoo / SymPy / sklearn 六条定位全部准确,可直接当"别自己写"的白名单
9 A / B / C 三级(自己写 / 自己封装 / 直接调用)的分类框架 框架留,边界要下调(见第三节第 10 条)

三、要砍的

3.1 结构层:14 包 → 7 包

原文的包 处置 理由
core/ 留(4 → 3 文件) 基础设施,必须有
data/ 留(4 文件) 最高频
statistics/ 留,改名 stats/(5 → 3 文件) S 级模块
regression/ + ml/ 合并为 models/ 原文这两块 fit_linear_regression 与 fit_linear 明显重复,一套 fit/predict/score 协议就够了
optimization/ + simulation/ + sensitivity/ 合并为 solve/ 这三者是同一件事的三种形态:"把模型反复算"。分开建三个包,共享的 Result、rng、并行约定要在三处重复
dynamics/ 降级为 solve/dynamics.py,进 v0.2 原文自己承认"不一定主攻 MCM A"。MCM A 一年一题,且 SymPy+SciPy 封装只需 4 个函数,不值得一个独立包
network/ 降级为 solve/graph.py,进 v0.2 只有 ICM D 用;NetworkX 已全部提供。原文列了 5 个子模块 20+ 函数,其中 degree_centrality 之类就是一行转发
decision/ 留但砍半:8 → 4 文件 AHP / TOPSIS / 熵权 / 灰色是中文赛高频,值得留;dea、fuzzy 见下
visualization/ 改 viz/,13 个 plot_* → 1 个 plot(kind=...) + 3 个专用图 见 3.3
utils/metrics.py 取消,指标并入 models/metrics.py 原文第 26 节又建议单列 analysis/ 放同样的函数,三处重复
第 26 节的 analysis/ 取消 与 utils/metrics.py 功能完全重叠
docs/api/ docs/tutorials/ 保留占位,不写内容 自动 API 文档用 mkdocs/sphinx 生成,手写必然过期

3.2 设计层

砍什么 理由 替代
5 个 Result 类 第一版没有任何一个函数需要区分这五种;过早分类会导致大量样板代码 1 个 Result:name / params / metrics / data / success / message,后续真需要时再派生
每个函数 10 项文档(数学定义/适用场景/参数/实现/示例/测试/复杂度/数值稳定性/常见错误/MCM 案例) 对一个一行转发的封装函数写 10 项文档,写作成本是实现的 20 倍。这是最可能导致项目停滞的一条 两档制,见第七节
「__init__.py 里再导出少量高频函数」的具体选择 原文选的是 solve_ode——但 ODE 已被降级 改成 monte_carlo / bootstrap_ci / minimize / parameter_sweep / topsis / compare_models

3.3 函数层:要删的清单

判断标准只有两条:美赛近 10 年题面出现过吗? / 成熟库是不是一行就够? 两条都不满足就删。

删除项 理由 替代
maximize() 就是 minimize 取负 minimize 加 sense="max" 参数
kendall_correlation / partial_correlation 美赛几乎不用;df.corr(method="kendall") 一行 pandas
modified_zscore_outliers / zscore_outliers IQR 和 z-score 两种覆盖 95% 场景 只留 detect_outliers(method="iqr"|"zscore")
distribution_pdf/cdf/ppf 三个独立函数 纯转发 scipy fit_distribution 返回的对象上挂 .pdf/.cdf/.ppf
sample_without_replacement / sample_with_replacement rng.choice(..., replace=) 一行 numpy
brownian_motion / geometric_brownian_motion niche,只有金融题偶尔用 用到再写;random_walk 已覆盖
mmc_metrics / simulate_queue 排队论在美赛出现频率极低,且 simulate_queue 是个完整的离散事件仿真引擎,成本极高 只留 mm1_metrics(闭式解,10 行)
crowding_distance / hypervolume NSGA-II 内部件,属于原文自己划的 C 类 pymoo
dea_efficiency 低频;且要解一堆 LP,实现成本不低 真要用,现场用 scipy.optimize.linprog 拼
fuzzy_comprehensive_evaluation 低频,且"隶属度函数"没有通用形式,做不了通用封装 删
value_iteration + policy_iteration + dynamic_programming 三个 三者是同一族的三种写法,第一版同时做属于过度设计 只留 dynamic_programming(通用)+ knapsack_dp(模板)
weighted_moving_average / holt_trend / seasonal_decompose statsmodels 一行。原文自己也在第 7 节说"做薄封装" 只留 exponential_smoothing 一个包装
grid_sweep parameter_sweep 的特例 合入 parameter_sweep
13 个 plot_* 每个都是 ax 上加两行;拆成 13 个函数后,改一次全局样式要改 13 处 plot(x, y, kind="line"|"scatter"|"hist"|"box"|"heatmap") + plot_correlation_matrix / plot_residuals / plot_convergence 三个有真实逻辑的
normalize 与 minmax_scale 并存 是同一个东西的两个名字 只留 normalize
standardize 与 zscore 并存(一个在 data、一个在 stats) 同上 只留 data.standardize
higher-level:sample_distribution、distribution_pdf 系列 转发 删

净效果:约 250 → 约 40 个函数。

3.4 下调 A/B/C 的边界

原文的 A 类("强烈建议自己实现")里有 dynamic programming、genetic algorithm、sensitivity analysis 等。用于学习时这个清单没问题;但比赛现场要反过来:

  • 比赛时:能用库就用库(SALib 的 sobol_analyze 一定比自己写的对)。
  • 平时:自己实现,目的是"读得懂、改得动、能解释给队友"。
  • 所以自己实现的代码要单独标 _from_scratch 或放在 mcm_toolkit/algo/,默认走库版本。

原文把这两个场景混在一起了。


四、ChatGPT 漏掉的(真正决定比赛成败的)

原文 33 节几乎全是"代码结构",但美赛是论文比赛,不是代码比赛。以下六条原文完全没提或严重低估:

  1. 论文产出链路(最严重的缺失) 工具箱的最终消费者是论文。原文只给了一个 save_figure。至少要补:

    • save_table(df, path, fmt=("csv","md","latex")) —— 结果表直接出 LaTeX,粘贴进论文
    • 全局图样式 mcm_style():字号 ≥ 9pt、线宽 ≥ 1.5、dpi=300、色盲友好调色板、双栏宽度
    • 图注(fig.caption)与"图号—正文引用"的约定
  2. 量纲与方向 normalize 没区分"无量纲化"和"标准化",更没提效益型 / 成本型指标方向。评价类题目(TOPSIS/熵权)翻车基本都翻在这里。

  3. 时间预算 4 天比赛,函数的价值 = 正确性 ÷ 上手时间。原文没有一条关于"够快"的约定:MC 必须向量化、n_resamples 默认值要能在一分钟内跑完、不要引入编译开销。

  4. 可复现性 提了 get_rng,但没提"提交要能复现"。约定:所有带随机的公开函数第一个参数是 random_state,论文附录必须写 seed。

  5. 测试测什么 说了 pytest,没说测什么。应测 已知解析解:MC 积分 vs 解析积分、正态 CI vs 公式值、bootstrap_ci 大样本下收敛到 CLT 值。不要测实现细节。

  6. 离线约束 原文的 extras 设计假设比赛机器能联网。现场装不上包是真实风险,必须有 environment.yml 锁版本 + 一份"最小可用依赖"清单。

另外两条工程问题:

  1. 原文第 32 节把 problems/ notebooks/ 和 src/ 混在一个仓库——这是对的,但要注意 problems/ 会带来大量数据文件,.gitignore 要提前写好(见仓库根目录的 .gitignore)。
  2. 没有"不做"清单。原文用"建议不要",但真正能防膨胀的是写死的"本仓库永远不实现 X"。已补进 docs/03-roadmap.md。

五、精简后的结构

MCM&ICM_Toolkit/
├── src/mcm_toolkit/
│   ├── core/           基础设施:Result / rng / 校验      ← 第一个做
│   ├── data/           读、洗、变换、采样                 ← 最高频
│   ├── stats/          描述、推断、bootstrap              ← S 级
│   ├── models/         回归 + 时序 + ML 薄封装(统一 fit/predict/score)
│   ├── solve/          优化、模拟、敏感性、图、动力学      ← 竞赛主力
│   ├── decision/       熵权 / AHP / TOPSIS / 灰色
│   └── viz/            统一绘图 + 图表导出
├── tests/              tests/test_*.py(按包一一对应)
├── examples/           每个模块一个能跑的最小例子
├── problems/           历年真题(2025_C/ ...)
├── notebooks/          探索用
├── docs/               本目录
├── scripts/            setup-conda.ps1 / setup-venv.ps1
├── pyproject.toml
├── environment.yml
└── STATUS.md           进度

包结构详情与每个包的边界见 02-architecture.md。


六、功能清单分级

见 03-roadmap.md。摘要:

  • L0(第一周,12 个):Result get_rng load_table clean_missing detect_outliers normalize standardize describe correlation_matrix bootstrap_ci monte_carlo save_figure
  • L1(v0.1,共约 40 个):L0 + 回归/时序/优化/敏感性/评价/绘图
  • L2(v0.2):dynamics、graph
  • 永久不做:见 03-roadmap.md 末节

七、开发纪律:文档从 10 项降到 2 档

原文要求每个函数都写 10 项。改成两档:

S 档(招牌算法,约 15 个) —— 用 docs/dev/function-card-template.md 的完整卡片: 数学定义 / 适用场景 / 参数 / 复杂度 / 数值稳定性 / 常见错误 / 最小示例 / 单测 / 赛题用法。 覆盖:bootstrap_ci monte_carlo simulated_annealing dynamic_programming parameter_sweep sobol_analyze topsis entropy_weights ahp_weights gm11 detect_outliers local_sensitivity 等。

A 档(其余,薄封装) —— 只要求:

  1. docstring 里一句话数学含义 + 一句话什么时候用;
  2. 一条 pytest(对齐库结果或已知值)。

不单独写文档。

判断标准:我会不会去改它的内部实现? 会 → S 档;只当转发器用 → A 档。


八、执行顺序(时间盒)

周 目标 交付
1 core + data + stats 骨架;S 档先写 bootstrap_ci monte_carlo normalize detect_outliers L0 全部可跑通
2–3 models + solve/optimize + solve/simulate compare_models 能跑
4 solve/sensitivity + decision + viz 一套端到端 example
5–6 拿一道真题(如 2025 C)从头走一遍,反向补函数 problems/2025_C/ 完成
之后 每做一题 → 沉淀 1~3 个函数 + 对应 test 仓库自然长大

这个顺序的关键是"先能跑通一条完整链路,再补宽度",与原文"先把 14 个包建齐"相反。