guzhujushi
|
5749e50e83
|
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 那条后面
|
2026-10-02 15:48:12 +08:00 |
|
guzhujushi
|
b6dc4bc5a6
|
feat(data): detect_outliers 收尾(文本列恒 False)+ 补测试与文档
实现(用户本人写 + Codex 轻度收尾):
- 统计量(quantile / mean / std)与掩码写入都收窄到数值列,含文本列的赛题表不再崩
- 非数值列在掩码里恒 False(用户定的语义),docstring Notes 补上这条
- 删掉死代码 data=data.copy():下面的 to_frame()/pd.DataFrame() 本就返回新对象,
函数全程只读 data,白复制一份;且它排在类型分派之前,会把错误入参的报错
从 ValueError 变成 AttributeError
- 删掉那行死代码后 pyright 反而暴露 1 个真错:df[Index] 被类型存根当成 Series,
.std() 于是被判成标量、std.replace(...) 非法。在取列子表处 cast 成 DataFrame
按运行时真值收窄(详见 docs/04-environment.md 坑 8)
测试:
- 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;ruff 0;pyright 0
- 仅剩 1 条 xfail:impute_missing 的 mode 分支就地改调用方的表(要选语义,留给用户)
文档:
- STATUS.md:L0 5/12、验证结果表、下一步重写、新增决策 32(非数值列恒 False)
- docs/04-environment.md:新增坑 8(pandas 存根让 df[Index] 退化成 Series,及三种无效修法)
- docs/dev/personal-pitfalls.md:只追加第 8 条(限制掩码 ≠ 限制统计量)
- CHANGELOG.md:本轮变更
|
2026-10-02 15:41:08 +08:00 |
|
guzhujushi
|
319b16b17c
|
fix(data): clean.py 轻度修复 + 摘掉 5 条已修好的 xfail
Codex 直接改的(格式 / 死代码 / 纯 bug,不动接口与语义):
- winsorize(Series) 直接崩:select_dtypes 在 Series 上不存在,Series 分支提到最前并加数值 dtype 守卫
- winsorize 的分位数改为只在数值列上算,含文本列的赛题表不再崩(与已有 numeric_cols 判断对齐)
- 删掉 detect_outliers 里已成空操作的 df = pd.DataFrame(data),去掉 df 别名
- clean_missing 的嵌套 if 合并(ruff SIM102),清掉 W293 行尾空白与函数内连续空行
测试:
- 5 条 xfail 经 XPASS 信号确认已修好,摘掉 mark 转正式用例
(detect_outliers 4 条 + winsorize 混合类型 1 条)
- 53 passed / 7 xfailed -> 58 passed / 2 xfailed
- 剩 2 条 xfail 保留,且不是漏改而是设计没定:
detect_outliers 遇文本列返回什么、impute_missing 的 mode 分支要不要就地改调用方的表
- ruff: 1 error -> All checks passed;pyright: 0 errors 不变
文档:
- STATUS.md:L0 进度 4/12、验证结果表、下一步重写、新增决策 31
(Codex 可直接改 src 的范围:纯 bug / 格式 / 死代码;要选语义的留给用户)
- CHANGELOG.md:本轮变更,并修掉 [Unreleased] 里被重复追加撑坏的一句
- docs/dev/personal-pitfalls.md:只追加第 7 条(守卫子句要排在类型分派之后)
|
2026-10-02 15:18:15 +08:00 |
|
guzhujushi
|
c2595b6d07
|
feat(data): clean.py 四个函数落地;补测试、docstring 与 ruff 清理
src 由用户本人写(决策 25),Codex 只做审查、补测试与文档。
实现(用户):
- clean_missing:按行/列删缺失过多的行,threshold 用 math.ceil 算 min_non_na
(3 列、阈值 0.5 时必须是 2;写 int() 截断会漏删)
- impute_missing / detect_outliers / winsorize(原属 L1,顺手落地)
Codex 改的轻度项:
- 按 §4.7 给四个函数补 Parameters / Returns / Raises(与 io.py 同一套 numpydoc 格式)
- ruff 6 -> 1:导入分组(I001)、elif 链改 if 加末尾无条件 return(RET505/RET503)、
去掉多余 f 前缀(F541)、删掉只会被覆盖的 mask 初始化、去掉行尾空白(W293)
- tests/test_data.py:新增 13 条 clean 行为测试 + 7 条 xfail
结果:
- pytest 53 passed / 42 skipped / 7 xfailed(此前 40 / 44 / 0)
- pyright 0 errors, 0 warnings
- ruff 剩 1 条 SIM102,就在 detect_outliers 里那段待修的代码中,删掉即全绿
已知未修(详见 STATUS.md「下一步」):
- detect_outliers 三个 bug:threshold 范围校验放错函数(iqr 分支 UnboundLocalError、
zscore 默认 3.0 被 [0,1] 拒掉)、quantile 在含文本列的表上崩、
is_series / is_ld_array 在 data 已转 DataFrame 之后才判断,因此永远为 False
- winsorize 同样在含文本列的表上崩
- impute_missing 的 mode 分支就地修改调用方的表
|
2026-10-02 15:04:13 +08:00 |
|
guzhujushi
|
97a2f95066
|
fix(env): 钉死 pyright 的分析目标,修掉"无法解析导入 numpy/pandas"
现象:编辑器 / pyright 满屏 reportMissingImports,但 .venv 与 conda 环境里
import numpy, pandas 都正常,pytest 也全过。
根因两层:
1. pyright 没配 venvPath / pythonPath 时会去 PATH 上找 python。本机 PATH 上
唯一的 python 是 agent-tools 的 shim(Codex 运行时,Python 3.14),没有科学栈。
pyright --verbose 显示它选了 3.14.6,Search paths 里一个 Anaconda 路径都没有。
注意持久化的 User/Machine PATH 并没有这一项,是 Codex 进程临时注入的——所以
"我的终端没问题"和"工具有问题"可以同时成立。
2. .venv 是 --system-site-packages 建的,三方包在 D:\anaconda\Lib\site-packages,
而 pyright / Pylance 不认 pyvenv.cfg 的 include-system-site-packages,
只去 .venv\Lib\site-packages 找(那里只有 pip)。
pyright 不读 pyvenv.cfg,但**认 .pth**。
改动:
- pyproject.toml [tool.pyright]:venvPath = "." / venv = ".venv" /
pythonVersion = "3.13",并注释了为什么必须写
- scripts/setup-venv.ps1:新增第 [2/4] 步,自动往 .venv 写
_mcm_base_site_packages.pth 指向该机 base 的 site-packages,换机重建即可
- tests/test_data.py:3 处 isna().all() 断言外面套 bool()(它的类型是
Series | bool,直接当条件 pyright 报"条件操作数无效");
2 处故意传错类型的用例加 type: ignore[arg-type]
结果:pyright 17 errors -> 0 errors / 0 warnings;pytest 两套环境均
40 passed, 44 skipped;ruff All checks passed;setup-venv.ps1 通过 AST 解析
(纯 ASCII + LF)。
文档:docs/04-environment.md 新增坑 7(含 pyright --verbose 诊断口诀与
VS Code / PyCharm 的操作步骤)、STATUS 决策 29、CHANGELOG。
|
2026-10-02 13:36:16 +08:00 |
|
guzhujushi
|
6758e81c9d
|
fix(data): 校验早于副作用,补空行;经验写入 pitfalls
save_table 的两处收尾(用户授权代改):
- 后缀校验原先藏在 if/else 分支的 else 里,排在 path.parent.mkdir(...) 之后,
传 sub/x.txt 会先把 sub\ 建出来再抛 ValueError。改成守卫子句,集中在 mkdir 之前,
校验段结束后才产生副作用;此时 else 分支自然消失,用回 if/else 两路分派
- __all__ 与下一个 def 之间补回第二个空行(PEP 8 / E302)
测试:
- 新增 test_save_table_validates_before_touching_disk,
断言参数非法时 tmp_path 下一个条目都不留(ValueError 与 TypeError 两条路径)
- 40 passed / 44 skipped,两套环境一致;ruff All checks passed
文档:
- docs/dev/personal-pitfalls.md 追加条目 5(参数校验排在副作用之后)
与条目 6(把 lint 的"没报错"当成"没问题"),索引表同步加行
- STATUS:io.py 收尾,L0 第 3 项完成;测试计数 40
- CHANGELOG:Fixed 段补两条
|
2026-10-01 23:26:47 +08:00 |
|
guzhujushi
|
19f4a15107
|
docs(data): 补齐 io 两个函数的 Parameters 与 Raises
按 docs/02-architecture.md §4.7,每个公开函数都要写全 Parameters 与 Raises,
格式对齐参考实现 core/random.py 的 get_rng。
- docstring 由 Codex 代写(本轮用户明确授权);函数体逻辑由用户本人改
- load_table:返回注解 Any -> pd.DataFrame,与 docstring 的承诺对齐;
写明 FileNotFoundError / ValueError / ImportError 各自在什么情况下抛
- save_table:写明 TypeError / ValueError / ImportError;
并把 isinstance(df, pd.DataFrame) 校验挪到 mkdir 之前
- 两套环境 pytest 均 39 passed / 44 skipped,ruff All checks passed
|
2026-10-01 23:22:40 +08:00 |
|
guzhujushi
|
49fd84a2df
|
docs: L0 进度 3/12,记录 zstandard 残骸坑与决策 26/27
- STATUS.md:本次任务拆成「第一阶段已完成 / 第二阶段进行中」;
L0 3/12;测试计数改为 39 passed / 44 skipped;
下一步里写明 io.py 待修的两处(mkdir 早于校验、缺 Raises)
- docs/04-environment.md 坑 6:conda 升级留下的 *.conda_trash 残骸目录会被
Python 当成 namespace package 导入成功(__file__ 为 None),
pandas 3.0 因此抛 ImportError: Can't determine version for zstandard
直接打断 pd.read_csv;含排查方法与「改名禁用」的修法
- docs/dev/personal-pitfalls.md:条目 3(注解与 docstring 打架)复发 +1
- 决策 26:未实现的算法逐条 skip,禁用模块级 pytestmark
- 决策 27:zstandard 残骸改名禁用,不删不重装
- CHANGELOG:补 load_table/save_table 与 Fixed 段
|
2026-10-01 23:11:48 +08:00 |
|
guzhujushi
|
98278edd77
|
docs: 新增「类型约定」章节(架构 §4.7)
把"数据类型必须明确"从口头要求变成仓库规则,每个函数都适用。
- 判断顺序表:整数用 (int, np.integer)、浮点用 (float, np.floating)、
bool 要放在 int 判断之前、数组先 np.asarray 归一化
- 硬规则:非法类型必须 raise TypeError,不许静默兜底
(静默的后果是"种子被忽略、结果不可复现且无提示",最难查)
- 要求每个公开函数写全 Parameters(含 None 走哪条分支)与 Raises
- docs/03-roadmap.md §3.2 开发纪律加一行指针
|
2026-10-01 20:04:32 +08:00 |
|
guzhujushi
|
c93810ffb1
|
fix(core): 补齐 get_rng 类型校验,set_seed 覆盖 numpy 旧全局
get_rng 的"共享单例生成器"设计由用户本人提出,本提交只在其上修 bug。
- random_state 判断从 isinstance(x, int) 放宽到 (int, np.integer):
np.int64 不是 int 的子类,之前会静默退回全局流、种子被无声忽略
- 非预期类型改成抛 TypeError(含 bool / float / str / list),不再静默降级
- get_rng 签名补上 np.integer 与 Generator,与 docstring 的承诺一致
- set_seed 同时调用 np.random.seed:sklearn / statsmodels 走的是 numpy
旧全局状态,不覆盖它们"提交能重跑"就有洞(带 noqa: NPY002 与理由)
- 测试:TestRandom 由 4 条增到 7 条(np.integer、非法类型、共享生成器推进)
- 新增 docs/dev/personal-pitfalls.md:个人易错点清单,只追加、不通读,
首批记录本轮 4 个点;docs/README.md 补上 05 与该文件的索引
- STATUS.md:L0 进度说明更新,决策 24 改写(共享单例)、新增决策 25
(src/ 实现默认由用户本人写)
|
2026-10-01 19:38:59 +08:00 |
|
guzhujushi
|
658b266614
|
feat(core): 实现 get_rng 与 set_seed
L0 第 2 项落地。
- get_rng(int) 固定种子可复现;get_rng(Generator) 原样透传;
get_rng() 跟随 set_seed 设过的全局种子,没设过则交给系统熵源
- set_seed(seed) 除记录 _GLOBAL_SEED 外,还调用 np.random.seed,
让 sklearn / statsmodels 这些走 numpy 旧全局状态的库也能复现;
这是全项目唯一碰旧接口的位置,标注了 noqa: NPY002 与理由
- 已知取舍写进 docstring:同一全局种子下多次 get_rng() 是同一条流
- tests/test_core.py:TestRandom 去掉 skip;把原来那条自证式的
test_set_seed_makes_global_reproducible 换成两条真断言
(不传 random_state 也要可复现、旧全局状态被覆盖)
- STATUS.md:L0 进度 2/12,新增决策 23(允许 set_seed 碰旧接口)
与 24(不做 SeedSequence.spawn 拆分);CHANGELOG.md 同步
|
2026-10-01 19:19:15 +08:00 |
|
guzhujushi
|
cb96c847dd
|
feat(core): 实现 Result 的 __repr__ 与 summary
L0 第 1 项落地。
- __repr__:单行紧凑;data 只给类型与规模(ndarray(100000)),
绝不整数组打印;__repr__ 永不抛异常
- summary():可直接贴进论文的 Markdown 表格,
行序 success → params.* → metrics.* → extras.*(按插入顺序,不排序),
float 走 .6g,竖线转义,message 以引用行附在表后
- 新增 5 个模块级私有辅助:_fmt_scalar / _fmt_cell / _fmt_mapping /
_describe_data / _truncate
- tests/test_core.py:去掉 test_result_repr_is_readable 的 skip,
并补 3 条行为测试(默认值与失败路径与十万级数组、Markdown 结构、幂等)
- STATUS.md:L0 进度 1/12;新增决策 21(repr 不打印 data 内容)、
22(summary 行序不排序);CHANGELOG.md 同步
|
2026-10-01 18:48:43 +08:00 |
|
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 |
|