priorityx 0.3.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- priorityx-0.5.0/.github/workflows/docs.yml +31 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/.github/workflows/release.yml +2 -2
- {priorityx-0.3.0 → priorityx-0.5.0}/.github/workflows/test.yml +1 -1
- priorityx-0.5.0/CHANGELOG.md +74 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/PKG-INFO +56 -1
- {priorityx-0.3.0 → priorityx-0.5.0}/README.md +55 -0
- priorityx-0.5.0/docs/api-reference.md +407 -0
- priorityx-0.5.0/docs/changelog.md +59 -0
- priorityx-0.5.0/docs/index.md +106 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/docs/methodology.md +7 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/docs/output_naming.md +4 -5
- {priorityx-0.3.0 → priorityx-0.5.0}/docs/priority_classification.md +1 -1
- {priorityx-0.3.0 → priorityx-0.5.0}/docs/quickstart.md +28 -21
- priorityx-0.5.0/mkdocs.yml +40 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/pyproject.toml +4 -1
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/__init__.py +25 -4
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/api.py +9 -5
- priorityx-0.5.0/src/priorityx/core/glmm.py +784 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/core/quadrants.py +11 -10
- priorityx-0.5.0/src/priorityx/metrics.py +397 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/tracking/drivers.py +252 -43
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/tracking/movement.py +17 -5
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/tracking/transitions.py +5 -5
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/viz/matrix.py +204 -70
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/viz/timeline.py +71 -23
- priorityx-0.5.0/src/priorityx/viz/trajectory.py +486 -0
- priorityx-0.5.0/tests/test_api_axes.py +90 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/tests/test_drivers.py +173 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/tests/test_glmm.py +77 -2
- priorityx-0.5.0/tests/test_metrics.py +78 -0
- priorityx-0.5.0/tests/test_movement_monthly.py +189 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/tests/test_quadrants.py +4 -2
- priorityx-0.5.0/tests/test_viz_matrix.py +47 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/uv.lock +207 -1
- priorityx-0.3.0/docs/README.md +0 -15
- priorityx-0.3.0/docs/api-reference.md +0 -239
- priorityx-0.3.0/src/priorityx/core/glmm.py +0 -429
- priorityx-0.3.0/src/priorityx/viz/trajectory.py +0 -335
- priorityx-0.3.0/tests/test_movement_monthly.py +0 -108
- {priorityx-0.3.0 → priorityx-0.5.0}/.gitignore +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/LICENSE +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/Makefile +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/examples/README.md +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/examples/bugs/bugs_monitoring.py +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/examples/incidents/incident_monitoring.py +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/examples/violations/violations_monitoring.py +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/scripts/version.py +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/core/__init__.py +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/core/filters.py +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/tracking/__init__.py +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/utils/__init__.py +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/utils/helpers.py +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/src/priorityx/viz/__init__.py +0 -0
- {priorityx-0.3.0 → priorityx-0.5.0}/tests/test_transitions.py +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Deploy Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths:
|
|
8
|
+
- 'docs/**'
|
|
9
|
+
- 'mkdocs.yml'
|
|
10
|
+
- '.github/workflows/docs.yml'
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: write
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
deploy:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
uses: actions/setup-python@v6
|
|
24
|
+
with:
|
|
25
|
+
python-version: '3.11'
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: pip install mkdocs mkdocs-material pymdown-extensions
|
|
29
|
+
|
|
30
|
+
- name: Deploy to GitHub Pages
|
|
31
|
+
run: mkdocs gh-deploy --force
|
|
@@ -13,7 +13,7 @@ jobs:
|
|
|
13
13
|
name: Build package
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
steps:
|
|
16
|
-
- uses: actions/checkout@
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
17
|
|
|
18
18
|
- name: Set up Python
|
|
19
19
|
uses: actions/setup-python@v6
|
|
@@ -87,7 +87,7 @@ jobs:
|
|
|
87
87
|
contents: write
|
|
88
88
|
|
|
89
89
|
steps:
|
|
90
|
-
- uses: actions/checkout@
|
|
90
|
+
- uses: actions/checkout@v6
|
|
91
91
|
|
|
92
92
|
- name: Create Release
|
|
93
93
|
uses: softprops/action-gh-release@v2
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Only major releases (v0.x.0) are listed.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## v0.4.0 (2025-01)
|
|
8
|
+
|
|
9
|
+
**Unified API with Axis Metrics**
|
|
10
|
+
|
|
11
|
+
- Introduced `x_metric` / `y_metric` parameters to `fit_priority_matrix()` for flexible axis definitions beyond default volume/growth
|
|
12
|
+
- Added `x_score` / `y_score` coordinate-based quadrant classification (replaces Random_Intercept/Random_Slope naming in outputs)
|
|
13
|
+
- Added Gamma family support for continuous GLMM (e.g., duration or amount metrics)
|
|
14
|
+
- Gaussian GLMM support for metric-based axes
|
|
15
|
+
- Improved quadrant label rendering with configurable legend position (`legend_loc`, `show_legend`)
|
|
16
|
+
- Row-aligned quadrant label offsetting to avoid legend overlap
|
|
17
|
+
|
|
18
|
+
**Trajectory Auto-Selection**
|
|
19
|
+
|
|
20
|
+
- Added `highlight_top_n` parameter to `plot_entity_trajectories()` for automatic entity selection
|
|
21
|
+
- Added `highlight_by` parameter: `"trajectory_distance"` (euclidean path) or `"total_movement"` (manhattan)
|
|
22
|
+
- Added `recent_periods` parameter to limit trajectory window to last N periods
|
|
23
|
+
|
|
24
|
+
**Enhanced Driver Analysis**
|
|
25
|
+
|
|
26
|
+
- Added `numeric_cols` parameter to `extract_transition_drivers()` for amount/duration breakdowns
|
|
27
|
+
- Explicit bins: `{"amount": [0, 1e6, 5e6, 10e6]}`
|
|
28
|
+
- Auto quantiles: `{"duration": 4}` (4 bins)
|
|
29
|
+
- Renamed `quarter_from`/`quarter_to` to `period_from`/`period_to` (backwards compatible)
|
|
30
|
+
- Renamed `top_n_subcategories` to `top_n`, `min_subcategory_delta` to `min_delta` (backwards compatible)
|
|
31
|
+
- Added `save_txt`, `txt_path`, `txt_mode` parameters to `display_transition_drivers()` for file output
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## v0.3.0 (2024-12)
|
|
36
|
+
|
|
37
|
+
**Entity Metrics and Priority Indices**
|
|
38
|
+
|
|
39
|
+
- Implemented `add_priority_indices()` for composite index calculation:
|
|
40
|
+
- **RI** (Risk Index): volume + growth + severity
|
|
41
|
+
- **SQI** (Service Quality Index): resolution speed + recovery rate
|
|
42
|
+
- **EWI** (Early Warning Index): blends RI and SQI for prioritization
|
|
43
|
+
- Added `aggregate_entity_metrics()` helper for per-entity metric aggregation
|
|
44
|
+
- Added `sensitivity_analysis()` for weight stability testing
|
|
45
|
+
- Monthly granularity support (beta) in GLMM and visualizations
|
|
46
|
+
- Unified `px.*` namespace imports pattern
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## v0.2.0 (2024-11)
|
|
51
|
+
|
|
52
|
+
**Transition Tracking and Visualization**
|
|
53
|
+
|
|
54
|
+
- Implemented `track_cumulative_movement()` for entity trajectory tracking
|
|
55
|
+
- Added `extract_transitions()` for quadrant movement detection
|
|
56
|
+
- Transition timeline visualization with priority-based coloring (Crisis/Investigate/Monitor/Low)
|
|
57
|
+
- Spike markers (`*X`, `*Y`, `*XY`) for volume/growth spikes
|
|
58
|
+
- Deterministic seeding via `PRIORITYX_GLMM_SEED` for reproducible GLMM fits
|
|
59
|
+
- `plot_entity_trajectories()` for movement path visualization
|
|
60
|
+
- Transition driver analysis (experimental)
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## v0.1.0 (2024-10)
|
|
65
|
+
|
|
66
|
+
**Initial Release**
|
|
67
|
+
|
|
68
|
+
- Core GLMM estimation with Poisson mixed effects (statsmodels backend)
|
|
69
|
+
- `fit_priority_matrix()` main API for entity prioritization
|
|
70
|
+
- Quadrant classification (Q1-Q4) based on volume and growth
|
|
71
|
+
- Priority matrix scatter plot visualization
|
|
72
|
+
- Quarterly, yearly, and semiannual temporal granularity
|
|
73
|
+
- Date filtering and minimum observation thresholds
|
|
74
|
+
- CSV and plot export with configurable output directories
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: priorityx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Entity prioritization and escalation detection using GLMM statistical models
|
|
5
5
|
Project-URL: Homepage, https://github.com/okkymabruri/priorityx
|
|
6
6
|
Project-URL: Repository, https://github.com/okkymabruri/priorityx
|
|
@@ -50,16 +50,71 @@ import priorityx as px
|
|
|
50
50
|
|
|
51
51
|
df = pd.read_csv("data.csv")
|
|
52
52
|
|
|
53
|
+
# Default: volume x growth (single GLMM)
|
|
53
54
|
results, stats = px.fit_priority_matrix(
|
|
54
55
|
df,
|
|
55
56
|
entity_col="service",
|
|
56
57
|
timestamp_col="date",
|
|
57
58
|
temporal_granularity="quarterly",
|
|
58
59
|
)
|
|
60
|
+
# Returns: entity, x_score, y_score, count, quadrant
|
|
59
61
|
|
|
60
62
|
px.plot_priority_matrix(results, entity_name="Service", save_plot=True)
|
|
61
63
|
```
|
|
62
64
|
|
|
65
|
+
### Custom Axes
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
# Custom Y axis: volume × resolution_days (two GLMMs)
|
|
69
|
+
results, _ = px.fit_priority_matrix(
|
|
70
|
+
df,
|
|
71
|
+
entity_col="service",
|
|
72
|
+
timestamp_col="date",
|
|
73
|
+
y_metric="resolution_days",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Custom both axes: disputed_amount × paid_amount
|
|
77
|
+
results, _ = px.fit_priority_matrix(
|
|
78
|
+
df,
|
|
79
|
+
entity_col="service",
|
|
80
|
+
timestamp_col="date",
|
|
81
|
+
x_metric="disputed_amount",
|
|
82
|
+
y_metric="paid_amount",
|
|
83
|
+
)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Composite Indices
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
# Add entity metrics
|
|
90
|
+
metrics = px.aggregate_entity_metrics(
|
|
91
|
+
df,
|
|
92
|
+
entity_col="service",
|
|
93
|
+
duration_start_col="opened_at",
|
|
94
|
+
duration_end_col="closed_at",
|
|
95
|
+
primary_col="exposure",
|
|
96
|
+
secondary_col="recovery",
|
|
97
|
+
)
|
|
98
|
+
results = results.merge(metrics, left_on="entity", right_on="service", how="left")
|
|
99
|
+
|
|
100
|
+
# Add weighted indices: RI (Risk), SQI (Service Quality), EWI (Early Warning)
|
|
101
|
+
results = px.add_priority_indices(
|
|
102
|
+
results,
|
|
103
|
+
volume_col="count",
|
|
104
|
+
growth_col="y_score",
|
|
105
|
+
severity_col="total_primary",
|
|
106
|
+
resolution_col="mean_duration",
|
|
107
|
+
recovery_col="secondary_to_primary_ratio",
|
|
108
|
+
# customize weights (default shown)
|
|
109
|
+
w_volume=0.4, w_growth=0.4, w_severity=0.2,
|
|
110
|
+
w_resolution=0.5, w_recovery=0.5,
|
|
111
|
+
w_risk=0.7, w_quality=0.3,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Top priority entities
|
|
115
|
+
top_risks = results.nlargest(10, "EWI")
|
|
116
|
+
```
|
|
117
|
+
|
|
63
118
|
## Features
|
|
64
119
|
|
|
65
120
|
- GLMM-based priority matrix (Q1–Q4) with entity-level intercept/slope insights
|
|
@@ -22,16 +22,71 @@ import priorityx as px
|
|
|
22
22
|
|
|
23
23
|
df = pd.read_csv("data.csv")
|
|
24
24
|
|
|
25
|
+
# Default: volume x growth (single GLMM)
|
|
25
26
|
results, stats = px.fit_priority_matrix(
|
|
26
27
|
df,
|
|
27
28
|
entity_col="service",
|
|
28
29
|
timestamp_col="date",
|
|
29
30
|
temporal_granularity="quarterly",
|
|
30
31
|
)
|
|
32
|
+
# Returns: entity, x_score, y_score, count, quadrant
|
|
31
33
|
|
|
32
34
|
px.plot_priority_matrix(results, entity_name="Service", save_plot=True)
|
|
33
35
|
```
|
|
34
36
|
|
|
37
|
+
### Custom Axes
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
# Custom Y axis: volume × resolution_days (two GLMMs)
|
|
41
|
+
results, _ = px.fit_priority_matrix(
|
|
42
|
+
df,
|
|
43
|
+
entity_col="service",
|
|
44
|
+
timestamp_col="date",
|
|
45
|
+
y_metric="resolution_days",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Custom both axes: disputed_amount × paid_amount
|
|
49
|
+
results, _ = px.fit_priority_matrix(
|
|
50
|
+
df,
|
|
51
|
+
entity_col="service",
|
|
52
|
+
timestamp_col="date",
|
|
53
|
+
x_metric="disputed_amount",
|
|
54
|
+
y_metric="paid_amount",
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Composite Indices
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
# Add entity metrics
|
|
62
|
+
metrics = px.aggregate_entity_metrics(
|
|
63
|
+
df,
|
|
64
|
+
entity_col="service",
|
|
65
|
+
duration_start_col="opened_at",
|
|
66
|
+
duration_end_col="closed_at",
|
|
67
|
+
primary_col="exposure",
|
|
68
|
+
secondary_col="recovery",
|
|
69
|
+
)
|
|
70
|
+
results = results.merge(metrics, left_on="entity", right_on="service", how="left")
|
|
71
|
+
|
|
72
|
+
# Add weighted indices: RI (Risk), SQI (Service Quality), EWI (Early Warning)
|
|
73
|
+
results = px.add_priority_indices(
|
|
74
|
+
results,
|
|
75
|
+
volume_col="count",
|
|
76
|
+
growth_col="y_score",
|
|
77
|
+
severity_col="total_primary",
|
|
78
|
+
resolution_col="mean_duration",
|
|
79
|
+
recovery_col="secondary_to_primary_ratio",
|
|
80
|
+
# customize weights (default shown)
|
|
81
|
+
w_volume=0.4, w_growth=0.4, w_severity=0.2,
|
|
82
|
+
w_resolution=0.5, w_recovery=0.5,
|
|
83
|
+
w_risk=0.7, w_quality=0.3,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Top priority entities
|
|
87
|
+
top_risks = results.nlargest(10, "EWI")
|
|
88
|
+
```
|
|
89
|
+
|
|
35
90
|
## Features
|
|
36
91
|
|
|
37
92
|
- GLMM-based priority matrix (Q1–Q4) with entity-level intercept/slope insights
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
## Core Functions
|
|
4
|
+
|
|
5
|
+
### fit_priority_matrix
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
import priorityx as px
|
|
9
|
+
|
|
10
|
+
# Default: volume × growth (single GLMM)
|
|
11
|
+
results, stats = px.fit_priority_matrix(
|
|
12
|
+
df,
|
|
13
|
+
entity_col="service",
|
|
14
|
+
timestamp_col="date",
|
|
15
|
+
temporal_granularity="quarterly",
|
|
16
|
+
)
|
|
17
|
+
# Returns: entity, x_score, y_score, count, quadrant
|
|
18
|
+
|
|
19
|
+
# Custom Y axis: volume × resolution_days (two GLMMs)
|
|
20
|
+
results, stats = px.fit_priority_matrix(
|
|
21
|
+
df,
|
|
22
|
+
entity_col="service",
|
|
23
|
+
timestamp_col="date",
|
|
24
|
+
y_metric="resolution_days",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Custom both axes with Gamma family for right-skewed data
|
|
28
|
+
results, stats = px.fit_priority_matrix(
|
|
29
|
+
df,
|
|
30
|
+
entity_col="service",
|
|
31
|
+
timestamp_col="date",
|
|
32
|
+
x_metric="disputed_amount",
|
|
33
|
+
y_metric="paid_amount",
|
|
34
|
+
family="gamma",
|
|
35
|
+
)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Unified entry point for GLMM-based entity prioritization. Supports count-based (Poisson) and metric-based (Gaussian/Gamma) axes.
|
|
39
|
+
|
|
40
|
+
**Parameters:**
|
|
41
|
+
|
|
42
|
+
- `df`: pandas DataFrame with one row per event
|
|
43
|
+
- `entity_col`: Entity identifier column name
|
|
44
|
+
- `timestamp_col`: Date column name
|
|
45
|
+
- `x_metric`: Optional metric column for X axis (None = count-based)
|
|
46
|
+
- `y_metric`: Optional metric column for Y axis (None = count-based)
|
|
47
|
+
- `x_effect`: Random effect for X score ("intercept" or "slope", default: "intercept")
|
|
48
|
+
- `y_effect`: Random effect for Y score ("intercept" or "slope", default: "slope")
|
|
49
|
+
- `family`: Distribution for continuous metrics ("gaussian" or "gamma", default: "gaussian")
|
|
50
|
+
- `count_col`: Optional count column (default: row count per entity-period)
|
|
51
|
+
- `date_filter`: Date filter string (e.g., "< 2025-01-01", ">= 2024-01-01")
|
|
52
|
+
- `min_observations`: Minimum time periods required per entity
|
|
53
|
+
- `min_total_count`: Minimum total count threshold
|
|
54
|
+
- `decline_window_quarters`: Filter entities inactive >N quarters
|
|
55
|
+
- `temporal_granularity`: "yearly", "quarterly", "semiannual", or "monthly"
|
|
56
|
+
- `vcp_p`: Random effects prior scale (default: 3.5)
|
|
57
|
+
- `fe_p`: Fixed effects prior scale (default: 3.0)
|
|
58
|
+
|
|
59
|
+
**Returns:**
|
|
60
|
+
|
|
61
|
+
- `results`: DataFrame with `entity`, `x_score`, `y_score`, `count`, `quadrant`
|
|
62
|
+
- `stats`: Dictionary with model statistics
|
|
63
|
+
|
|
64
|
+
**Family Selection:**
|
|
65
|
+
|
|
66
|
+
- `"gaussian"` (default): Works for any data, robust for entity ranking
|
|
67
|
+
- `"gamma"`: Use for right-skewed positive data (durations, monetary amounts)
|
|
68
|
+
|
|
69
|
+
> **Reproducibility:** set the environment variable `PRIORITYX_GLMM_SEED` or call `set_glmm_random_seed(value)` before invoking `fit_priority_matrix` to obtain deterministic variational Bayes estimates.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Metrics Functions
|
|
74
|
+
|
|
75
|
+
### aggregate_entity_metrics
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import priorityx as px
|
|
79
|
+
|
|
80
|
+
metrics = px.aggregate_entity_metrics(
|
|
81
|
+
df,
|
|
82
|
+
entity_col="service",
|
|
83
|
+
duration_start_col="opened_at",
|
|
84
|
+
duration_end_col="closed_at",
|
|
85
|
+
primary_col="exposure",
|
|
86
|
+
secondary_col="recovery",
|
|
87
|
+
)
|
|
88
|
+
# Returns: entity, mean_duration, total_primary, total_secondary, secondary_to_primary_ratio
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Computes per-entity aggregated metrics for enrichment.
|
|
92
|
+
|
|
93
|
+
### add_priority_indices
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
import priorityx as px
|
|
97
|
+
|
|
98
|
+
enriched = px.add_priority_indices(
|
|
99
|
+
results,
|
|
100
|
+
volume_col="count",
|
|
101
|
+
growth_col="y_score",
|
|
102
|
+
severity_col="total_primary",
|
|
103
|
+
resolution_col="mean_duration",
|
|
104
|
+
recovery_col="secondary_to_primary_ratio",
|
|
105
|
+
# Weights (defaults shown)
|
|
106
|
+
w_volume=0.4, w_growth=0.4, w_severity=0.2,
|
|
107
|
+
w_resolution=0.5, w_recovery=0.5,
|
|
108
|
+
w_risk=0.7, w_quality=0.3,
|
|
109
|
+
)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Adds composite risk indices to enriched entity data.
|
|
113
|
+
|
|
114
|
+
**Output columns:**
|
|
115
|
+
|
|
116
|
+
- `z_volume`, `z_growth`, `z_severity`: Z-scored risk components
|
|
117
|
+
- `z_neg_resolution`, `z_recovery`: Z-scored quality components
|
|
118
|
+
- `RI`: Risk Index = weighted sum of z_volume, z_growth, z_severity
|
|
119
|
+
- `SQI`: Service Quality Index = weighted sum of z_neg_resolution, z_recovery
|
|
120
|
+
- `EWI`: Early Warning Index = w_risk × RI + w_quality × (-SQI)
|
|
121
|
+
|
|
122
|
+
**Usage:**
|
|
123
|
+
```python
|
|
124
|
+
# Top priority entities
|
|
125
|
+
top_risks = enriched.nlargest(10, "EWI")
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### sensitivity_analysis
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
import priorityx as px
|
|
132
|
+
|
|
133
|
+
results = px.sensitivity_analysis(
|
|
134
|
+
df,
|
|
135
|
+
index_col="EWI",
|
|
136
|
+
entity_col="entity",
|
|
137
|
+
weight_ranges={
|
|
138
|
+
"w_risk": [0.6, 0.7, 0.8],
|
|
139
|
+
"w_quality": [0.2, 0.3, 0.4],
|
|
140
|
+
},
|
|
141
|
+
top_n=10,
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Tests ranking stability across weight variations.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Tracking Functions
|
|
150
|
+
|
|
151
|
+
### track_cumulative_movement
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
import priorityx as px
|
|
155
|
+
|
|
156
|
+
movement, meta = px.track_cumulative_movement(
|
|
157
|
+
df,
|
|
158
|
+
entity_col,
|
|
159
|
+
timestamp_col,
|
|
160
|
+
quarters=None,
|
|
161
|
+
min_total_count=20,
|
|
162
|
+
decline_window_quarters=6,
|
|
163
|
+
temporal_granularity="quarterly",
|
|
164
|
+
vcp_p=3.5,
|
|
165
|
+
fe_p=3.0
|
|
166
|
+
)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Tracks entity movement through priority quadrants over time.
|
|
170
|
+
|
|
171
|
+
**Returns:**
|
|
172
|
+
|
|
173
|
+
- `movement`: DataFrame with quarterly X/Y positions
|
|
174
|
+
- `meta`: Dictionary with tracking metadata
|
|
175
|
+
|
|
176
|
+
### extract_transitions
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
import priorityx as px
|
|
180
|
+
|
|
181
|
+
transitions = px.extract_transitions(
|
|
182
|
+
movement_df,
|
|
183
|
+
focus_risk_increasing=True
|
|
184
|
+
)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Extracts quadrant transitions from movement data.
|
|
188
|
+
|
|
189
|
+
**Returns:**
|
|
190
|
+
|
|
191
|
+
- DataFrame with transition details and risk levels
|
|
192
|
+
|
|
193
|
+
### extract_transition_drivers
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
import priorityx as px
|
|
197
|
+
|
|
198
|
+
# Basic usage with categorical breakdowns
|
|
199
|
+
analysis = px.extract_transition_drivers(
|
|
200
|
+
movement_df,
|
|
201
|
+
df_raw,
|
|
202
|
+
entity_name="Service A",
|
|
203
|
+
period_from="2024-Q2",
|
|
204
|
+
period_to="2024-Q3",
|
|
205
|
+
entity_col="service",
|
|
206
|
+
timestamp_col="date",
|
|
207
|
+
subcategory_cols=["type", "category"], # categorical breakdowns
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# With numeric column breakdowns (amounts, durations)
|
|
211
|
+
analysis = px.extract_transition_drivers(
|
|
212
|
+
movement_df,
|
|
213
|
+
df_raw,
|
|
214
|
+
entity_name="Fintech - Pinjaman Online",
|
|
215
|
+
period_from="2024-Q3",
|
|
216
|
+
period_to="2024-Q4",
|
|
217
|
+
entity_col="product",
|
|
218
|
+
timestamp_col="date",
|
|
219
|
+
subcategory_cols=["region", "gender"],
|
|
220
|
+
numeric_cols={
|
|
221
|
+
"disputed_amount": [0, 1e6, 5e6, 10e6], # explicit bin edges
|
|
222
|
+
"resolution_days": 4, # 4 quantile bins (auto)
|
|
223
|
+
},
|
|
224
|
+
)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Analyzes root causes of a quadrant transition.
|
|
228
|
+
|
|
229
|
+
**Parameters:**
|
|
230
|
+
|
|
231
|
+
- `movement_df`: Output from track_cumulative_movement()
|
|
232
|
+
- `df_raw`: Raw event data (pandas DataFrame)
|
|
233
|
+
- `entity_name`: Entity to analyze
|
|
234
|
+
- `period_from`: Starting period (e.g., "2024-Q2", "2024-01")
|
|
235
|
+
- `period_to`: Ending period (e.g., "2024-Q3", "2024-02")
|
|
236
|
+
- `entity_col`: Entity column name
|
|
237
|
+
- `timestamp_col`: Timestamp column name
|
|
238
|
+
- `subcategory_cols`: Optional list of categorical columns for breakdown (auto-detected when omitted)
|
|
239
|
+
- `numeric_cols`: Optional dict of numeric columns with bin specs:
|
|
240
|
+
- List of floats: explicit bin edges (e.g., `[0, 1e6, 5e6, 10e6]`)
|
|
241
|
+
- Integer: number of quantile bins (e.g., `4` for quartiles)
|
|
242
|
+
- `top_n`: Limit of drivers per column (default: 3)
|
|
243
|
+
- `min_delta`: Minimum count delta for inclusion (default: 1)
|
|
244
|
+
|
|
245
|
+
**Returns:**
|
|
246
|
+
|
|
247
|
+
- Dictionary with:
|
|
248
|
+
- `transition`: includes risk-level change and `is_concerning` flag
|
|
249
|
+
- `magnitude`: cumulative deltas plus period-specific weekly averages and complaint counts
|
|
250
|
+
- `spike_drivers`: summary notes aligned with spike indicators (`*X`, `*Y`, `*XY`)
|
|
251
|
+
- `subcategory_drivers`: per-column driver lists for categorical columns
|
|
252
|
+
- `numeric_drivers`: per-column driver lists for numeric columns (with bin edges)
|
|
253
|
+
- `priority`: priority tier, trigger reason, spike axis
|
|
254
|
+
- `meta`: diagnostic flags (e.g., whether subcategory columns were auto-detected)
|
|
255
|
+
|
|
256
|
+
### classify_priority
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
from priorityx.tracking.drivers import classify_priority
|
|
260
|
+
|
|
261
|
+
priority, reason, spike_axis = classify_priority(
|
|
262
|
+
from_quadrant="Q3",
|
|
263
|
+
to_quadrant="Q1",
|
|
264
|
+
x=0.5, y=0.6,
|
|
265
|
+
x_delta=0.5, y_delta=0.5,
|
|
266
|
+
count_delta=100,
|
|
267
|
+
percent_change=200
|
|
268
|
+
)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Classifies supervisory priority (1=Critical, 2=Investigate, 3=Monitor, 4=Low).
|
|
272
|
+
|
|
273
|
+
**Returns:**
|
|
274
|
+
|
|
275
|
+
- Tuple of (priority, reason, spike_axis)
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Visualization Functions
|
|
280
|
+
|
|
281
|
+
### plot_priority_matrix
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
import priorityx as px
|
|
285
|
+
|
|
286
|
+
fig = px.plot_priority_matrix(
|
|
287
|
+
results_df,
|
|
288
|
+
entity_name="Entity",
|
|
289
|
+
figsize=(16, 12),
|
|
290
|
+
top_n_labels=5,
|
|
291
|
+
show_quadrant_labels=False,
|
|
292
|
+
save_plot=False,
|
|
293
|
+
output_dir="plot"
|
|
294
|
+
)
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Creates scatter plot of priority matrix.
|
|
298
|
+
|
|
299
|
+
### plot_transition_timeline
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
import priorityx as px
|
|
303
|
+
|
|
304
|
+
fig = px.plot_transition_timeline(
|
|
305
|
+
transitions_df,
|
|
306
|
+
entity_name="Entity",
|
|
307
|
+
filter_risk_levels=["critical", "high"],
|
|
308
|
+
max_entities=20,
|
|
309
|
+
save_plot=False,
|
|
310
|
+
output_dir="plot",
|
|
311
|
+
movement_df=movement_df
|
|
312
|
+
)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Creates timeline heatmap of transitions. Passing `movement_df` is required to compute the Crisis/Investigate/Monitor/Low priority tiers and spike markers (`*X`, `*Y`, `*XY`). Omitting it falls back to legacy risk-level tags.
|
|
316
|
+
|
|
317
|
+
### plot_entity_trajectories
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
import priorityx as px
|
|
321
|
+
|
|
322
|
+
# Basic usage
|
|
323
|
+
fig = px.plot_entity_trajectories(
|
|
324
|
+
movement_df,
|
|
325
|
+
entity_name="Entity",
|
|
326
|
+
max_entities=10,
|
|
327
|
+
save_plot=False,
|
|
328
|
+
plot_dir="plot"
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
# Auto-select top movers (recommended)
|
|
332
|
+
fig = px.plot_entity_trajectories(
|
|
333
|
+
movement_df,
|
|
334
|
+
entity_name="product",
|
|
335
|
+
highlight_top_n=4, # auto-select top 4 entities
|
|
336
|
+
highlight_by="trajectory_distance", # by path length (or "total_movement")
|
|
337
|
+
recent_periods=6, # limit to last 6 periods
|
|
338
|
+
save_plot=True,
|
|
339
|
+
plot_dir="results/plot",
|
|
340
|
+
)
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Creates trajectory plot showing entity paths through priority space.
|
|
344
|
+
|
|
345
|
+
**Parameters:**
|
|
346
|
+
|
|
347
|
+
- `movement_df`: Output from track_cumulative_movement()
|
|
348
|
+
- `entity_name`: Label for entity type (e.g., "product", "service")
|
|
349
|
+
- `max_entities`: Maximum entities to show (default: 10)
|
|
350
|
+
- `highlight_entities`: List of specific entities to highlight
|
|
351
|
+
- `highlight_top_n`: Auto-select top N entities by movement (overrides max_entities)
|
|
352
|
+
- `highlight_by`: Selection method when using highlight_top_n:
|
|
353
|
+
- `"trajectory_distance"`: Euclidean path length (sum of sqrt(dx² + dy²))
|
|
354
|
+
- `"total_movement"`: Manhattan distance (sum of |dx| + |dy|)
|
|
355
|
+
- `recent_periods`: Limit trajectory to last N periods (useful for long histories)
|
|
356
|
+
- `temporal_granularity`: "quarterly", "monthly", etc.
|
|
357
|
+
- `save_plot`: Save to file (default: False)
|
|
358
|
+
- `save_csv`: Save trajectory data to CSV (default: False)
|
|
359
|
+
- `plot_dir`: Output directory for plots
|
|
360
|
+
- `csv_dir`: Output directory for CSVs
|
|
361
|
+
- `close_fig`: Close figure after rendering (set True for Jupyter to avoid duplicates)
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Utility Functions
|
|
366
|
+
|
|
367
|
+
### Display Summaries
|
|
368
|
+
|
|
369
|
+
```python
|
|
370
|
+
from priorityx.utils.helpers import (
|
|
371
|
+
display_quadrant_summary,
|
|
372
|
+
display_transition_summary,
|
|
373
|
+
display_movement_summary
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
display_quadrant_summary(results_df, entity_name="Service")
|
|
377
|
+
display_transition_summary(transitions_df, entity_name="Service")
|
|
378
|
+
display_movement_summary(movement_df, entity_name="Service")
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Prints formatted summaries of analysis results.
|
|
382
|
+
|
|
383
|
+
### display_transition_drivers
|
|
384
|
+
|
|
385
|
+
```python
|
|
386
|
+
import priorityx as px
|
|
387
|
+
|
|
388
|
+
# Print to console
|
|
389
|
+
px.display_transition_drivers(analysis)
|
|
390
|
+
|
|
391
|
+
# Print and save to file
|
|
392
|
+
px.display_transition_drivers(
|
|
393
|
+
analysis,
|
|
394
|
+
save_txt=True,
|
|
395
|
+
txt_path="driver_analysis.txt",
|
|
396
|
+
txt_mode="a", # append (default) or "w" to overwrite
|
|
397
|
+
)
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Prints transition driver analysis in human-readable format.
|
|
401
|
+
|
|
402
|
+
**Parameters:**
|
|
403
|
+
|
|
404
|
+
- `analysis`: Output from extract_transition_drivers()
|
|
405
|
+
- `save_txt`: Save output to text file (default: False)
|
|
406
|
+
- `txt_path`: Path for text file (required if save_txt=True)
|
|
407
|
+
- `txt_mode`: File mode - "a" to append (default), "w" to overwrite
|