## 新增 - `core.validate.as_array(x, *, numeric_only=True, dtype=float, ndim=None) -> (arr, kind)`: 一次做完"类型白名单 + 转 ndarray + 报告原来是什么容器"。`kind` 是 `"frame"` / `"series"` / `"array"`。 - **还原不代做**(用户拍的板):`describe` / `correlation_*` / `confidence_interval` / `t_test` 的 输出天生与输入不同形,统一还原只会重演易错点 14;所以只报告 `kind`,调用方自己手写三行。 - `core/__init__.py` 导出 `as_array`;`check_array`(L1 未实现)的 docstring 注明实现时复用它。 - 入口三条硬规矩:**默认绝不摊平**(要摊平显式 `ndim=1`);**不删缺失值**; `numeric_only` 按"输出是否与输入同形"选,不按喜好选。 ## 去重 - `normalize` / `standardize` / `log_transform` / `zscore` / `confidence_interval` / `t_test` 六处手抄的 `isinstance(x, pd.DataFrame)` / `select_dtypes` / `np.asarray` 全部删掉,各剩 1 行入口。 - `data/transform.py` 的 `_NUMERIC_TYPES` 白名单连同 3 份副本一起删除 —— 这类判断原来散在 **5 个文件 31 处**。 - `transform` 的三个函数走 `numeric_only=False`:它们的输出必须与输入同形,跳过非数值列会少列。 ## 修掉 - `zscore` / `normalize` / `standardize` / `log_transform` 的 Series 分支**补回 `name`** —— 此前 `pd.Series(result, index=...)` 会把 `name` 丢掉,管道里 `concat` 会变成无名列。 - "容器对、内容转不成 float"的错误类型,由 numpy 的 `ValueError` 统一成 `TypeError`(决策 45,**待确认**)。 ## 测试与文档 - `tests/test_core.py` 新增 `TestAsArray` 8 条:五种容器的 kind、默认只取数值列、 `numeric_only=False` 遇文本报错、默认不摊平、`ndim=2` 只校验不重塑、白名单外一律 TypeError、 **保留 NaN**、`dtype=None` 保持原 dtype;`tests/test_stats.py` 新增 1 条(Series 保住 index/name)。 - 全量 **171 条:134 passed / 37 skipped / 0 xfail**;ruff 0,pyright 0;`examples/01` 跑通(exit 0)。 - `docs/02-architecture.md` 新增 §4.8「入口只有一个:`core.validate.as_array`」,目录树补 `as_array`; `docs/03-roadmap.md` 的 L1 表下补说明;`docs/dev/personal-pitfalls.md` 新增第 16 条并把索引补到 16。 - `STATUS.md`:决策 44 / 45,E 节记 as_array,「下一步」第 7 条列 3 个待拍板口径。 ## 待用户拍板(Codex 一律未代选) - `int` / `float` 标量是否继续留在白名单(现在会产出 0 维数组,`axis=0` 的算法照样炸)。 - "内容转不成 float" 该用 `TypeError`(现状)还是 `ValueError`。 - 要不要让 `as_array` 顺带返回选中的列(改三元组),省掉 `frame` 分支重写 `select_dtypes`。
5.5 KiB
路线图与开发纪律
依据:
01-suggestion-review.md§6–§8。 进度看根目录STATUS.md,本文件只定义"做什么、做到什么程度、什么不做"。
一、功能清单分级
L0 —— 第一周必做(12 个)
没有这 12 个,工具箱根本跑不起来;有了这 12 个,已经能应付大部分题目。
| 函数 | 所在模块 | 档位 |
|---|---|---|
Result |
core/result.py |
A |
get_rng / set_seed |
core/random.py |
A |
load_table |
data/io.py |
A |
clean_missing |
data/clean.py |
A |
detect_outliers |
data/clean.py |
S |
normalize |
data/transform.py |
A |
standardize |
data/transform.py |
A |
describe |
stats/descriptive.py |
A |
correlation_matrix |
stats/inference.py |
A |
bootstrap_ci |
stats/bootstrap.py |
S |
monte_carlo |
solve/simulate.py |
S |
save_figure |
viz/export.py |
A |
correlation_matrix有两个伴随函数(决策 41):correlation_pvalues给 p 值矩阵、correlation_table给"系数 + 星标"的论文表格。三者共用同一套入参守卫与成对删缺失口径。
L1 —— v0.1(共约 40 个)
在 L0 基础上补齐:
| 模块 | 函数 |
|---|---|
core |
check_array check_same_length check_probability check_square_matrix |
data |
impute_missing winsorize log_transform one_hot_encode train_test_split kfold_split bootstrap_sample |
core.validate.as_array(统一入口,决策 44)已提前落地。它不是"多一个公开 API", |stats|zscorecoefficient_of_variationconfidence_intervalt_testanovachi_square_testfit_distributiongoodness_of_fitbootstrap_statistic| |models|rmsemaemapesmaper2_scoreadjusted_r2compare_modelsfit_linearfit_polynomialfit_nonlinearpredictexponential_smoothingfit_arimaforecastfit_forestfit_logistickmeanspcacross_validate| |solve|minimizelinear_programinteger_programdynamic_programmingknapsack_dpsimulated_annealingpareto_frontmonte_carlo_probabilitymonte_carlo_integralrandom_walkmarkov_simulatemarkov_steady_statemm1_metricslocal_sensitivityone_at_a_timeparameter_sweeprobustness_testsobol_analyzemorris_analyze| |decision|equal_weightsentropy_weightscritic_weightsahp_weightsahp_consistency_ratiotopsisgrey_relational_analysisgm11_fit_predict| |viz|mcm_styleplotplot_correlation_matrixplot_residualsplot_convergencesave_table|
L2 —— v0.2
solve/graph.py:build_graphshortest_pathmin_spanning_treebetweenness_centralitypagerankmax_flowcommunity_detectionsolve/dynamics.py:solve_odesolve_systemfind_equilibriumlocal_stability
触发条件:在真题里真的用到了,或者要为 MCM A / ICM D 备赛时再写。
二、永久不做(防膨胀清单)
原文用"建议不要",这里写成硬规则。往这个清单里加东西,必须先改这份文档。
- 不重写 SciPy 的优化器、
scipy.stats的分布、scipy.integrate的积分器 - 不重写 sklearn 的 estimator(
fit/predict之外一律不做) - 不重写 statsmodels 的时间序列框架
- 不重写 NetworkX 的图算法
- 不重写 SALib 的 Sobol / Morris / FAST
- 不实现 NSGA-II / SPEA2 等完整多目标进化算法(用 pymoo)
- 不实现符号计算引擎(用 SymPy)
- 不实现完整离散事件仿真引擎(
simulate_queue那种) - 不做深度学习 / PyTorch 相关任何东西
- 不做 GUI、不做 Web 界面、不做 CLI 之外的产品化
- 不做自动微分、不做 GPU 后端
- 不为"完整性"补函数——没在真题里用过三次的函数不写
三、开发纪律
3.1 文档两档制
S 档(招牌算法,自实现):完整函数卡片,模板见 dev/function-card-template.md。
覆盖:detect_outliers bootstrap_ci monte_carlo monte_carlo_probability
monte_carlo_integral dynamic_programming knapsack_dp simulated_annealing
local_sensitivity sobol_analyze entropy_weights topsis ahp_weights
gm11_fit_predict。约 15 个。
A 档(薄封装):docstring 里一句话数学含义 + 一句话什么时候用 + 一条 pytest。
判断标准:我会不会去改它的内部实现? 会 → S 档。
3.2 每写一个函数
- 先想"这道题里它替代了哪段手写代码"——想不出来就先不写。
- 先在
tests/里写一条会失败的断言(测已知解析解,不测实现细节)。- 参数类型注解按
02-architecture.md§4.7 写全;非法类型抛TypeError,不静默兜底。
- 参数类型注解按
- 实现到测试通过。
- 在
examples/里加一行最小用法。 - 更新
STATUS.md。
3.3 提交前
.venv\Scripts\python.exe -m pytest -q
.venv\Scripts\python.exe -m ruff check src tests
四、时间盒
| 周 | 目标 | 完成标志 |
|---|---|---|
| 1 | core + data + stats;S 档先写 bootstrap_ci monte_carlo detect_outliers |
L0 全部通过测试 |
| 2–3 | models + solve/optimize + solve/simulate |
compare_models 出对比表 |
| 4 | solve/sensitivity + decision + viz |
一条端到端 example |
| 5–6 | 用一道真题走完整流程,反向补函数 | problems/<年份>_<题号>/ 完成 |
| 之后 | 每做一题沉淀 1~3 个函数 + 对应 test | 仓库自然长大 |
核心原则:先跑通一条完整链路,再补宽度。