审查并精简 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 后端)
59 lines
1.7 KiB
Python
59 lines
1.7 KiB
Python
"""models 包测试。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
import pytest
|
|
|
|
pytestmark = pytest.mark.skip(reason="未实现:见 docs/03-roadmap.md L1")
|
|
|
|
|
|
def test_fit_linear_recovers_known_coefficients(linear_data):
|
|
"""真值 y = 2x + 1,拟合系数应在 1% 内。"""
|
|
from mcm_toolkit.models import fit_linear
|
|
|
|
x, y = linear_data
|
|
r = fit_linear(x.reshape(-1, 1), y)
|
|
assert np.isclose(r.params["coef"][0], 2.0, rtol=0.01)
|
|
assert np.isclose(r.params["intercept"], 1.0, atol=0.05)
|
|
|
|
|
|
def test_fit_polynomial_matches_numpy(linear_data):
|
|
from mcm_toolkit.models import fit_polynomial
|
|
|
|
x, y = linear_data
|
|
r = fit_polynomial(x.reshape(-1, 1), y, degree=2)
|
|
assert np.allclose(r.params["coef"], np.polyfit(x, y, 2), rtol=1e-6)
|
|
|
|
|
|
def test_metrics_known_values():
|
|
from mcm_toolkit.models import mae, r2_score, rmse
|
|
|
|
y_true = np.array([1.0, 2.0, 3.0])
|
|
y_pred = np.array([1.0, 2.0, 5.0])
|
|
assert np.isclose(rmse(y_true, y_pred), np.sqrt(4 / 3))
|
|
assert np.isclose(mae(y_true, y_pred), 2 / 3)
|
|
assert r2_score(y_true, y_pred) < 1.0
|
|
|
|
|
|
def test_r2_is_one_for_perfect_fit():
|
|
from mcm_toolkit.models import r2_score
|
|
|
|
y = np.array([1.0, 2.0, 3.0, 4.0])
|
|
assert np.isclose(r2_score(y, y), 1.0)
|
|
|
|
|
|
def test_compare_models_returns_table_sorted_by_first_metric(linear_data):
|
|
from mcm_toolkit.models import compare_models, fit_linear, fit_polynomial
|
|
|
|
x, y = linear_data
|
|
X = x.reshape(-1, 1)
|
|
tbl = compare_models(
|
|
{"linear": fit_linear(X, y), "poly2": fit_polynomial(X, y, degree=2)},
|
|
X,
|
|
y,
|
|
cv=0,
|
|
)
|
|
assert set(tbl.index) >= {"linear", "poly2"}
|
|
assert "rmse" in tbl.columns
|