feat(models): 审查 metrics.py:工程侧收口 + 修 r2/smape 两个真 bug(+18 条测试)
models/metrics.py(用户写、Codex 审):6 个回归指标 + 共享入口 verify_yt_yp 落地, compare_models 仍是 TODO(L1)。 真 bug(决策 59,由用户亲手改定): - r2_score 的 SS_tot 基准用了 np.mean(y_pred),必须是 np.mean(y_true)。 探针实测:修前 0.8803827751196172、修后 0.875 = sklearn.metrics.r2_score 一致; adjusted_r2 复用它,一并修正。完美拟合(r2_score(y, y) == 1)与常量 y 都掩盖了这个错, 所以新测试特意用"非完美拟合"的数据。ss_tol 顺带改名 ss_tot。 - smape 的 np.where 掩码防不住零除(两条分支都会被求值),在 filterwarnings = ["error::RuntimeWarning"] 下任何含 0 的用例直接红 → 改 np.divide(where=), 数值结果不变(决策 60)。 工程侧(决策 47):报错文案统一为"参数名 + 实际值";补 7 处 docstring (Parameters / Returns / Raises,把 NaN 报错、mape 遇 0、r2 常量 y、adjusted_r2 分母保护 写成契约;n_features 注明不含截距);ruff 9 条清零(6 F541 + 3 W293)。 tests/test_models.py:5 条 → 23 条(2 条摘 skip 转正 + 18 条新增)。 三连:pytest 224 passed / 26 skipped(250 收集)、ruff 0、pyright 0。 文档:STATUS 决策 59 / 60 + 第九轮(含 4 条待拍板口径);CHANGELOG 本轮条目; docs/dev/personal-pitfalls.md 追加易错点 31(基准量抄错对象)与 32(np.where 掩码防不住零除)。
This commit is contained in:
1 parent
3bb31f95de
commit
9907289ec8
5 files changed
+463
-26
No files matched your search
@@ -613,6 +613,37 @@
|
||||
`markov_steady_state` 未收敛时是否带 `data`、非方阵的 `TypeError` / `ValueError` 不一致、
|
||||
`mm1_metrics` 的 `data` 该不该是 dict。
|
||||
|
||||
### Added
|
||||
- `models/metrics.py`:6 个回归指标落地(**由用户本人实现**)—— `rmse` / `mae` / `mape` / `smape` /
|
||||
`r2_score` / `adjusted_r2`,共用一个入口守卫 `verify_yt_yp`(`as_array` → 形状 / 空 / NaN 三道校验)。
|
||||
`compare_models` 仍是 `TODO(L1)`。
|
||||
- `tests/test_models.py`:5 条 → **23 条**。`test_metrics_known_values` / `test_r2_is_one_for_perfect_fit`
|
||||
两条摘掉 `skip` 转正,另新增 18 条 —— 形状不一致 / 空 / NaN / `str` 被 `TypeError` 挡、四种入参
|
||||
(`DataFrame` / `Series` / `ndarray` / `list`)结果一致 ×5、`mape` 遇 0、`smape` 全 0 且**不许漏告警**、
|
||||
`adjusted_r2` 的 `bool` / `float` / `0` / 分母保护 / `np.int64` / 惩罚单调性,以及 `r2_score` 的
|
||||
**非完美拟合**解析值与 `sklearn.metrics.r2_score` 对照。
|
||||
|
||||
### Changed
|
||||
- `models/metrics.py`:`r2_score` 的 `SS_tot` 基准由 `np.mean(y_pred)` 改为 `np.mean(y_true)`(**真 bug**,
|
||||
由用户亲手改定,见 STATUS 决策 59 / 个人易错点 31),`ss_tol` 随之改名 `ss_tot`;修前 0.8803827751196172、
|
||||
修后 0.875(与 sklearn 一致),`adjusted_r2` 同步修正。
|
||||
- `models/metrics.py`:`smape` 的零除改用 `np.divide(..., out=..., where=denom != 0.0)` ——
|
||||
`np.where` 的两条分支都会被求值,原写法在 `filterwarnings = ["error::RuntimeWarning"]` 下会让
|
||||
"含 0 的 smape"测试直接失败(决策 60)。数值结果与口径不变。
|
||||
- `models/metrics.py`:补 7 处 docstring(`Parameters` / `Returns` / `Raises`),把"NaN 报错 / `mape` 遇 0 报错 /
|
||||
`r2_score` 常量 y 报错 / `adjusted_r2` 的分母保护"写成契约;`n_features` 的口径写明**不含截距**。
|
||||
- `models/metrics.py`:报错文案统一为"参数名 + 实际值"(形状不一致会带上两个 `shape`);
|
||||
ruff 9 条清零(6 条 `F541` 无占位符 f-string + 3 条 `W293`)+ 补函数间空行。
|
||||
- `STATUS.md`:新增**决策 59 / 60**,「下一步」推进到第九轮(含 4 条待拍板口径);
|
||||
验证计数更新为 **224 passed / 26 skipped(250 收集)**。
|
||||
- `docs/dev/personal-pitfalls.md`:新增易错点 31(公式的"基准量"抄错对象,且完美拟合会掩盖它)、
|
||||
32(`np.where` 掩码防不住零除)。
|
||||
|
||||
### Notes
|
||||
- **4 条口径待用户拍板**(Codex 只报不改):`mape` 遇负 `y_true` 现在返回负数、只拦 `NaN` 不拦 `inf`、
|
||||
`rmse(1.0, 1.0)` 这类标量被当成 1 个样本、`compare_models` 的键名 `"r2"` 与函数名 `r2_score` 不一致。
|
||||
详见 `STATUS.md`「第九轮新增:4 条口径待你拍板」。
|
||||
|
||||
## [0.0.1] - 2026-10-01
|
||||
|
||||
### Added
|
||||
|
||||
Reference in new issue
Block a user