2026-10-01 17:43:48 +08:00
|
|
|
|
# 更新日志
|
|
|
|
|
|
|
|
|
|
|
|
格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
|
|
|
|
|
|
版本号参考 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
|
|
|
|
|
|
|
|
|
|
## [Unreleased]
|
|
|
|
|
|
|
|
|
|
|
|
### Added
|
|
|
|
|
|
- 仓库骨架:`src/mcm_toolkit/` 7 个包(core / data / stats / models / solve / decision / viz)
|
|
|
|
|
|
- 顶层 `__init__.py` 只导出 7 个子包 + 8 个快捷函数,`__all__` 即公开 API 清单
|
|
|
|
|
|
- `core.Result`:唯一的结果对象(替代原建议里的 5 个 Result 类)
|
|
|
|
|
|
- `docs/01-suggestion-review.md`:对 ChatGPT 建库建议的审查与精简(14 包 → 7 包,~250 函数 → ~40)
|
|
|
|
|
|
- `docs/02-architecture.md`:包边界、`Result` / RNG / `fit-predict-score` 协议、依赖分层
|
|
|
|
|
|
- `docs/03-roadmap.md`:L0/L1/L2 分级 + **永久不做清单**
|
|
|
|
|
|
- `docs/04-environment.md`:conda / venv 配置与三个已踩的坑
|
|
|
|
|
|
- `docs/dev/function-card-template.md`:S 档算法的函数卡片模板
|
|
|
|
|
|
- `.venv`(基于 Anaconda base,`--system-site-packages`)+ 可编辑安装 —— 10.5 MB,离线可用
|
|
|
|
|
|
- conda 环境 `mcm-toolkit`(`D:\anaconda\envs\mcm-toolkit`)—— Python 3.13.15,含 SALib / pymoo / pyright
|
|
|
|
|
|
- `scripts/setup-conda.ps1` / `scripts/setup-venv.ps1` / `scripts/doctor.ps1`
|
|
|
|
|
|
- `environment.yml`:需联网时的精确复现方案
|
|
|
|
|
|
- `pyproject.toml`:核心依赖只 4 个,其余走 extras
|
|
|
|
|
|
|
2026-10-01 18:48:43 +08:00
|
|
|
|
### Changed
|
2026-10-01 19:38:59 +08:00
|
|
|
|
- `core.get_rng` / `core.set_seed`:实现(L0 第 2 项)。`get_rng` 收 `int` / `np.integer` /
|
|
|
|
|
|
`Generator` / `None`,其余类型抛 `TypeError`;无参调用复用同一个会推进的共享生成器。
|
|
|
|
|
|
`set_seed` 同时覆盖 numpy 旧全局状态,让 sklearn / statsmodels 也可复现。
|
2026-10-01 18:48:43 +08:00
|
|
|
|
- `core.Result`:补上 `__repr__` 与 `summary()` 实现(L0 第 1 项落地)。
|
|
|
|
|
|
`repr` 紧凑单行且不打印 `data` 内容;`summary()` 输出可直接贴进论文的 Markdown 表格。
|
2026-10-01 23:11:48 +08:00
|
|
|
|
- `data.load_table`:实现(L0 第 3 项)。按扩展名分派 `.csv` / `.xlsx` / `.xls`;
|
|
|
|
|
|
`.csv` 默认做编码探测(utf-8 → utf-8-sig → gbk → gb18030),显式传 `encoding=` 时不再探测;
|
|
|
|
|
|
`na_values` 默认吃下空串 / `NA` / `N/A` / `#N/A` / `null` / `-`。
|
|
|
|
|
|
- `data.save_table`:实现(原属 L1,顺手落地)。按扩展名分派,父目录不存在时自动创建,
|
|
|
|
|
|
返回实际写入的 `Path`。
|
2026-10-01 23:22:40 +08:00
|
|
|
|
- `data.load_table` / `data.save_table`:docstring 补 `Parameters` / `Raises`
|
|
|
|
|
|
(`docs/02-architecture.md` §4.7 对每个公开函数的硬要求)。
|
|
|
|
|
|
- `data.load_table` 的返回注解 `Any` → `pd.DataFrame`,与 docstring 的承诺对齐。
|
2026-10-01 18:48:43 +08:00
|
|
|
|
|
2026-10-01 19:38:59 +08:00
|
|
|
|
### Added
|
2026-10-01 20:04:32 +08:00
|
|
|
|
- `docs/02-architecture.md` §4.7「类型约定」:注解要写全、numpy 标量的判断写法、
|
|
|
|
|
|
非法类型必须抛 `TypeError`。配套在 `docs/03-roadmap.md` 的开发纪律里加了指针。
|
2026-10-01 19:38:59 +08:00
|
|
|
|
- `docs/dev/personal-pitfalls.md`:个人易错点清单,**只追加、不通读**
|
|
|
|
|
|
|
2026-10-02 15:04:13 +08:00
|
|
|
|
### Added
|
|
|
|
|
|
- `data.clean`:四个函数落地(**由用户本人实现**)——`clean_missing`(L0 第 4 项)、
|
|
|
|
|
|
`impute_missing` / `detect_outliers` / `winsorize`(原属 L1,顺手写了)。
|
|
|
|
|
|
- `tests/test_data.py`:新增 13 条 clean 行为测试,覆盖 `clean_missing` 的阈值语义与轴向、
|
|
|
|
|
|
`impute_missing` 的 mean/ffill/mode 与全 NaN 列、`winsorize` 的分位点与异常类型。
|
|
|
|
|
|
- `tests/test_data.py`:另加 7 条 `xfail`,把**已知但未修的契约**钉在测试报告里(见 Notes)。
|
|
|
|
|
|
|
|
|
|
|
|
### Changed
|
|
|
|
|
|
- `data.clean`:docstring 按 `docs/02-architecture.md` §4.7 补全 Parameters / Returns / Raises
|
|
|
|
|
|
(Codex 代写,与 io.py 同一套 numpydoc 格式)。
|
|
|
|
|
|
- `data.clean`:ruff 从 6 条清到 1 条——导入分组(I001)、elif 链改 if 加末尾无条件 return
|
|
|
|
|
|
(RET505 / RET503)、去掉多余 f 前缀(F541)、删掉只会被覆盖的 mask 初始化(死代码)、
|
2026-10-02 15:18:15 +08:00
|
|
|
|
去掉行尾空白(W293)。
|
2026-10-02 13:36:16 +08:00
|
|
|
|
本机 PATH 上只有 Codex 运行时的 3.14 shim(无科学栈),且 pyright 不认
|
|
|
|
|
|
`pyvenv.cfg` 的 `include-system-site-packages`。
|
|
|
|
|
|
改为 `[tool.pyright]` 指定 `venvPath = "."` / `venv = ".venv"` /
|
|
|
|
|
|
`pythonVersion = "3.13"`,并让 `scripts/setup-venv.ps1` 往 `.venv` 里写一个
|
|
|
|
|
|
指向 base site-packages 的 `.pth`。pyright 17 errors → **0**。
|
|
|
|
|
|
详见 `docs/04-environment.md` 坑 7。
|
|
|
|
|
|
- `tests/test_data.py`:`df["b"].isna().all()` 的类型是 `Series | bool`,
|
|
|
|
|
|
直接当断言条件 pyright 会报"条件操作数无效",外面套 `bool()`;
|
|
|
|
|
|
两条故意传错类型的用例加 `# type: ignore[arg-type]`。
|
2026-10-01 23:26:47 +08:00
|
|
|
|
- `data.save_table` 的后缀校验排在 `path.parent.mkdir(...)` **之后**,传 `.txt` 会先留下一个
|
|
|
|
|
|
空目录再抛 `ValueError`。改为**先校验、后副作用**,并加回归测试。
|
|
|
|
|
|
- `data/io.py` 里 `__all__` 与下一个 `def` 之间只有 1 个空行(PEP 8 要 2 个)。
|
2026-10-01 23:11:48 +08:00
|
|
|
|
- `tests/test_data.py` 顶上的**模块级** `pytestmark = pytest.mark.skip(...)` 会连带跳过同文件里
|
|
|
|
|
|
已经写好的函数,导致 `load_table` 零覆盖。改为逐条 skip 未实现的算法,并补 8 条 io 测试
|
|
|
|
|
|
(编码探测、NA 归一、后缀校验、缺文件报错、往返读写、类型校验)。测试数 31 → **39 passed**。
|
|
|
|
|
|
- conda base 里 zstandard 的 `*.conda_trash` 残骸目录被 Python 当成 namespace package 导入,
|
|
|
|
|
|
使 `.venv`(= base)的 `pd.read_csv` 抛 `ImportError: Can't determine version for zstandard`。
|
|
|
|
|
|
已把残骸目录改名禁用(**可逆**,未删除),详见 `docs/04-environment.md` 坑 6。
|
2026-10-02 15:18:15 +08:00
|
|
|
|
- `data.clean` 第二轮审查(2026-10-02),Codex 直接修掉 4 处**轻度**问题:
|
|
|
|
|
|
`winsorize(Series)` 因 `select_dtypes` 在 `Series` 上不存在而直接崩(Series 分支提到最前,
|
|
|
|
|
|
并加数值 dtype 守卫);`winsorize` 的 `data.quantile()` 改为只在数值列上算
|
|
|
|
|
|
(文本列不再崩,与已有的 `numeric_cols` 判断对齐);删掉 `detect_outliers` 里已成空操作的
|
|
|
|
|
|
`df = pd.DataFrame(data)`(数据在更早处就转过了,顺手去掉 `df` 这个别名);
|
|
|
|
|
|
清掉行尾空白(W293)、函数体内的连续空行,并把 `clean_missing` 的嵌套 `if` 合并
|
|
|
|
|
|
(SIM102,ruff 最后 1 条)。ruff `1 error` → **`All checks passed`**,pyright 仍 0。
|
|
|
|
|
|
- `tests/test_data.py`:5 条 `xfail` 经 XPASS 信号确认已修好,**摘掉 mark 转正式用例**
|
|
|
|
|
|
(`detect_outliers` 的 4 条 + `winsorize` 混合类型 1 条)。测试 **53 passed / 7 xfailed →
|
|
|
|
|
|
58 passed / 2 xfailed**。
|
|
|
|
|
|
- `CHANGELOG.md`:[Unreleased] 里有一句被重复追加撑坏
|
|
|
|
|
|
("…删掉它即全绿。:分析器会去 PATH 上找 python,"),已修。
|
2026-10-02 15:41:08 +08:00
|
|
|
|
- `data.detect_outliers` 收尾(2026-10-02,**由用户本人实现**):统计量(`quantile` /
|
|
|
|
|
|
`mean` / `std`)与掩码写入**都**收窄到数值列,含文本列的赛题表不再崩;
|
|
|
|
|
|
非数值列在掩码里恒 `False`(用户本人定的语义,见决策 32)。docstring `Notes` 补上这条语义。
|
|
|
|
|
|
- `data.detect_outliers` 里 `data=data.copy()` 是死代码:下面的 `to_frame()` / `pd.DataFrame()`
|
|
|
|
|
|
本来就返回新对象,函数全程也没原地改过 `data`,白白复制一份数据;而且它排在类型分派
|
|
|
|
|
|
**之前**,会把错误入参的报错从 `ValueError` 变成 `AttributeError`。已删。
|
|
|
|
|
|
- `data.detect_outliers`:删掉那行死代码后 pyright 反而报了 1 个真错 ——
|
|
|
|
|
|
`df[Index]` 被类型存根当成 `Series`,`.std()` 于是被判成标量、`std.replace(...)` 非法。
|
|
|
|
|
|
在取列子表处用 `cast(pd.DataFrame, ...)` 按运行时真值收窄。详见 `docs/04-environment.md` 坑 8。
|
|
|
|
|
|
- `tests/test_data.py`:`test_detect_outliers_survives_text_columns` 摘掉 xfail 并加强断言
|
|
|
|
|
|
(文本列必须恒 `False`);新增 `test_detect_outliers_all_text_frame_returns_all_false`
|
|
|
|
|
|
钉住"整表没有数值列"这条边界。测试 **58 passed / 2 xfailed → 60 passed / 1 xfailed**。
|
|
|
|
|
|
- `docs/dev/personal-pitfalls.md`:追加第 8 条(限制掩码 ≠ 限制统计量)。
|
2026-10-01 23:11:48 +08:00
|
|
|
|
|
2026-10-01 17:43:48 +08:00
|
|
|
|
### Notes
|
2026-10-02 15:41:08 +08:00
|
|
|
|
- `detect_outliers` 原有的三个 bug 加一处设计空白**已全部收口**:`threshold` 范围校验挪进
|
|
|
|
|
|
`clean_missing`、`is_series` / `is_ld_array` 提到类型转换**之前**、统计量与掩码都限制在数值列、
|
|
|
|
|
|
非数值列恒 `False`(决策 32)。最后一条 `xfail` 已按 XPASS 信号摘掉。
|
|
|
|
|
|
**仍缺 S 档函数卡片**(`docs/algorithms/`)与 `examples/` 最小用法 —— 见 `STATUS.md`「下一步」第 1/4 条。
|
2026-10-02 15:04:13 +08:00
|
|
|
|
- `impute_missing` 的 mode 分支会**就地修改**调用方的 DataFrame,其余四个分支都返回新表。
|
2026-10-02 15:41:08 +08:00
|
|
|
|
同样属于"要选语义",留给用户本人写 —— 见 `STATUS.md`「下一步」第 2 条。
|
2026-10-02 15:04:13 +08:00
|
|
|
|
- 已知缺口:
|
2026-10-01 23:11:48 +08:00
|
|
|
|
- 除 `core.Result`、`core.get_rng`、`core.set_seed`、`data.load_table`、`data.save_table` 外,其余函数体**尚未实现**(统一 `raise NotImplementedError` + `TODO(L0/L1/v0.2)` 标记)。
|
2026-10-01 17:43:48 +08:00
|
|
|
|
这是刻意的:先定接口,再按 `docs/03-roadmap.md` 的 L0 → L1 顺序填实现。
|
2026-10-01 23:11:48 +08:00
|
|
|
|
- 已知缺口:`SALib`(Sobol/Morris)、`pymoo`、`pyright` 已装进 conda 环境 `mcm-toolkit`,`.venv` 里没有。
|
2026-10-01 17:43:48 +08:00
|
|
|
|
|
|
|
|
|
|
## [0.0.1] - 2026-10-01
|
|
|
|
|
|
|
|
|
|
|
|
### Added
|
|
|
|
|
|
- 项目初始化,包结构落盘(实现为空)。
|