审查并精简 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 后端)
66 lines
2.0 KiB
Python
66 lines
2.0 KiB
Python
"""data 包测试。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
import pytest
|
|
|
|
pytestmark = pytest.mark.skip(reason="未实现:见 docs/03-roadmap.md L0/L1")
|
|
|
|
|
|
def test_detect_outliers_finds_planted_points():
|
|
"""人工埋 3 个离群点,IQR 法应正好命中 3 个。"""
|
|
from mcm_toolkit.data import detect_outliers
|
|
|
|
x = np.concatenate([np.arange(100.0), [1e6, -1e6, 1e7]])
|
|
mask = np.asarray(detect_outliers(x, method="iqr"))
|
|
assert mask.sum() == 3
|
|
assert mask[-3:].all()
|
|
|
|
|
|
def test_detect_outliers_returns_mask_not_filtered_data():
|
|
"""约定:只标不删——返回与原数据同形的布尔掩码。"""
|
|
from mcm_toolkit.data import detect_outliers
|
|
|
|
x = np.arange(50.0)
|
|
mask = np.asarray(detect_outliers(x, method="zscore"))
|
|
assert mask.shape == x.shape
|
|
assert mask.dtype == bool
|
|
|
|
|
|
def test_normalize_minmax_range(rng):
|
|
from mcm_toolkit.data import normalize
|
|
|
|
x = rng.normal(size=(50, 3))
|
|
out = np.asarray(normalize(x, method="minmax"))
|
|
assert np.allclose(out.min(axis=0), 0.0)
|
|
assert np.allclose(out.max(axis=0), 1.0)
|
|
|
|
|
|
def test_standardize_has_zero_mean_unit_std(rng):
|
|
from mcm_toolkit.data import standardize
|
|
|
|
x = rng.normal(5, 3, size=1000)
|
|
out = np.asarray(standardize(x))
|
|
assert abs(out.mean()) < 1e-9
|
|
assert abs(out.std() - 1.0) < 1e-9
|
|
|
|
|
|
def test_train_test_split_sizes_and_no_overlap(rng):
|
|
from mcm_toolkit.data import train_test_split
|
|
|
|
X = rng.normal(size=(100, 2))
|
|
Xtr, Xte = train_test_split(X, test_size=0.2, random_state=0)
|
|
assert len(Xtr) == 80 and len(Xte) == 20
|
|
assert len({tuple(r) for r in Xtr} & {tuple(r) for r in Xte}) == 0
|
|
|
|
|
|
def test_load_table_detects_gbk(tmp_path):
|
|
"""国内赛题数据常见 GBK,编码探测必须能兜住。"""
|
|
from mcm_toolkit.data import load_table
|
|
|
|
p = tmp_path / "gbk.csv"
|
|
p.write_bytes("城市,人口\n北京,2189\n".encode("gbk"))
|
|
df = load_table(p)
|
|
assert list(df.columns) == ["城市", "人口"]
|