chore: 补 S 档卡片 / examples;clean.py 收尾,xfail 清零
实现收尾(Codex 代写,用户授权): - impute_missing 的 mode 分支改为返回新表(原先就地改调用方的 DataFrame,另外四支都返回新对象) - detect_outliers 补入参类型校验(§4.7:非法类型抛 TypeError,不静默兜底): 接受 DataFrame / Series / list / tuple / ndarray;tuple 同时补进 is_ld_array; dict 不再被接受(以前靠 pd.DataFrame() 碰巧能过,见决策 33) 测试: - 摘掉最后一条 xfail(mode 就地改)并加强断言 - 新增 3 条:非法类型抛 TypeError、元组按一维数组型处理、全 NaN 列与单元素列不抛异常 - 64 passed / 42 skipped / 0 xfailed(xfail 清零,7 条契约全部转正);ruff 0;pyright 0 文档: - 新增 docs/algorithms/detect_outliers.md —— 第一张 S 档函数卡片(roadmap 要求约 15 张) 除模板九节外多记三条判断:为什么不返回 Result、非数值列恒 False 的两条备选路各错在哪、 ddof 口径与 stats.zscore 不一致(前者 1、后者 0,小样本差一成) - 新增 examples/01_clean_and_describe.py —— 六个 data 函数的最小用法,实测跑通(exit 0) - STATUS.md:E 节收尾、验证结果表、下一步重写(transform/standardize 的待定项)、决策 33 - CHANGELOG.md:把 [Unreleased] 里重复 7 次的 Added/Changed 小节合并成 Added/Changed/Notes; 并修掉上轮遗留的缺陷 —— pyright 那条 bullet 的开头被吞掉,半句挂在 ruff 那条后面
This commit is contained in:
1 parent
b6dc4bc5a6
commit
5749e50e83
8 files changed
+344
-51
No files matched your search
@@ -99,11 +99,19 @@
|
||||
- 语义由用户本人定:**非数值列不参与统计,掩码里恒 `False`**(见决策 32)
|
||||
- 三轮修掉的 4 个 bug:`threshold` 范围校验放错函数、IQR 上界符号、
|
||||
`is_series` / `is_ld_array` 判在类型转换之后(永远为 False)、文本列上算分位数直接崩
|
||||
- 最后这轮的关键教训:**限制掩码 ≠ 限制统计量** —— 只把 `mask[numeric_cols] = ...`
|
||||
- 关键教训:**限制掩码 ≠ 限制统计量** —— 只把 `mask[numeric_cols] = ...`
|
||||
收窄是不够的,`quantile()` / `mean()` / `std()` 也要一起收窄(见坑 8 / 个人易错点 8)
|
||||
- 返回形状与输入同形;Series 进 Series 出(列名保留)、一维数组进一维布尔数组出
|
||||
- 测试:`tests/test_data.py` 该函数共 11 条,含「全文本表返回全 False」这条边界
|
||||
- [ ] **待补:** `detect_outliers` 的 S 档函数卡片(`docs/algorithms/`)与 `examples/` 最小用法
|
||||
- **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` 六个函数的最小用法,实测可直接跑通
|
||||
- [ ] 剩余 7 项:`normalize` `standardize` `describe` `correlation_matrix`
|
||||
`bootstrap_ci` `monte_carlo` `save_figure`
|
||||
|
||||
@@ -111,7 +119,7 @@
|
||||
|
||||
| 检查 | venv | conda `mcm-toolkit` |
|
||||
|---|---|---|
|
||||
| `pytest` | 见下(单列) | **60 passed, 42 skipped, 1 xfailed** |
|
||||
| `pytest` | 见下(单列) | **64 passed, 42 skipped(0 xfail)** |
|
||||
| `import mcm_toolkit` | 0.0.1 / 16 项 | 0.0.1 / 16 项 |
|
||||
| `ruff check` | All checks passed | **All checks passed**(0 error) |
|
||||
| `scripts/doctor.ps1` | 跑通 | — |
|
||||
@@ -121,10 +129,10 @@
|
||||
(修配置之前是 17 errors,全是"无法解析导入 numpy / pandas",见决策 29 与
|
||||
`docs/04-environment.md` 坑 7)
|
||||
- base 亦已复核:numpy 2.4.6 / scipy 1.18.1 / pandas 3.0.6(与两套环境一致)
|
||||
- 60 条通过 = 20 条公开 API 契约测试 + 11 条 `core` 行为测试 + 29 条 `data` 行为测试
|
||||
- 只剩 1 条 `xfail`:`impute_missing` 的 mode 分支就地改调用方的表。
|
||||
这条**不是漏改,是要选语义**;修好后会自动变 XPASS,那时把 `xfail` 摘掉即可(决策 30)
|
||||
- 累计 6 条 `xfail` 正是靠这个 XPASS 信号确认修好并摘掉的(本轮摘掉 1 条 + 撤销 1 条过严的判定)
|
||||
- 64 条通过 = 20 条公开 API 契约测试 + 11 条 `core` 行为测试 + 33 条 `data` 行为测试
|
||||
- **`xfail` 清零**:累计 7 条"契约已写进 docstring、实现没跟上"的用例全部转正,
|
||||
决策 30 那套信号(XPASS → 摘 mark)跑完了一个完整闭环
|
||||
- `examples/01_clean_and_describe.py` 实测跑通(exit 0);`00_quickstart.py` 仍等 `stats` / `viz`
|
||||
- 42 条 skip 是等实现的算法(`normalize` / `standardize` / `train_test_split` 等)
|
||||
- 三个 `.ps1` 通过 PowerShell AST 语法解析
|
||||
|
||||
@@ -180,23 +188,24 @@
|
||||
| 30 | 已知待修的契约用 `@pytest.mark.xfail(strict=False)`,不用 skip | skip 会让"契约还没写"和"写了但实现有问题"混在一起,5 条 skip 曾把 `clean.py` 的 bug 全藏住。xfail 照样进报告,修好后自动变 XPASS,是"修好了"的信号,而且 XPASS 不失败,不会卡住提交 |
|
||||
| 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 认的转发手段 |
|
||||
| 28 | 不启用 ruff 的 preview 规则集 | `E302`(函数间要 2 个空行)在 ruff 0.16 里是 preview 规则,`select = ["E"]` 默认**不包含**它——所以少一个空行 ruff 照样报 "All checks passed"。行数空行得自己盯,别指望 lint |
|
||||
| 33 | `detect_outliers` 只接受 `DataFrame` / `Series` / `list` / `tuple` / `ndarray`,`dict` 一律 `TypeError` | §4.7 要求非法类型抛 `TypeError` 而非静默兜底。`dict` 以前能"碰巧"被 `pd.DataFrame()` 转成表,但那不是文档承诺的形状,静默接受会让调用方以为传什么都行;`tuple` 则补进文档与 `is_ld_array`,与 `list` 同等对待 |
|
||||
| 32 | `detect_outliers` 对非数值列恒返回 `False`(既不跳过也不报错) | **用户本人在两条路里选的**。跳过会让 docstring 里"与原数据同形"变成谎话(形状对不上,没法按位置对回原表);报错则让一张带 `city` 列的真题表直接不可用。`False` 的读法是"这一列没有离群点",对文本列是最不坏的解释,也让整表能一次跑完 |
|
||||
| 31 | Codex 可**直接改** `src/` 的范围:纯 bug(不改接口与语义)、格式、死代码 | 决策 25 说实现归用户,但"能跑"是底线:`winsorize(pd.Series)` 因 `select_dtypes` 在 `Series` 上不存在而直接崩、测试变红,这种必须当场修。凡是要**选一个语义**的(文本列返回什么、mode 要不要就地改)一律留给用户本人,Codex 只把选项和影响列清楚 |
|
||||
| 27 | base 里的 zstandard 残骸目录**改名禁用**,不删除、不重装 | 删掉不可逆;`pip install zstandard` 会给 base 塞一个 conda 记录里根本没有的包,下次 `conda update --all` 又要重新判断。改名后 `import` 变回正常 `ModuleNotFoundError`,pandas 自动跳过 |
|
||||
|
||||
## 下一步
|
||||
|
||||
1. **写 `detect_outliers` 的 S 档函数卡片**(`docs/algorithms/` 下,照 `docs/dev/function-card-template.md`)。
|
||||
roadmap 要求 S 档先写卡片再写码 —— `detect_outliers` 是反着来的,于是 bug 全翻在
|
||||
"该想清楚"的地方:上界符号、布尔优先级、维度。卡片至少要把这几条钉住:
|
||||
两种方法的数学定义与失效场景、非数值列为什么恒 `False`、`k` / `threshold` 默认值从哪来、
|
||||
以及"只标不删"这个设计选择。
|
||||
2. 顺手把 `impute_missing` 的 mode 分支改成**返回新表**
|
||||
(现在就地改调用方的 DataFrame,和另外四个分支不一致;`data = data.copy()` 一行的事)。
|
||||
注意它和 `detect_outliers` 恰好相反:那个函数全程只读,加 `copy()` 是纯浪费 ——
|
||||
同一个 `copy()`,一处必须要、一处必须不要。
|
||||
3. **下一个文件**:`data/transform.py` 的 `normalize` / `standardize`
|
||||
(`tests/test_data.py` 里两条 skip 已就位;写之前先定 `method` 的取值集合与 `axis` 语义)。
|
||||
4. 补齐 `examples/`:`Result`、`load_table`、`clean_missing`、`detect_outliers` 都还差一行最小用法
|
||||
(roadmap §3.2 第 4 步)。
|
||||
1. **`data/transform.py` 的 `normalize` / `standardize`**(用户本人开始写)
|
||||
- 签名已经定好(`normalize(x, method="minmax", feature_range=(0.0, 1.0))`、
|
||||
`standardize(x, ddof=0)`),动手前只需要定两件事:`normalize` 的 `method` 取值集合
|
||||
(默认 `"minmax"`;要不要再放 `"maxabs"` / `"robust"`?YAGNI 的话就只留 `"minmax"`)、
|
||||
以及 `axis` 语义 —— 赛题里几乎总是**按列**,那就明确默认按列,别留模糊。
|
||||
- 注意 `standardize` 的 `ddof=0` 与 `detect_outliers` 里 pandas 默认的 `ddof=1` 不一致,
|
||||
两处都要在 docstring 里写明,否则以后对不上账(见 `docs/algorithms/detect_outliers.md` §5)。
|
||||
- `tests/test_data.py` 里两条 skip 已就位(`test_normalize_minmax_range`、
|
||||
`test_standardize_has_zero_mean_unit_std`)。
|
||||
2. `stats.describe` + `data/transform.py` 的 `log_transform` / `one_hot_encode`
|
||||
(`examples/01_clean_and_describe.py` 末尾的 `TODO(L0)` 就等 `describe`)。
|
||||
3. 补齐 `examples/00_quickstart.py`:它要等 `stats` / `viz`;`Result` 的用法届时一并写进去。
|
||||
4. 每写完一个函数:docstring(§4.7 全套)+ 一条 pytest + `examples/` 一行用法 + 更新 `STATUS.md`。
|
||||
5. L0 跑通后,找一道真题(建议 2025 C)走完整流程,反向沉淀函数。
|
||||
Reference in new issue
Block a user