Skip to content

Commit 29a2920

Browse files
authored
Merge pull request #290 from Integration-Automation/feat/data-drift-batch
Add distribution drift detection
2 parents 858d4f7 + fd9a097 commit 29a2920

15 files changed

Lines changed: 413 additions & 1 deletion

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
## Table of Contents
1515

16+
- [What's new (2026-06-21) — Distribution Drift Detection](#whats-new-2026-06-21--distribution-drift-detection)
1617
- [What's new (2026-06-21) — Layered Configuration Resolver](#whats-new-2026-06-21--layered-configuration-resolver)
1718
- [What's new (2026-06-21) — Server-Sent Events (SSE) Client Parser](#whats-new-2026-06-21--server-sent-events-sse-client-parser)
1819
- [What's new (2026-06-21) — Dotenv (.env) Parsing](#whats-new-2026-06-21--dotenv-env-parsing)
@@ -134,6 +135,12 @@
134135

135136
---
136137

138+
## What's new (2026-06-21) — Distribution Drift Detection
139+
140+
Check whether today's data is shaped like the baseline. Full reference: [`docs/source/Eng/doc/new_features/v82_features_doc.rst`](docs/source/Eng/doc/new_features/v82_features_doc.rst).
141+
142+
- **`psi` / `ks_two_sample` / `categorical_drift` / `detect_drift`** (`AC_detect_drift`, `AC_categorical_drift`): `stats` had A/B experiment tests but no Population Stability Index and no KS two-sample test for reference-vs-current distributions. This adds PSI (quantile-binned log-ratio), the KS statistic with a Kolmogorov p-value, and a categorical chi-square + total-variation summary — pairing with `data_profile`. `detect_drift` gives a one-call `{psi, drifted, ks}` verdict. Pure-stdlib, deterministic.
143+
137144
## What's new (2026-06-21) — Layered Configuration Resolver
138145

139146
Compose config with `defaults < file < env < CLI` precedence. Full reference: [`docs/source/Eng/doc/new_features/v81_features_doc.rst`](docs/source/Eng/doc/new_features/v81_features_doc.rst).

README/README_zh-CN.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目录
1414

15+
- [本次更新 (2026-06-21) — 分布漂移检测](#本次更新-2026-06-21--分布漂移检测)
1516
- [本次更新 (2026-06-21) — 分层配置解析器](#本次更新-2026-06-21--分层配置解析器)
1617
- [本次更新 (2026-06-21) — Server-Sent Events (SSE) 客户端解析器](#本次更新-2026-06-21--server-sent-events-sse-客户端解析器)
1718
- [本次更新 (2026-06-21) — Dotenv (.env) 解析](#本次更新-2026-06-21--dotenv-env-解析)
@@ -133,6 +134,12 @@
133134

134135
---
135136

137+
## 本次更新 (2026-06-21) — 分布漂移检测
138+
139+
检查今天的数据形状是否与基准一致。完整参考:[`docs/source/Zh/doc/new_features/v82_features_doc.rst`](../docs/source/Zh/doc/new_features/v82_features_doc.rst)
140+
141+
- **`psi` / `ks_two_sample` / `categorical_drift` / `detect_drift`**(`AC_detect_drift``AC_categorical_drift`):`stats` 有 A/B 实验检定,但没有 Population Stability Index,也没有针对 reference-vs-current 分布的 KS 双样本检定。本功能加入 PSI(分位分箱的 log-ratio)、KS 统计量与 Kolmogorov p 值,以及类别卡方 + total-variation 摘要 —— 与 `data_profile` 搭配。`detect_drift` 给出一次性的 `{psi, drifted, ks}` 判定。纯标准库、确定。
142+
136143
## 本次更新 (2026-06-21) — 分层配置解析器
137144

138145
`defaults < file < env < CLI` 优先级组合配置。完整参考:[`docs/source/Zh/doc/new_features/v81_features_doc.rst`](../docs/source/Zh/doc/new_features/v81_features_doc.rst)

README/README_zh-TW.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目錄
1414

15+
- [本次更新 (2026-06-21) — 分布漂移偵測](#本次更新-2026-06-21--分布漂移偵測)
1516
- [本次更新 (2026-06-21) — 分層設定解析器](#本次更新-2026-06-21--分層設定解析器)
1617
- [本次更新 (2026-06-21) — Server-Sent Events (SSE) 用戶端解析器](#本次更新-2026-06-21--server-sent-events-sse-用戶端解析器)
1718
- [本次更新 (2026-06-21) — Dotenv (.env) 解析](#本次更新-2026-06-21--dotenv-env-解析)
@@ -133,6 +134,12 @@
133134

134135
---
135136

137+
## 本次更新 (2026-06-21) — 分布漂移偵測
138+
139+
檢查今天的資料形狀是否與基準一致。完整參考:[`docs/source/Zh/doc/new_features/v82_features_doc.rst`](../docs/source/Zh/doc/new_features/v82_features_doc.rst)
140+
141+
- **`psi` / `ks_two_sample` / `categorical_drift` / `detect_drift`**(`AC_detect_drift``AC_categorical_drift`):`stats` 有 A/B 實驗檢定,但沒有 Population Stability Index,也沒有針對 reference-vs-current 分布的 KS 雙樣本檢定。本功能加入 PSI(分位分箱的 log-ratio)、KS 統計量與 Kolmogorov p 值,以及類別卡方 + total-variation 摘要 —— 與 `data_profile` 搭配。`detect_drift` 給出一次性的 `{psi, drifted, ks}` 判定。純標準函式庫、具決定性。
142+
136143
## 本次更新 (2026-06-21) — 分層設定解析器
137144

138145
`defaults < file < env < CLI` 優先序組合設定。完整參考:[`docs/source/Zh/doc/new_features/v81_features_doc.rst`](../docs/source/Zh/doc/new_features/v81_features_doc.rst)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Distribution Drift Detection
2+
============================
3+
4+
``stats`` has two-sample tests for A/B *experiment* outcomes (proportions and
5+
means), but no Population Stability Index and no Kolmogorov-Smirnov two-sample
6+
test for the canonical "is today's data shaped like the baseline" check. This
7+
adds PSI, KS, and a categorical-drift summary that pair with ``data_profile``.
8+
9+
Pure standard library (``math`` / ``bisect`` / ``collections`` + reuse of
10+
``stats.percentile``); imports no ``PySide6``. Every function is pure
11+
(sequences in, dict/float out), so it is fully deterministic in CI.
12+
13+
Headless API
14+
------------
15+
16+
.. code-block:: python
17+
18+
from je_auto_control import psi, ks_two_sample, categorical_drift, detect_drift
19+
20+
score = psi(reference, current) # Population Stability Index
21+
ks = ks_two_sample(reference, current) # {statistic, p_value}
22+
report = detect_drift(reference, current) # {psi, drifted, ks}
23+
24+
cat = categorical_drift(ref_labels, cur_labels)
25+
# {chi_square, total_variation, categories}
26+
27+
``psi`` bins ``current`` against ``reference`` quantile edges and sums the
28+
log-ratio contribution per bin (0 for identical distributions, growing as they
29+
diverge). ``ks_two_sample`` returns the maximum empirical-CDF gap and a p-value
30+
from the Kolmogorov distribution. ``categorical_drift`` compares label
31+
frequencies via a chi-square statistic and the total-variation distance.
32+
``detect_drift`` wraps the numeric path into one report with a ``drifted``
33+
verdict at ``threshold`` (default ``0.25``).
34+
35+
Executor commands
36+
-----------------
37+
38+
``AC_detect_drift`` takes ``reference`` / ``current`` numeric lists (and
39+
optional ``threshold`` / ``bins``) and returns ``{psi, drifted, ks}``.
40+
``AC_categorical_drift`` returns the categorical summary. Both are exposed as
41+
MCP tools (``ac_detect_drift`` / ``ac_categorical_drift``) and as Script Builder
42+
commands under **Data**.

docs/source/Eng/eng_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ Comprehensive guides for all AutoControl features.
104104
doc/new_features/v79_features_doc
105105
doc/new_features/v80_features_doc
106106
doc/new_features/v81_features_doc
107+
doc/new_features/v82_features_doc
107108
doc/ocr_backends/ocr_backends_doc
108109
doc/observability/observability_doc
109110
doc/operations_layer/operations_layer_doc
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
分布漂移偵測
2+
==========
3+
4+
``stats`` 具備針對 A/B *實驗*結果(比例與平均)的雙樣本檢定,但沒有 Population Stability Index,也沒有
5+
Kolmogorov-Smirnov 雙樣本檢定來做經典的「今天的資料形狀是否與基準一致」檢查。本功能加入 PSI、KS,以及
6+
與 ``data_profile`` 搭配的類別漂移摘要。
7+
8+
純標準函式庫(``math`` / ``bisect`` / ``collections`` + 重用 ``stats.percentile``);不匯入 ``PySide6``。
9+
每個函式皆為純函式(輸入序列、輸出 dict/float),因此在 CI 中完全具決定性。
10+
11+
無頭 API
12+
--------
13+
14+
.. code-block:: python
15+
16+
from je_auto_control import psi, ks_two_sample, categorical_drift, detect_drift
17+
18+
score = psi(reference, current) # Population Stability Index
19+
ks = ks_two_sample(reference, current) # {statistic, p_value}
20+
report = detect_drift(reference, current) # {psi, drifted, ks}
21+
22+
cat = categorical_drift(ref_labels, cur_labels)
23+
# {chi_square, total_variation, categories}
24+
25+
``psi`` 以 ``reference`` 的分位邊界將 ``current`` 分箱,並加總每箱的 log-ratio 貢獻(分布相同為 0,
26+
分歧越大值越大)。``ks_two_sample`` 回傳最大經驗 CDF 差距與 Kolmogorov 分布的 p 值。``categorical_drift``
27+
以卡方統計量與 total-variation 距離比較類別頻率。``detect_drift`` 把數值路徑包成一份報告,並以 ``threshold``
28+
(預設 ``0.25``)給出 ``drifted`` 判定。
29+
30+
執行器命令
31+
----------
32+
33+
``AC_detect_drift`` 接受 ``reference`` / ``current`` 數值清單(以及選用的 ``threshold`` / ``bins``)
34+
回傳 ``{psi, drifted, ks}``。``AC_categorical_drift`` 回傳類別摘要。兩者皆以 MCP 工具
35+
(``ac_detect_drift`` / ``ac_categorical_drift``)以及 Script Builder 中 **Data** 分類下的命令提供。

docs/source/Zh/zh_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ AutoControl 所有功能的完整使用指南。
104104
doc/new_features/v79_features_doc
105105
doc/new_features/v80_features_doc
106106
doc/new_features/v81_features_doc
107+
doc/new_features/v82_features_doc
107108
doc/ocr_backends/ocr_backends_doc
108109
doc/observability/observability_doc
109110
doc/operations_layer/operations_layer_doc

je_auto_control/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@
159159
)
160160
# Data profiling: per-column stats + schema inference from observed rows
161161
from je_auto_control.utils.data_profile import infer_schema, profile_rows
162+
# Distribution drift: PSI, KS two-sample, categorical drift
163+
from je_auto_control.utils.data_drift import (
164+
categorical_drift, detect_drift, ks_two_sample, psi,
165+
)
162166
# i18n / l10n testing: pseudo-localize, overflow + catalog checks
163167
from je_auto_control.utils.i18n_test import (
164168
check_catalog, check_overflow, pseudo_localize, pseudo_localize_catalog,
@@ -823,6 +827,7 @@ def start_autocontrol_gui(*args, **kwargs):
823827
"merge_results", "shard_flows",
824828
"extract_fields", "mask_rows", "validate_rows",
825829
"infer_schema", "profile_rows",
830+
"categorical_drift", "detect_drift", "ks_two_sample", "psi",
826831
"check_catalog", "check_overflow", "pseudo_localize",
827832
"pseudo_localize_catalog",
828833
"Checkpoint", "CheckpointStore", "run_resumable",

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,29 @@ def _add_resilience_specs(specs: List[CommandSpec]) -> None:
16971697
),
16981698
description="Show the value and winning layer for a dotted config key.",
16991699
))
1700+
specs.append(CommandSpec(
1701+
"AC_detect_drift", "Data", "Data Drift: Detect (PSI + KS)",
1702+
fields=(
1703+
FieldSpec("reference", FieldType.STRING,
1704+
placeholder="[1.0, 2.0, 3.0, ...]"),
1705+
FieldSpec("current", FieldType.STRING,
1706+
placeholder="[1.1, 2.2, 9.9, ...]"),
1707+
FieldSpec("threshold", FieldType.FLOAT, optional=True,
1708+
default=0.25),
1709+
FieldSpec("bins", FieldType.INT, optional=True, default=10),
1710+
),
1711+
description="Numeric drift: Population Stability Index + KS two-sample.",
1712+
))
1713+
specs.append(CommandSpec(
1714+
"AC_categorical_drift", "Data", "Data Drift: Categorical",
1715+
fields=(
1716+
FieldSpec("reference", FieldType.STRING,
1717+
placeholder='["a", "b", "a", ...]'),
1718+
FieldSpec("current", FieldType.STRING,
1719+
placeholder='["a", "c", "c", ...]'),
1720+
),
1721+
description="Categorical drift: chi-square + total-variation distance.",
1722+
))
17001723
specs.append(CommandSpec(
17011724
"AC_rate_limit", "Flow", "Rate Limit (Token Bucket)",
17021725
fields=(
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""Distribution drift detection for AutoControl data checks."""
2+
from je_auto_control.utils.data_drift.data_drift import (
3+
categorical_drift, detect_drift, ks_two_sample, psi,
4+
)
5+
6+
__all__ = ["categorical_drift", "detect_drift", "ks_two_sample", "psi"]

0 commit comments

Comments
 (0)