2026-10-01 17:43:48 +08:00
|
|
|
|
# STATUS — 当前进度
|
|
|
|
|
|
|
2026-10-02 15:18:15 +08:00
|
|
|
|
> 更新日期:2026-10-02
|
2026-10-01 17:43:48 +08:00
|
|
|
|
|
|
|
|
|
|
## 本次任务
|
|
|
|
|
|
|
2026-10-01 23:11:48 +08:00
|
|
|
|
**第一阶段(已完成)**:审查并精简 ChatGPT 的建库建议 → 生成骨架文件 →
|
|
|
|
|
|
配置 conda 与 venv 环境 → 初始化 git 仓库 → 接入 Gitea 远端。
|
|
|
|
|
|
两套环境均已建成并通过验证,仓库已推送到 `code.guzhujushi.cn`。
|
2026-10-01 17:43:48 +08:00
|
|
|
|
|
2026-10-01 23:11:48 +08:00
|
|
|
|
**第二阶段(进行中)**:按 `docs/03-roadmap.md` 的 L0 → L1 顺序**逐个实现函数**,
|
|
|
|
|
|
用户本人写 `src/`、Codex 负责审查 + `tests/`(决策 25)。
|
2026-10-03 13:17:58 +08:00
|
|
|
|
当前 8/12:`Result`、`get_rng`/`set_seed`、`load_table`/`save_table`、`clean_missing`、`detect_outliers`、`normalize`/`standardize`、`describe`。
|
2026-10-01 17:43:48 +08:00
|
|
|
|
|
|
|
|
|
|
## 任务清单
|
|
|
|
|
|
|
|
|
|
|
|
### ✅ 已完成
|
|
|
|
|
|
|
|
|
|
|
|
**A. 建议审查与精简**
|
|
|
|
|
|
- [x] 通读 `chatGPT_Suggestion.md`(33 节,约 2.4 万字),输出 `docs/01-suggestion-review.md`
|
|
|
|
|
|
- 总裁决:**方向对,量级错**
|
|
|
|
|
|
- 14 个包 → **7 个**;约 250 个函数 → **约 40 个**;5 个 Result 类 → **1 个**
|
|
|
|
|
|
- 单函数文档要求 10 项 → **2 档**(只有约 15 个招牌算法写完整卡片)
|
|
|
|
|
|
- 逐项给出"砍什么 / 为什么 / 替代什么",并补上原文缺失的六件事
|
|
|
|
|
|
(论文产出链路、指标方向与量纲、时间预算、可复现性、测试测什么、离线约束)
|
|
|
|
|
|
|
2026-10-01 17:45:54 +08:00
|
|
|
|
**B. 骨架文件生成**(76 个文件,约 6800 行)
|
2026-10-01 17:43:48 +08:00
|
|
|
|
- [x] `docs/02-architecture.md` 架构、`docs/03-roadmap.md` 路线图与**永久不做清单**
|
|
|
|
|
|
- [x] `docs/04-environment.md` 环境文档、`docs/dev/function-card-template.md` 卡片模板
|
|
|
|
|
|
- [x] `src/mcm_toolkit/` 7 个包 23 个模块(**只有签名 + docstring + `NotImplementedError`**)
|
|
|
|
|
|
- [x] `tests/` 9 个文件、`examples/` 4 个、`problems/` `notebooks/` `figures/` `tables/`
|
|
|
|
|
|
- [x] `pyproject.toml`(核心依赖 4 个 + 6 组 extras)、`environment.yml`
|
2026-10-01 17:45:54 +08:00
|
|
|
|
- [x] `.gitignore` `.gitattributes` `.editorconfig` `LICENSE` `CHANGELOG.md` `README.md`
|
2026-10-01 17:43:48 +08:00
|
|
|
|
- [x] 脚本 `scripts/setup-venv.ps1` `setup-conda.ps1` `doctor.ps1`
|
|
|
|
|
|
|
|
|
|
|
|
**C. 环境配置**
|
2026-10-01 17:45:54 +08:00
|
|
|
|
- [x] **venv 已建好**:`.venv`(10.5 MB,Anaconda base + `--system-site-packages`)
|
2026-10-01 17:43:48 +08:00
|
|
|
|
+ `pip install -e . --no-deps --no-build-isolation`;
|
2026-10-01 17:45:54 +08:00
|
|
|
|
可直接导入 numpy 2.4.6 / scipy 1.18.1 / pandas 3.0.6 / matplotlib 3.11.2 /
|
|
|
|
|
|
sklearn 1.9.1 / statsmodels 0.15.0 / networkx 3.6.1 / sympy 1.14.0
|
|
|
|
|
|
(版本随 base 走,base 升级后自动同步)
|
2026-10-01 17:43:48 +08:00
|
|
|
|
- [x] **conda 环境已建好**:`D:\anaconda\envs\mcm-toolkit`(1.55 GB,Python 3.13.15)
|
|
|
|
|
|
- 科学栈:numpy 2.4.6 / scipy 1.18.1 / pandas 3.0.6 / matplotlib 3.11.2 /
|
|
|
|
|
|
sklearn 1.9.1 / statsmodels 0.15.0 / networkx 3.6.1 / sympy 1.14.0(MKL 后端)
|
|
|
|
|
|
- 已补装 pip-only 依赖:SALib、pymoo 0.6.2、pyright 1.1.414
|
|
|
|
|
|
- 已在本项目中可编辑安装
|
|
|
|
|
|
- 实测耗时 868 秒,下载约 3 GB
|
|
|
|
|
|
- [x] **Anaconda base 已升级** 2025.12 → **2026.07**(365 个包,下载 638 MB,耗时 1033 秒)
|
2026-10-01 17:45:54 +08:00
|
|
|
|
- conda 自身 25.11.1 → **26.7.3**(实测复核)
|
2026-10-01 17:43:48 +08:00
|
|
|
|
- 并把项目环境 numpy 对齐到 base 的 2.4.6,**两套环境数值栈现已完全一致**(MKL 后端)
|
|
|
|
|
|
- 升级前已用 `conda list -n base --revisions` 留了回滚点
|
|
|
|
|
|
- [x] 环境脚本按实测结果重写:`setup-conda.ps1` 默认改为**精准包列表**
|
|
|
|
|
|
(`--clone base` 实测会走完整下载安装,不再是"离线快捷方式")
|
|
|
|
|
|
|
2026-10-01 17:45:54 +08:00
|
|
|
|
**D. Git 仓库**
|
|
|
|
|
|
- [x] `git init -b main`,`core.autocrlf=false`,首次提交
|
|
|
|
|
|
`5319589`(76 文件 / 6812 行),工作区干净
|
|
|
|
|
|
- [x] `git ls-files --eol` 复核:**全部 LF**,`.gitattributes` 生效
|
|
|
|
|
|
- [x] 仓库由**本人账户 guzhu** 创建(见决策 17)
|
2026-10-01 17:56:12 +08:00
|
|
|
|
- [x] **远端 Gitea 已接通并推送**:`origin` = `git@code.guzhujushi.cn:guzhujushi/MCM-ICM_Toolkit.git`,
|
|
|
|
|
|
`main` 跟踪 `origin/main`,远端 HEAD = `96080b9`,76 个文件已在服务器上(见决策 19/20)
|
|
|
|
|
|
- [x] 推送通道:公网 22 被防火墙过滤 → 改用 Tailscale(`100.115.86.48:22`),
|
|
|
|
|
|
`~/.ssh/config` 加了一条域名别名,remote 里仍写域名
|
2026-10-01 17:45:54 +08:00
|
|
|
|
|
2026-10-03 13:17:58 +08:00
|
|
|
|
**E. L0 实现进度(8/12)**
|
2026-10-01 18:48:43 +08:00
|
|
|
|
- [x] `core/result.py` 的 `Result`
|
|
|
|
|
|
- `__repr__`:单行紧凑;`data` 只给类型与规模,**绝不**整数组打印
|
|
|
|
|
|
(十万级数组的 repr 实测仍 < 200 字符);`success` 恒在
|
|
|
|
|
|
- `summary()`:Markdown 表格,可直接贴进论文;
|
|
|
|
|
|
行序 `success` → `params.*` → `metrics.*` → `extras.*`;
|
|
|
|
|
|
float 走 `.6g`,`|` 转义,`message` 以引用行附在表后;幂等无副作用
|
|
|
|
|
|
- 测试:`tests/test_core.py` 去掉 skip + 新增 3 条
|
|
|
|
|
|
(默认值/失败路径/大数组、Markdown 结构、可重复调用)
|
2026-10-01 19:38:59 +08:00
|
|
|
|
- [x] `core/random.py` 的 `get_rng` / `set_seed`(**设计由用户本人写**,Codex 补齐类型校验)
|
|
|
|
|
|
- 无参 `get_rng()` 复用**同一个模块级生成器**且会推进:既保证重跑一致,
|
|
|
|
|
|
又避免两个都省略 `random_state` 的函数抽到同一串数(原决策 24 的取舍已消掉)
|
|
|
|
|
|
- `get_rng` 收 `int` / `np.integer` / `Generator` / `None`,其余类型**抛 `TypeError`**:
|
|
|
|
|
|
`np.int64` 不是 `int` 的子类,曾因此静默退回全局流
|
|
|
|
|
|
- `set_seed` 同时调 `np.random.seed`,覆盖 sklearn / statsmodels 走的 numpy 旧全局
|
|
|
|
|
|
(全项目**唯一**碰旧接口的地方,带 `# noqa: NPY002` 与理由)
|
|
|
|
|
|
- 测试:`TestRandom` 共 7 条(可复现、透传、无参跟随、旧全局、np.integer、非法类型、共享推进)
|
2026-10-01 23:11:48 +08:00
|
|
|
|
- [x] `data/io.py` 的 `load_table`(+ `save_table`,原属 L1,顺手落地)
|
|
|
|
|
|
- 实现由**用户本人**写(决策 25),Codex 只做审查 + 补测试
|
|
|
|
|
|
- `.csv` / `.xlsx` / `.xls` 按扩展名分派;`.csv` 默认编码探测
|
|
|
|
|
|
utf-8 → utf-8-sig → gbk → gb18030,显式传 `encoding=` 时不再探测
|
|
|
|
|
|
- `na_values` 默认吃下空串 / `NA` / `N/A` / `#N/A` / `null` / `-`
|
|
|
|
|
|
- 不支持的扩展名抛 `ValueError`;文件不存在抛带路径的 `FileNotFoundError`
|
2026-10-01 23:26:47 +08:00
|
|
|
|
- `save_table` 的校验顺序已修正:后缀判断提到 `mkdir` 之前
|
|
|
|
|
|
(此前传 `.txt` 会先留下一个空目录再抛错)
|
|
|
|
|
|
- 测试:`tests/test_data.py` 由 1 条(且被模块级 skip 掉)扩到 **9 条**
|
2026-10-01 23:22:40 +08:00
|
|
|
|
- docstring 的 `Parameters` / `Raises` 已按 §4.7 补齐(Codex 代写,用户授权)——
|
|
|
|
|
|
numpydoc 格式,对齐参考实现 `core/random.py` 的 `get_rng`
|
2026-10-02 15:04:13 +08:00
|
|
|
|
- [x] `data/clean.py` 的 `clean_missing`(L0 第 4 项)
|
|
|
|
|
|
- 实现由**用户本人**写,Codex 只做审查、补测试与文档
|
|
|
|
|
|
- `threshold` 用 `math.ceil` 算 `min_non_na`:3 列、阈值 0.5 时必须是 2,
|
|
|
|
|
|
写 `int()` 截断会漏删
|
|
|
|
|
|
- 顺手落地兄弟函数 `impute_missing` / `winsorize`(原属 L1)
|
2026-10-02 15:41:08 +08:00
|
|
|
|
- [x] `data/clean.py` 的 `detect_outliers`(L0 第 5 项,S 档,**实现由用户本人写**)
|
|
|
|
|
|
- 语义由用户本人定:**非数值列不参与统计,掩码里恒 `False`**(见决策 32)
|
|
|
|
|
|
- 三轮修掉的 4 个 bug:`threshold` 范围校验放错函数、IQR 上界符号、
|
|
|
|
|
|
`is_series` / `is_ld_array` 判在类型转换之后(永远为 False)、文本列上算分位数直接崩
|
2026-10-02 15:48:12 +08:00
|
|
|
|
- 关键教训:**限制掩码 ≠ 限制统计量** —— 只把 `mask[numeric_cols] = ...`
|
2026-10-02 15:41:08 +08:00
|
|
|
|
收窄是不够的,`quantile()` / `mean()` / `std()` 也要一起收窄(见坑 8 / 个人易错点 8)
|
|
|
|
|
|
- 返回形状与输入同形;Series 进 Series 出(列名保留)、一维数组进一维布尔数组出
|
2026-10-02 15:48:12 +08:00
|
|
|
|
- **S 档函数卡片已写**:`docs/algorithms/detect_outliers.md`
|
|
|
|
|
|
(含"为什么不返回 `Result`"、非数值列恒 `False` 的两条备选路、`ddof` 口径不一致等)
|
|
|
|
|
|
- 测试:`tests/test_data.py` 该函数共 **9 条**
|
|
|
|
|
|
- [x] `data/clean.py` 的两处收尾(**Codex 代写,用户授权**)
|
|
|
|
|
|
- `impute_missing` 的 mode 分支改为**返回新表**(原先就地改调用方的表,与另外四支不一致)
|
|
|
|
|
|
—— 最后一条 `xfail` 随之转正,**`xfail` 清零**
|
|
|
|
|
|
- `detect_outliers` 补**入参类型校验**(§4.7 要求非法类型抛 `TypeError`):
|
|
|
|
|
|
接受 `DataFrame` / `Series` / `list` / `tuple` / `ndarray`,`dict` 不再接受(决策 33)
|
|
|
|
|
|
- [x] `examples/01_clean_and_describe.py`:`load_table` / `save_table` / `clean_missing` /
|
|
|
|
|
|
`impute_missing` / `detect_outliers` / `winsorize` 六个函数的最小用法,实测可直接跑通
|
2026-10-02 20:43:03 +08:00
|
|
|
|
- [x] `data/transform.py` 的四个函数(**由用户本人实现**):`normalize` / `standardize`(L0 第 6、7 项)、
|
|
|
|
|
|
`log_transform` / `one_hot_encode`(原属 L1,顺手写了)
|
|
|
|
|
|
- `normalize`:三种 method(`minmax` / `vector` / `max`)都**按列**;`feature_range` 校验下界 < 上界;
|
|
|
|
|
|
常量列压到下界而不出 nan(决策 34)
|
|
|
|
|
|
- `standardize`:按列,`ddof` 真的传下去 —— 测试用解析关系钉住
|
|
|
|
|
|
(`ddof=0` → std 恰为 1;`ddof=1` → `sqrt((n-1)/n)` = 0.866)
|
|
|
|
|
|
- `log_transform`:`offset=None` 时自动取 `1 - min(x)`,保证 `x + offset >= 1`
|
|
|
|
|
|
- `one_hot_encode`:自动识别的 dtype 集合已显式补上 `'str'` / `'string'`(见坑 9)
|
|
|
|
|
|
- Codex 清掉 5 条 ruff(RET503 / F541 / RET504 / RET505 / SIM108),并把 `feature_range`
|
|
|
|
|
|
的两条校验提到 `np.asarray` **之前**、修掉说反的报错文案(条件是"下界必须小于上界")
|
|
|
|
|
|
- 测试:**新写 18 条**,其中两条是把原先挂着的 `skip` 转为实跑 —— 见 `tests/test_data.py` 的 transform 段
|
2026-10-02 21:48:27 +08:00
|
|
|
|
- [x] **`transform.py` 的 4 个口径已收口**(2026-10-02,Codex 代修,用户授权"报错顺手修掉"):
|
|
|
|
|
|
- 输入白名单统一成模块级 `_NUMERIC_TYPES`,**`DataFrame` 补进去**并移到 `np.asarray` 之前
|
|
|
|
|
|
(此前 `DataFrame` 不在白名单 → `standardize(df)` / `log_transform(df)` 直接 `TypeError`,
|
|
|
|
|
|
函数体里所有 `is_df` 分支都是**死代码**)
|
|
|
|
|
|
- 三个函数都保持"DataFrame 进 DataFrame 出"(列名 + 索引原样带回),Series 进 Series 出
|
|
|
|
|
|
- `normalize` 的三个 method 分支原来**互相覆盖**(`minmax` / `vector` 算完的结果被末尾
|
|
|
|
|
|
无条件的 `x / max` 冲掉,三种 method 实际都只走 max),改成 `if / elif / else`
|
|
|
|
|
|
- `one_hot_encode` 不再拿 `data.columns` 重包一层(哑变量列名对不上 → 编码列整列丢失)
|
|
|
|
|
|
- `log_transform` 的 `offset` 守卫**写反了**(`offset > 0` 就抛错,恰好拒掉唯一合法用例),
|
|
|
|
|
|
改成校验真正的定义域前提 `min(x) + offset > 0`(见决策 35)
|
|
|
|
|
|
- docstring 按 §4.7 补齐 `Parameters` / `Returns` / `Raises`(Codex 代写,与 `io.py` 同一套 numpydoc 格式)
|
|
|
|
|
|
- 口径定稿后 ruff 4 条 RET505 一并清掉 → `All checks passed`;pyright **2 errors → 0**
|
2026-10-03 13:17:58 +08:00
|
|
|
|
- [x] `stats/descriptive.py` 的 `describe`(L0 第 8 项,**由用户本人实现**,Codex 审查 + 代修)
|
|
|
|
|
|
- **一个静默 bug(最危险的那种)**:`df_num.describe().T` 把表转反了(行 = 变量、列 = 指标),
|
|
|
|
|
|
而 docstring 与 `test_describe_reports_expected_keys` 都要求"行 = 指标、列 = 变量"。
|
|
|
|
|
|
转置后 `.loc[指标名] = <按变量索引的 Series>` 与列名**零交集**,pandas 不报错,
|
|
|
|
|
|
直接把这四行(`missing` / `missing_ratio` / `skewness` / `kurtosis`)**整行填成 NaN**。
|
|
|
|
|
|
去掉 `.T` 一处即修好三件事:方向对了、NaN 没了、`weights` 分支不再报
|
|
|
|
|
|
`cannot set a row with mismatched columns`(见易错点 11、决策 36)
|
|
|
|
|
|
- `median` 行补上(pandas 的 `describe()` 只有 `50%`,而测试契约定的是 `median`)
|
|
|
|
|
|
- 入参放宽到 `list` / `tuple` / `ndarray`(兄弟函数都收,`00_quickstart.py` 传的就是 ndarray)
|
|
|
|
|
|
- `weights` 校验补齐:长度、非一维、NaN/inf、负值、和为 0 都抛带原因的错误
|
|
|
|
|
|
(原先和为 0 时裸抛 `ZeroDivisionError`)
|
|
|
|
|
|
- `zscore`:修 RET505,docstring 补 `Parameters` / `Returns` / `Raises`;
|
|
|
|
|
|
`coefficient_of_variation`:均值为 0 由 `TypeError` 改为 `ValueError`(那是取值问题不是类型问题)、
|
|
|
|
|
|
空数组提前报错(原先静默返回 nan + RuntimeWarning)、改掉"异变系数"错别字
|
|
|
|
|
|
- pyright 的 `DataFrame | Series` 重载问题按坑 8 用 `cast` 收窄;ruff 7 条清到 0
|
|
|
|
|
|
- 测试:`test_stats.py` 去掉**模块级** `pytestmark`(它把 6 条测试**全部**跳过了 ——
|
|
|
|
|
|
决策 26 说的就是这个,实现写完了却零覆盖),改成逐条 skip 未实现的 5 条,
|
|
|
|
|
|
并新写 20 条 describe / zscore / 变异系数用例
|
|
|
|
|
|
- [x] `examples/01_clean_and_describe.py`:填掉末尾的 `TODO(L0)`,加一段 `describe` 输出
|
|
|
|
|
|
- [ ] 剩余 4 项:`correlation_matrix` `bootstrap_ci` `monte_carlo` `save_figure`
|
2026-10-01 18:48:43 +08:00
|
|
|
|
|
2026-10-01 17:43:48 +08:00
|
|
|
|
### 验证结果
|
|
|
|
|
|
|
|
|
|
|
|
| 检查 | venv | conda `mcm-toolkit` |
|
|
|
|
|
|
|---|---|---|
|
2026-10-03 13:17:58 +08:00
|
|
|
|
| `pytest` | 见下(单列) | **102 passed, 39 skipped(0 xfail)** |
|
2026-10-01 17:43:48 +08:00
|
|
|
|
| `import mcm_toolkit` | 0.0.1 / 16 项 | 0.0.1 / 16 项 |
|
2026-10-02 15:18:15 +08:00
|
|
|
|
| `ruff check` | All checks passed | **All checks passed**(0 error) |
|
2026-10-01 17:43:48 +08:00
|
|
|
|
| `scripts/doctor.ps1` | 跑通 | — |
|
|
|
|
|
|
| SALib / pymoo / pyright | 缺失 | 已装 |
|
|
|
|
|
|
|
2026-10-02 13:36:16 +08:00
|
|
|
|
- `pyright`(分析目标 = 工作区 `.venv`):**0 errors, 0 warnings**
|
|
|
|
|
|
(修配置之前是 17 errors,全是"无法解析导入 numpy / pandas",见决策 29 与
|
|
|
|
|
|
`docs/04-environment.md` 坑 7)
|
2026-10-02 15:04:13 +08:00
|
|
|
|
- base 亦已复核:numpy 2.4.6 / scipy 1.18.1 / pandas 3.0.6(与两套环境一致)
|
2026-10-03 13:17:58 +08:00
|
|
|
|
- **141 条用例:102 passed / 39 skipped**。收集数按文件:`test_data.py` 52、`test_api_surface.py` 20、
|
|
|
|
|
|
`test_core.py` 15、`test_solve.py` 9、`test_viz.py` 8、`test_decision.py` 7、`test_stats.py` 25、
|
2026-10-02 20:43:03 +08:00
|
|
|
|
`test_models.py` 5
|
2026-10-02 15:48:12 +08:00
|
|
|
|
- **`xfail` 清零**:累计 7 条"契约已写进 docstring、实现没跟上"的用例全部转正,
|
|
|
|
|
|
决策 30 那套信号(XPASS → 摘 mark)跑完了一个完整闭环
|
|
|
|
|
|
- `examples/01_clean_and_describe.py` 实测跑通(exit 0);`00_quickstart.py` 仍等 `stats` / `viz`
|
2026-10-03 13:17:58 +08:00
|
|
|
|
- 39 条 skip 是等实现的算法(`train_test_split`、`describe`、`bootstrap_ci`、`monte_carlo` 等)
|
2026-10-02 21:48:27 +08:00
|
|
|
|
- **本轮回归(已修)**:`transform.py` 上一版有 3 处真 bug —— 修前 **7 failed / 75 passed**,
|
|
|
|
|
|
且 pyright 在同一处报 `reportArgumentType`。**不是静态误报**:pyright CLI 复现 + 测试真红。
|
|
|
|
|
|
结论:见到红线先跑 CLI 与 `pytest`,**不许直接挂 `# type: ignore`**(见个人易错点 10)
|
2026-10-01 17:43:48 +08:00
|
|
|
|
- 三个 `.ps1` 通过 PowerShell AST 语法解析
|
|
|
|
|
|
|
|
|
|
|
|
### ⚠️ 需要注意 / 遗留
|
|
|
|
|
|
|
2026-10-01 17:45:54 +08:00
|
|
|
|
- [x] ~~两套环境版本不一致~~ → **已解决**:base 升级到 2026.07 后,
|
2026-10-01 17:43:48 +08:00
|
|
|
|
numpy/scipy/pandas/matplotlib/sklearn/statsmodels/networkx/sympy 版本完全一致,
|
|
|
|
|
|
只差 Python 补丁号(3.13.9 vs 3.13.15)。详见 `docs/04-environment.md` §5。
|
2026-10-01 17:56:12 +08:00
|
|
|
|
- [x] ~~Gitea 远程尚未配置~~ → **已配置并推送完成**,见上面 D 节与决策 19/20。
|
|
|
|
|
|
note:仓库当前是 **Public**(匿名 `git ls-remote` 可读),要改私有去 Gitea 仓库设置。
|
2026-10-03 13:17:58 +08:00
|
|
|
|
- [ ] L0 完成 **8/12**(`Result`、`get_rng`/`set_seed`、`load_table`/`save_table`、`clean_missing`、
|
|
|
|
|
|
`detect_outliers`、`normalize`、`standardize`、`describe`),其余按 `docs/03-roadmap.md` 的 L0 → L1 顺序推进;
|
2026-10-02 20:43:03 +08:00
|
|
|
|
详情见上面 E 节
|
2026-10-01 17:45:54 +08:00
|
|
|
|
- [ ] 本机 `exec_command` 在沙箱模式下**完全不可用**
|
|
|
|
|
|
(`helper_unknown_error: setup refresh had errors`),只有提权
|
|
|
|
|
|
(`require_escalated`)模式可用。沙箱模式只允许写 `D:\MCM&ICM_Toolkit`。
|
|
|
|
|
|
- [ ] **副作用**:沙箱通道(Node 子进程)以 `CodexSandboxOffline` 账户运行,
|
|
|
|
|
|
它写出的文件 Owner 是沙箱账户而非 `guzhu`。
|
|
|
|
|
|
实测 `guzhu` 对这些文件仍有 Modify 权限(继承自 `Authenticated Users`),
|
|
|
|
|
|
读写不受影响;但 git 的 **dubious ownership** 检查会因此误报,
|
|
|
|
|
|
所以 `.git` 必须由本人账户创建(见决策 17)。
|
|
|
|
|
|
若以后再用沙箱通道写文件,注意同一问题。
|
2026-10-01 17:43:48 +08:00
|
|
|
|
|
|
|
|
|
|
## 决策记录
|
|
|
|
|
|
|
|
|
|
|
|
| # | 决策 | 理由 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| 1 | 包数从 14 砍到 7 | `regression`/`ml` 重复;`optimization`/`simulation`/`sensitivity` 同族;`dynamics`/`network` 低频 → 降级为模块 |
|
|
|
|
|
|
| 2 | 只保留 1 个 `Result` | 第一版没有任何函数需要区分 5 种结果类型,属过早分类 |
|
|
|
|
|
|
| 3 | 函数清单从 ~250 砍到 ~40 | 4 天赛程的工具,不是 6 个月的框架;没在真题里用过三次的不写 |
|
|
|
|
|
|
| 4 | 删掉 `maximize` / 重复的 `normalize` / 13 个 `plot_*` 等 | 同义或一行转发;`plot(kind=...)` 替代 13 个函数 |
|
|
|
|
|
|
| 5 | 文档从"每函数 10 项"降到 2 档 | 10 项文档的写作成本是实现的 20 倍,是最可能导致项目停滞的一条 |
|
|
|
|
|
|
| 6 | 补上原文缺失的**论文产出链路** `save_table` / `mcm_style` | 美赛是论文比赛;原文只给了一个 `save_figure` |
|
|
|
|
|
|
| 7 | 补上**永久不做清单** | 原文用"建议不要",防不住膨胀;写成硬规则 |
|
|
|
|
|
|
| 8 | venv 用 `--system-site-packages` | 10.5 MB、离线可用;作为轻量开发与断网兜底 |
|
|
|
|
|
|
| 9 | conda 环境用**精准包列表**而非 `--clone base` | 实测 `--clone` 会重放 base 全套包并逐个下载(连 pandoc 都下),远慢于精准列表 |
|
|
|
|
|
|
| 10 | 生成的是**签名 + docstring + NotImplementedError** | 用户要自己读代码学算法;骨架定接口,实现留给学习过程 |
|
|
|
|
|
|
| 11 | `.ps1` 写成**纯 ASCII**(英文注释/输出),而非中文 | Windows PowerShell 5.1 无 BOM 时按 GBK 解析 `.ps1`,中文直接导致语法错误;保留中文就必须加 BOM,违反 AGENTS.md |
|
|
|
|
|
|
| 12 | `.ps1` 用 LF 而非 CRLF | 遵守 AGENTS.md「shell 脚本 UTF-8 无 BOM + LF」;PS 5.1 对 LF 无问题 |
|
|
|
|
|
|
| 13 | `chatGPT_Suggestion.md` 保持原样 | 用户手写的输入文件,不属于本次产物,不做无谓改动 |
|
|
|
|
|
|
| 14 | base 升级用 `conda update -n base --all`,而不是装新 conda | 计划干净(365 更新 / 0 删除 / 0 冲突),且能保留既有的 `lingbot-map` 环境 |
|
|
|
|
|
|
| 15 | 项目环境 numpy **降**到 base 的 2.4.6 | 升 base 的 numpy 会连带把 BLAS 从 MKL 换成 OpenBLAS;宁可降一个 minor,也不动整套线性代数后端 |
|
|
|
|
|
|
| 16 | 新增 `.gitattributes` 强制 LF | 仓库要给队友在 Windows/WSL/Linux 上 clone,不固定行尾会产生"整文件都变了"的假 diff |
|
2026-10-01 17:45:54 +08:00
|
|
|
|
| 17 | `.git` 由**本人账户 guzhu** 重建,不做 `safe.directory` 豁免 | 沙箱通道建的 `.git` Owner 是 `CodexSandboxOffline`,git 会报 dubious ownership。加全局豁免是把问题藏起来;直接以本人账户重建,仓库和远程(Gitea)身份一致 |
|
|
|
|
|
|
| 18 | `core.autocrlf=false`(仓库级) | 配合 `.gitattributes` 的 LF 策略,避免 Windows 上 checkout 又转成 CRLF |
|
2026-10-01 17:56:12 +08:00
|
|
|
|
| 19 | Gitea 的 SSH **走 Tailscale 内网**,不在公网开 22 | 实测公网 `8.145.36.108:22` 超时(服务器侧过滤,本机出站 22 没被封:github.com:22 可通),而 Tailscale `100.115.86.48:22` 可达且 `git@` 认证直接过 Gitea。remote 里仍写域名,域名→内网 IP 的映射放在 `~/.ssh/config`,换机只改一处 |
|
|
|
|
|
|
| 20 | 首次推送用 `--force-with-lease` **覆盖** Gitea 的 `Initial commit` | 远端那个提交是建仓时自动初始化产生的,与本地无共同祖先,普通 push 必被拒。推送前已把其中的 LICENSE 与手写简介并入本地 `README.md`,原提交仍留在本机对象库(`1c683cf`) |
|
2026-10-01 18:48:43 +08:00
|
|
|
|
| 21 | `Result.__repr__` **不打印 `data` 内容**,只给类型与规模 | 模拟轨迹动辄十万个数,repr 一旦刷屏,traceback / 调试器 / notebook 输出就全废了。要看数据请直接取 `result.data` |
|
|
|
|
|
|
| 22 | `Result.summary()` 的行序 = 字典插入顺序,不排序 | 比赛时"想先看哪个指标"自己决定键的插入顺序即可,工具不该替人排序 |
|
2026-10-01 19:19:15 +08:00
|
|
|
|
| 23 | `set_seed` 内部**允许**调用 `np.random.seed`(带 noqa) | sklearn / statsmodels 默认走 numpy 旧全局状态,只记自己的 `_GLOBAL_SEED` 覆盖不到它们,"提交能重跑"就是假的。旧接口在这一个点上不是"取随机数"而是"设种子",性质不同 |
|
2026-10-01 19:38:59 +08:00
|
|
|
|
| 24 | `get_rng(None)` **复用同一个模块级生成器**(会推进),不每次新建 | **用户本人提出**,取代 Codex 原来"每次新建 `default_rng(全局种子)`"的写法——那样两个都省略 `random_state` 的函数会抽到完全相同的数。共享单例既保证重跑一致,又让流自然推进 |
|
|
|
|
|
|
| 25 | `src/` 下的实现默认由**用户本人**写,Codex 只改 `tests/` 与 `docs/` | 目标是"一边学一边自己写"。曾出现 Codex 直接落盘 `random.py`、与用户编辑器缓冲区冲突导致保存失败。需要代写时用户会明说 |
|
2026-10-01 23:11:48 +08:00
|
|
|
|
| 26 | 未实现的算法用**逐条** `@pytest.mark.skip`,禁用模块级 `pytestmark` | 模块级 skip 会把同文件里**已经写好**的函数一起跳过。本次 `test_data.py` 就这样让 `load_table` 零覆盖,直到有人手动数才被发现 |
|
2026-10-02 15:04:13 +08:00
|
|
|
|
| 30 | 已知待修的契约用 `@pytest.mark.xfail(strict=False)`,不用 skip | skip 会让"契约还没写"和"写了但实现有问题"混在一起,5 条 skip 曾把 `clean.py` 的 bug 全藏住。xfail 照样进报告,修好后自动变 XPASS,是"修好了"的信号,而且 XPASS 不失败,不会卡住提交 |
|
2026-10-02 13:36:16 +08:00
|
|
|
|
| 29 | 静态分析器钉死到工作区 `.venv`,并把 base 的 site-packages 用 `.pth` 链进去 | pyright / Pylance **不认** `pyvenv.cfg` 的 `include-system-site-packages`,`.venv` 自己只有 `pip`;不钉的话它们会去 PATH 上找 python,本机 PATH 上那个是 Codex 运行时的 3.14 shim,没有科学栈,于是报"无法解析导入"。`.pth` 是唯一被 pyright 认的转发手段 |
|
2026-10-01 23:22:40 +08:00
|
|
|
|
| 28 | 不启用 ruff 的 preview 规则集 | `E302`(函数间要 2 个空行)在 ruff 0.16 里是 preview 规则,`select = ["E"]` 默认**不包含**它——所以少一个空行 ruff 照样报 "All checks passed"。行数空行得自己盯,别指望 lint |
|
2026-10-02 20:43:03 +08:00
|
|
|
|
| 34 | 常量列(`max == min`)不定区间也不崩:`normalize` 压到 `feature_range` 下界,`standardize` 给 0 | 除零必须有个确定的答案,不能出 nan / inf。给 0 与 `sklearn` 的 `MinMaxScaler` / `StandardScaler` 一致(sklearn 把常量列的 scale 设为 1,结果就是 0),换库不换结论。行为已由 `test_normalize_constant_column_stays_finite` 与 `test_standardize_constant_column_stays_finite` 钉住 |
|
2026-10-02 15:48:12 +08:00
|
|
|
|
| 33 | `detect_outliers` 只接受 `DataFrame` / `Series` / `list` / `tuple` / `ndarray`,`dict` 一律 `TypeError` | §4.7 要求非法类型抛 `TypeError` 而非静默兜底。`dict` 以前能"碰巧"被 `pd.DataFrame()` 转成表,但那不是文档承诺的形状,静默接受会让调用方以为传什么都行;`tuple` 则补进文档与 `is_ld_array`,与 `list` 同等对待 |
|
2026-10-02 15:41:08 +08:00
|
|
|
|
| 32 | `detect_outliers` 对非数值列恒返回 `False`(既不跳过也不报错) | **用户本人在两条路里选的**。跳过会让 docstring 里"与原数据同形"变成谎话(形状对不上,没法按位置对回原表);报错则让一张带 `city` 列的真题表直接不可用。`False` 的读法是"这一列没有离群点",对文本列是最不坏的解释,也让整表能一次跑完 |
|
2026-10-02 15:18:15 +08:00
|
|
|
|
| 31 | Codex 可**直接改** `src/` 的范围:纯 bug(不改接口与语义)、格式、死代码 | 决策 25 说实现归用户,但"能跑"是底线:`winsorize(pd.Series)` 因 `select_dtypes` 在 `Series` 上不存在而直接崩、测试变红,这种必须当场修。凡是要**选一个语义**的(文本列返回什么、mode 要不要就地改)一律留给用户本人,Codex 只把选项和影响列清楚 |
|
2026-10-01 23:11:48 +08:00
|
|
|
|
| 27 | base 里的 zstandard 残骸目录**改名禁用**,不删除、不重装 | 删掉不可逆;`pip install zstandard` 会给 base 塞一个 conda 记录里根本没有的包,下次 `conda update --all` 又要重新判断。改名后 `import` 变回正常 `ModuleNotFoundError`,pandas 自动跳过 |
|
2026-10-02 21:48:27 +08:00
|
|
|
|
| 35 | `log_transform` 的显式 `offset` 按**定义域前提**校验:`min(x) + offset > 0` 才放行 |
|
2026-10-03 13:17:58 +08:00
|
|
|
|
| 36 | `describe` 的返回表**不转置**:行 = 指标、列 = 变量 |
|
|
|
|
|
|
docstring 与 `test_describe_reports_expected_keys` 早就写死了这个方向,实现里多做的 `.T` 是净负担 —— 且不是"风格不同"那么轻:转置后 `.loc[指标名] = <按变量索引的 Series>` 与列名零交集,pandas **不报错**、把四行整行填成 NaN。方向约定以"能按列名对齐"为准,见易错点 11 |
|
2026-10-02 21:48:27 +08:00
|
|
|
|
原码写的是 `if offset > 0: raise`,把唯一合法的用例(正 offset 正好抬定义域)全拒了,报错文案却是"offset 必须大于 0",自相矛盾。改成校验真正的前提:`log` 要求自变量取正。`offset=0` 对全正数据合法(`offset=None` 的自动分支本来就取 0)。**Codex 代选、待用户确认** —— 若原意是"只收正 offset",改回即可 |
|
2026-10-01 17:43:48 +08:00
|
|
|
|
## 下一步
|
|
|
|
|
|
|
2026-10-03 13:17:58 +08:00
|
|
|
|
1. **`correlation_matrix` 是 L0 里下一个该写的**(A 档,`stats/inference.py`)——
|
|
|
|
|
|
写法和 `describe` 一样:先想"替代了哪段手写代码" → 先写一条会红的测试 → 再实现
|
|
|
|
|
|
→ 补 `examples/` 一行(`docs/03-roadmap.md` §3.2)。
|
|
|
|
|
|
2. 之后按 L0 剩余顺序推进:`bootstrap_ci`(**S 档,要写函数卡片**)→ `monte_carlo`(**S 档**)
|
|
|
|
|
|
→ `save_figure`(A)。
|
2026-10-02 21:48:27 +08:00
|
|
|
|
3. L0 跑通后,找一道真题(建议 2025 C)走完整流程,反向沉淀函数。
|
2026-10-03 13:17:58 +08:00
|
|
|
|
4. **三处口径待你拍板**(Codex 只列选项,不替你选):
|
|
|
|
|
|
- **决策 35**:`log_transform` 的显式 `offset` 按"定义域前提"校验(`min(x) + offset > 0`)。
|
|
|
|
|
|
若原意是"只收正 offset",说一声我改回去。
|
|
|
|
|
|
- **`zscore(df)` 遇到非数值列会静默丢掉那一列**(`describe` 也一样只描述数值列)。
|
|
|
|
|
|
`detect_outliers` 走的是"保留列、掩码恒 False"(决策 32)—— 要不要统一?
|
|
|
|
|
|
- **`coefficient_of_variation` 在均值为负时返回负值**(`σ/μ` 原样输出)。
|
|
|
|
|
|
备选:① 取绝对值 `σ/|μ|`;② 均值为负直接抛 `ValueError`;③ 维持现状 + Notes 提醒(我暂时按 ③ 写的)。
|