Thenewchicken55/statistical-analysis
GitHub: Thenewchicken55/statistical-analysis
一款工业机组性能直方图批量异常检测工具,通过同业基准对比、统计漂移检测和物理范围硬性规则多层分析自动标记设备性能异常并输出健康评分。
Stars: 0 | Forks: 0
# Mill 性能直方图异常检测器
一款批量统计分析工具,用于将磨机/发电机性能直方图与**同业基准集合**及指定的参考模型进行比对,从而标记出异常情况 —— 全自动、离线运行,无需手动调整阈值。
## 功能简介
针对每一个性能信号(如 AMPS、DIFF PRESS、INLET TEMP 等),该工具会根据该标签下的所有传感器模型构建一个**同业基准集合** (peer ensemble),然后针对每个模型进行评估:
它跨越三个层级(统计层、同业包络层、硬性规则层)检查 **18 个检测器类别**,生成机器可读的 JSONL 文件、多标签页 Excel 报告、PNG 仪表板,并且 —— 当存在 `Anomaly Table` 工作表时 —— 生成验证报告(精确率 / 召回率 / F1 分数)。
## 前置条件
- **Python 3.10+**
- 一次性安装依赖项:
```
pip install -r requirements.txt
```
## 快速开始
### 第 1 步 — 运行分析
```
python main.py
```
```
results.jsonl # machine-readable, one line per (tag, model) pair
results_summary.md # human-readable markdown summary
results_report.xlsx # multi-tab Excel report (health scores, validation, flags)
results_dashboard.png # top-N flagged models vs peer envelope
```
### 第 2 步 — 查看结果
控制台输出会显示基于真实标准 `Anomaly Table` 工作表的验证指标:
```
Done: 619 pair(s) analysed — 241 flagged, 378 clean.
Results : results.jsonl
Summary : results_summary.md
Excel : results_report.xlsx
Dashboard: results_dashboard.png
Validation: precision=0.012 recall=1.000 f1=0.025 accuracy=0.616
TP=3 FP=238 FN=0 TN=378 excluded=0 unknown=0
```
- **recall=1.000** — 捕获了所有已知异常(Test2),零漏报
- 误报的模型类似于 `BRA.Compressor` —— 它属于在不同的运行范围下工作的不同机器系列,但在真实标准中被标记为“Normal”。可以通过配置同业分组或调整阈值来减少此类情况。
## 运行模式
### 同业模式(默认 —— 推荐用于机组数据)
无需目标模型。引擎会根据工作表上的所有模型为每个标签构建一个 `PeerEnsemble`,并运行 `peer_*` 检测器。传统检测器(center_shift、PSI 等)会自动与综合生成的同业中位数参考进行对比。
```
target:
target_model: null # null = pure peer mode
peer_mode:
enabled: true
min_peers: 3
```
### 目标模式(传统模式 —— 单一参考模型)
设置 `target_model`,将所有模型与指定的唯一参考进行对比:
```
target:
target_model: "1 Mill AutoTrain"
```
## 异常类别
### 第 1 层 — 基于同业对比(可靠性最高)
| 名称 | 含义 | 检测方法 |
|---|---|---|
| `peer_center_shift` | 模型均值相对于同业中位数发生偏移 | 稳健 z 分数 (基于 MAD) |
| `peer_spread_shift` | 模型标准差不同于同业 | 标准差的稳健 z 分数 + 标准差比率 |
| `peer_envelope` | 分布质量超出同业 P5/P95 区间 | 留一法 (Leave-one-out) 的逐区间包络线 |
| `peer_near_zero` | 相较于同业出现卡死在零值的现象(即“Test2”异常) | 中位数与同业中位数的比率 |
### 第 2 层 — 统计 / 漂移
| 名称 | 含义 | 检测方法 |
|---|---|---|
| `center_shift` | 均值/中位数发生移动 | Cohen's d + KS 检验 |
| `spread_shift` | 分布变宽/变窄 | 标准差比率 + Levene 检验 |
| `missing_data` | 在同业存在数据密度的区域出现空隙 | 零区间空隙检测 |
| `skewness_shift` | 分布变得不对称 | 偏度差值 (Delta skewness) |
| `kurtosis_shift` | 尾部权重发生变化 | 峰度差值 (Delta kurtosis) |
| `bimodality` | 出现意外的第二峰 | Hartigan dip 检验 |
| `truncation` | 边界处数据堆积(截断) | 边缘质量 + 内部拟合残差 |
| `scale_anomaly` | 数据点明显增多/减少 | 计数比率 |
| `tail_anomaly` | 出现/消失的异常值 | p1/p99 百分位过冲 |
| `shape_divergence` | 整体形状不匹配 | Wasserstein 距离 |
| `psi` | 群体稳定性指标 | PSI (工业标准的漂移检测) |
| `flatness` | 异常平坦/均匀 | 熵比率 + 峰度 |
| `quantization` | 梳齿状分布(传感器舍入) | 唯一值密度 + 空内部区间 |
### 第 3 层 — 硬性规则(始终强制覆盖)
| 名称 | 含义 | 检测方法 |
|---|---|---|
| `physical_range` | 分布质量超出工程限制 | 基于 YAML 配置中每个标签的 min/max |
违反硬性规则会强制使 `any_abnormality = True` 并设定 `health_score = 0`,而不受软件评分的影响。
## 健康度评分
每一个 (tag, model) 对都会获得一个 **0-100 的健康度评分**:
- **100** — 未检测到异常
- **0** — 违反硬性规则(物理范围)
- 公式:`penalty = Σ(weight × severity × confidence) / Σ(all weights)` → `score = 100 × (1 - penalty)`
检测器权重(基于分层方法的最佳实践):
- 同业包络线 + 近零值:最高 (2.5–3.0)
- PSI + 形状:中高 (2.0–2.5)
- 单一矩统计量:中等 (1.0–1.5)
- 硬性规则:覆盖(直接降为 0)
## 配置参考 (`config.yaml`)
```
input:
file: "sampleData/MHPS Compressor_2026-07-15_05-24-19.xlsx"
skip_sheets: ["Anomaly Table"]
target:
target_model: null # null = peer mode
peer_mode:
enabled: true
min_peers: 3
ground_truth:
enabled: true
sheet: "Anomaly Table"
# 每个 tag 的工程限制(硬性规则)
physical_ranges:
"COMB SHELL - PRESS (P2C)":
min: 0
max: 200
detectors:
peer_center_shift:
enabled: true
z_threshold: 3.0
peer_envelope:
enabled: true
frac_threshold: 0.30
mass_threshold: 0.25
physical_range:
enabled: true
# ... (see config.yaml for all detectors)
```
## Excel 报告标签页
| 标签页 | 内容 |
|---|---|
| Summary | 计数 + 验证指标 |
| Health_Score | 每个 (tag, model) 的健康度评分,按最差情况优先排序 |
| Series_Metrics | 每个模型的均值、标准差、中位数、同业比较 |
| Out_of_Peer | 被同业检测器标记且带有证据的行 |
| Hard_Violations | 违反物理范围的记录 |
| Validation | 每个 (tag, model) 的真实值与预测值对比 |
| Detector_Hits | 每个真实异常被哪个检测器捕获 |
| All_Flags | 每一个 (tag, model, detector) 标记,长格式 |
| Flag_Matrix | 标签 × 检测器严重程度矩阵 |
## CLI 选项
## 文件结构
```
├── main.py — CLI entry point
├── config.yaml — all settings (edit this)
├── requirements.txt
├── src/
│ ├── config.py — config loader (peer mode, physical ranges, ground truth)
│ ├── data_model.py — HistogramData, AnalysisResult, DetectorResult
│ ├── loader.py — Excel reader
│ ├── binning.py — Freedman-Diaconis histogram binning
│ ├── statistics.py — moments, PSI, JSD, KL, Wasserstein, etc.
│ ├── peer.py — PeerEnsemble builder
│ ├── engine.py — batch orchestration + health scoring
│ ├── ground_truth.py — Anomaly Table loader + validation report
│ ├── excel_report.py — multi-tab Excel writer
│ ├── dashboard.py — PNG peer-envelope visualization
│ ├── report.py — JSONL writer
│ └── detectors/
│ ├── base.py
│ ├── peer.py — 4 peer detectors (center, spread, envelope, near_zero)
│ ├── physical_range.py — hard-rule detector
│ ├── center_shift.py
│ ├── spread_shift.py
│ ├── missing_data.py
│ ├── skewness_shift.py
│ ├── kurtosis_shift.py
│ ├── bimodality.py
│ ├── truncation.py — upgraded with interior-fit residual
│ ├── scale_anomaly.py
│ ├── tail_anomaly.py
│ ├── shape_divergence.py
│ ├── psi.py
│ ├── flatness.py
│ └── quantization.py
├── tests/
│ ├── test_detectors.py — synthetic ground-truth tests
│ ├── test_peer_detectors.py — peer detector + integration tests
│ ├── test_no_false_negatives.py
│ └── test_loader.py
├── sampleData/
│ └── MHPS Compressor_2026-07-15_05-24-19.xlsx
└── plan/
├── AISuggestions.md
└── feature-histogram-analyzer-1.md
```
## 前置条件
- **Python 3.10+**
- 一次性安装依赖项:
```
pip install -r requirements.txt
```
## 快速开始(3 步)
### 第 1 步 — 查看你的模型名称
运行检查工具以查看 Excel 文件中的内容:
```
python main.py --inspect
```
这会打印出每个工作表、每个模型、各自的数据点数量,以及当前被标记为目标的模型:
```
File: Mill Perf_2026-06-17_10-11-33.xlsx
Sheets (16):
[Anomaly Table] ← in skip_sheets (skipped)
[Sheet1] tag: 'AMPS'
1 Mill AutoTrain n= 391 2019-01-03 → 2019-03-31 ← current target
1A Mill Perf n= 393 2025-01-03 → 2025-03-28
1A Mill Perf - 2020-... n= 392 2019-01-01 → 2019-07-13
...
```
### 第 2 步 — 配置并运行
打开 `config.yaml` 并将 `target_model` 设置为你希望作为参考的确切模型名称:
```
target:
target_model: "1 Mill AutoTrain"
```
然后运行分析:
```
python main.py
```
输出:`results.jsonl`(每个标签下的每个对比模型各占一行)。
### 第 3 步 — 查看结果
```
python summarize.py
```
```
================================================================================
MILL PERFORMANCE ABNORMALITY REPORT
================================================================================
Source : Mill Perf_2026-06-17_10-11-33.xlsx
Target : 1 Mill AutoTrain
Pairs : 713 │ Flagged: 599 (84%) │ Clean: 114 (16%)
================================================================================
▶ TAG: AMPS (37/46 flagged)
────────────────────────────────────────────────────────────────────────────────
✓ 1A Mill Perf CLEAN
✗ 1A Mill Perf_2 spread:HIGH skew:HIGH kurtosis:HIGH tails:HIGH shape: MED
✗ 1A Mill Perf - 2025-05-20 ... spread:HIGH skew:HIGH kurtosis:HIGH tails:HIGH shape:HIGH
✓ 1A Mill Perf - 2020-02-27 ... CLEAN
...
================================================================================
MOST COMMON ABNORMALITIES (across all tags shown)
================================================================================
shape_divergence ████████████████████░░░░░░░░░░ 487/713 ( 68%) avg severity: 0.70
kurtosis_shift ████████████████████░░░░░░░░░░ 478/713 ( 67%) avg severity: 0.41
skewness_shift ████████████████████░░░░░░░░░░ 465/713 ( 65%) avg severity: 0.54
...
```
## 异常类别
| 名称 | 含义 | 检测方法 |
|---|---|---|
| `center_shift` | 均值/中位数向左或向右移动 | Cohen's d + KS 检验 |
| `spread_shift` | 分布明显变宽或变窄 | 标准差比率 + Levene 检验 |
| `missing_data` | 参考模型具有密度的区域出现空隙 | 零区间空隙检测 |
| `skewness_shift` | 分布变得更加不对称 | 偏度差值 (Delta skewness) |
| `kurtosis_shift` | 尾部比参考模型更重或更轻 | 峰度差值 (Delta kurtosis) |
| `bimodality` | 出现意外的第二峰 | Hartigan dip 检验 |
| `truncation` | 数据在测量边界处堆积 | 边界区间质量 |
| `scale_anomaly` | 数据点明显增多或减少 | 计数比率 |
| `tail_anomaly` | 出现或消失的异常值 | p1/p99 百分位过冲 |
| `shape_divergence` | 整体形状不匹配(兜底检测) | Wasserstein 距离 |
### 严重程度级别
| 标签 | 严重程度范围 | 含义 |
|---|---|---|
| `HIGH` | ≥ 0.6 | 显著差异 —— 可能为真实异常 |
| ` MED` | 0.3 – 0.59 | 中度差异 —— 值得审查 |
| ` LOW` | < 0.3 | 轻微差异 —— 低优先级 |
### 低漏报策略
当检测器不确定时(样本量小、统计处于边界状态),它会**默认设置为 flagged = true** 且置信度较低。此时需要人工进行核实。这可以防止遗漏工业设备中存在的真实问题。
## 摘要选项
```
# 完整报告
python summarize.py
# 仅显示被标记的 model(隐藏 CLEAN 行)
python summarize.py --flagged-only
# 过滤到特定的 tag
python summarize.py --tag "AMPS"
python summarize.py --tag "INLET PRESS" --flagged-only
# 跨所有 tag 过滤到特定的 model
python summarize.py --model "1A Mill Perf"
# 仅显示至少有一个 detector 命中 HIGH severity 的记录
python summarize.py --min-severity 0.6
# 从不同的结果文件读取
python summarize.py other_results.jsonl
```
## 主要 CLI 选项
```
# 检查 Excel 文件 — 发现工作表名称、model 名称、数据计数
python main.py --inspect
# 运行分析(读取 config.yaml)
python main.py
# 在运行时覆盖目标 model
python main.py --target "1B Mill Perf"
# 指向特定的 Excel 文件
python main.py --input "data/NewFile.xlsx"
# 处理目录中的所有 .xlsx 文件
python main.py --input-dir data/
# 追加到现有结果而不是覆盖
python main.py --input "NewFile.xlsx" --output results.jsonl --append
```
## 配置参考 (`config.yaml`)
```
input:
file: "Mill Perf_2026-06-17_10-11-33.xlsx" # single file to analyse
dir: null # or a directory of .xlsx files
skip_sheets: ["Anomaly Table"] # sheet names to ignore
target:
target_model: "1 Mill AutoTrain" # reference model — must match column header exactly
target_model_overrides: {} # per-sheet overrides: {Sheet1: OtherModel}
output:
path: "results.jsonl"
append: false # true = add to existing file
binning:
max_bins: 200 # cap on histogram bins
detectors:
center_shift:
enabled: true
d_threshold: 0.5 # Cohen's d (0.2=small, 0.5=medium, 0.8=large effect)
spread_shift:
enabled: true
upper: 1.5 # flag if comp_std / target_std > this
lower: 0.67 # flag if comp_std / target_std < this
missing_data:
enabled: true
gap_pct: 0.05 # fraction of target range that must be absent to flag
skewness_shift:
enabled: true
delta_threshold: 0.5 # abs(comp_skew - target_skew)
kurtosis_shift:
enabled: true
delta_threshold: 1.0 # abs(comp_kurt - target_kurt)
bimodality:
enabled: true
p_value_threshold: 0.05 # Hartigan dip test — lower = stricter
truncation:
enabled: true
edge_pct: 0.15 # boundary bin fraction threshold
scale_anomaly:
enabled: true
lower: 0.5 # flag if n_comp / n_target < this
upper: 2.0 # flag if n_comp / n_target > this
tail_anomaly:
enabled: true
sigma_threshold: 2.0 # standard deviations beyond reference p1/p99
shape_divergence:
enabled: true
wasserstein_threshold: 0.3 # normalized Wasserstein distance
```
### 调整灵敏度
这些阈值是**自参考**的 —— 每个阈值都是相对于参考模型自身的统计数据来表示的,因此不同的信号类型(温度 vs RPM vs 压力)会自动进行校准。
若要让检测**更严格**(减少标记):调高阈值。
若要让检测**更敏感**(增加标记):调低阈值。
若要彻底禁用特定的检测器:
```
detectors:
kurtosis_shift:
enabled: false
```
## 输出文件格式 (`results.jsonl`)
每行一个 JSON 对象,每个 `(tag, comparison_model)` 对占一行:
```
{
"file": "Mill Perf_2026-06-17_10-11-33.xlsx",
"sheet": "AMPS",
"target_model": "1 Mill AutoTrain",
"comparison_model": "1A Mill Perf_2",
"n_target": 391,
"n_comparison": 397,
"date_range_target": { "min": "2019-01-03", "max": "2019-03-31" },
"date_range_comparison": { "min": "2019-01-02", "max": "2019-07-30" },
"flags": {
"center_shift": { "flagged": false, "severity": 0.10, "confidence": 0.97 },
"spread_shift": { "flagged": true, "severity": 0.79, "confidence": 1.00 },
"missing_data": { "flagged": false, "severity": 0.00, "confidence": 1.00 },
"skewness_shift": { "flagged": true, "severity": 1.00, "confidence": 1.00 },
"kurtosis_shift": { "flagged": true, "severity": 1.00, "confidence": 1.00 },
"bimodality": { "flagged": false, "severity": 0.38, "confidence": 1.00 },
"truncation": { "flagged": false, "severity": 0.06, "confidence": 1.00 },
"scale_anomaly": { "flagged": false, "severity": 0.00, "confidence": 1.00 },
"tail_anomaly": { "flagged": true, "severity": 1.00, "confidence": 1.00 },
"shape_divergence":{ "flagged": true, "severity": 0.46, "confidence": 1.00 }
},
"any_abnormality": true
}
```
**字段参考:**
- `flagged` — `true` = 检测到异常,`false` = 正常,`null` = 检测器已跳过(该标签没有参考数据)
- `severity` — `0.0` 到 `1.0`,表示异常的严重程度(而不仅仅是是否存在异常)
- `confidence` — `0.0` 到 `1.0`,表示此标记在统计学上的可靠程度。低于 `0.6` 的值会自动设定为 `flagged: true`(保守策略)。
- `any_abnormality` — 如果**任何**检测器标记了该数据对,则为 `true`
## Excel 文件要求
| 行 | 内容 |
|---|---|
| 0 | `Template Tag:` \| `` \| (empty...) |
| 1 | `Model:` \| `` \| `Model:` \| `` \| ... |
| 2 | `Timestamp (UTC)` \| `Value` \| `Timestamp (UTC)` \| `Value` \| ... |
| 3+ | 实际数据行 |
- 每个工作表代表一个信号/标签
- 列以 `(timestamp, value)` 对的形式出现,每个模型一对
- `config.yaml` 中的 `target_model` 名称必须与工作表第 1 行中出现的模型名称完全匹配(区分大小写)
- 非数据工作表(例如汇总表)应列在 `config.yaml` 的 `skip_sheets` 下
## 文件结构
```
D:\AI helper\
├── main.py — run analysis, inspect files
├── summarize.py — human-readable report from results.jsonl
├── config.yaml — all settings (edit this)
├── requirements.txt — Python dependencies
├── results.jsonl — analysis output (generated)
├── src/
│ ├── config.py — config loader
│ ├── data_model.py — dataclasses (HistogramData, DetectorResult, AnalysisResult)
│ ├── loader.py — Excel reader
│ ├── binning.py — Freedman-Diaconis histogram binning
│ ├── statistics.py — Cohen's d, KS test, Levene, Wasserstein, etc.
│ ├── engine.py — batch orchestration
│ ├── report.py — JSONL writer
│ └── detectors/
│ ├── base.py
│ ├── center_shift.py
│ ├── spread_shift.py
│ ├── missing_data.py
│ ├── skewness_shift.py
│ ├── kurtosis_shift.py
│ ├── bimodality.py
│ ├── truncation.py
│ ├── scale_anomaly.py
│ ├── tail_anomaly.py
│ └── shape_divergence.py
├── tests/
│ ├── test_detectors.py — synthetic ground-truth tests
│ ├── test_no_false_negatives.py — low-confidence policy tests
│ └── test_loader.py — Excel parsing tests
└── plan/
└── feature-histogram-analyzer-1.md — implementation plan
```
## 故障排除
**`WARNING: target 'X' not found in sheet 'Y'`**
→ `config.yaml` 中的模型名称与该工作表中的列标题不匹配。运行 `python main.py --inspect` 查看确切的名称并纠正拼写。
**某个标签下的所有模型均显示为 CLEAN**
→ 目标模型在该标签下可能只有极少的数据 (n < 30)。inspect 的输出会显示每个模型的 n 值。考虑通过 `target_model_overrides` 为该标签使用不同的参考模型。
**HIGH 标记过多 / 标记过少**
→ 调整 `config.yaml` 中的阈值乘数。请参阅“配置参考”部分。调高 `d_threshold`、`wasserstein_threshold` 等会降低敏感度;调低它们则会增加敏感度。
**`No results produced`**
→ 检查 `config.yaml` 是否指向了现有文件,并确保 `skip_sheets` 没有意外排除所有数据工作表。
标签:逆向工具