priorityx 0.2.1__tar.gz → 0.2.3__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.2.1 → priorityx-0.2.3}/PKG-INFO +2 -1
- {priorityx-0.2.1 → priorityx-0.2.3}/README.md +1 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/docs/api-reference.md +14 -7
- {priorityx-0.2.1 → priorityx-0.2.3}/docs/quickstart.md +6 -1
- {priorityx-0.2.1 → priorityx-0.2.3}/examples/README.md +3 -4
- {priorityx-0.2.1 → priorityx-0.2.3}/examples/bugs/bugs_monitoring.py +8 -8
- {priorityx-0.2.1 → priorityx-0.2.3}/examples/incidents/incident_monitoring.py +10 -12
- {priorityx-0.2.1 → priorityx-0.2.3}/examples/violations/violations_monitoring.py +10 -19
- {priorityx-0.2.1 → priorityx-0.2.3}/pyproject.toml +3 -1
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/__init__.py +1 -1
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/core/glmm.py +17 -17
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/tracking/drivers.py +273 -212
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/tracking/transitions.py +28 -1
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/utils/helpers.py +3 -3
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/viz/matrix.py +22 -7
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/viz/timeline.py +21 -6
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/viz/trajectory.py +27 -12
- priorityx-0.2.3/tests/test_drivers.py +243 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/uv.lock +577 -345
- priorityx-0.2.1/src/priorityx/viz/__init__.py +0 -0
- priorityx-0.2.1/tests/test_drivers.py +0 -118
- {priorityx-0.2.1 → priorityx-0.2.3}/.github/workflows/release.yml +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/.github/workflows/test.yml +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/.gitignore +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/LICENSE +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/Makefile +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/docs/methodology.md +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/docs/priority_classification.md +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/scripts/version.py +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/core/__init__.py +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/core/filters.py +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/core/quadrants.py +0 -0
- {priorityx-0.2.1/src/priorityx/drivers → priorityx-0.2.3/src/priorityx/tracking}/__init__.py +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/src/priorityx/tracking/movement.py +0 -0
- {priorityx-0.2.1/src/priorityx/tracking → priorityx-0.2.3/src/priorityx/utils}/__init__.py +0 -0
- {priorityx-0.2.1/src/priorityx/utils → priorityx-0.2.3/src/priorityx/viz}/__init__.py +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/tests/test_glmm.py +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/tests/test_quadrants.py +0 -0
- {priorityx-0.2.1 → priorityx-0.2.3}/tests/test_transitions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: priorityx
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
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
|
|
@@ -74,6 +74,7 @@ plot_priority_matrix(results, entity_name="Service", save_plot=True)
|
|
|
74
74
|
- GLMM-based priority matrix (Q1–Q4) with entity-level intercept/slope insights
|
|
75
75
|
- Priority-based transition timeline (Crisis / Investigate / Monitor / Low) with spike markers (`*X`, `*Y`, `*XY`)
|
|
76
76
|
- Cumulative movement tracking and trajectory visualizations
|
|
77
|
+
- Transition driver analysis that surfaces top subcategories causing quadrant shifts with spike summaries
|
|
77
78
|
- Deterministic seeding option for reproducible GLMM runs (set `PRIORITYX_GLMM_SEED`)
|
|
78
79
|
|
|
79
80
|
## Use Cases
|
|
@@ -46,6 +46,7 @@ plot_priority_matrix(results, entity_name="Service", save_plot=True)
|
|
|
46
46
|
- GLMM-based priority matrix (Q1–Q4) with entity-level intercept/slope insights
|
|
47
47
|
- Priority-based transition timeline (Crisis / Investigate / Monitor / Low) with spike markers (`*X`, `*Y`, `*XY`)
|
|
48
48
|
- Cumulative movement tracking and trajectory visualizations
|
|
49
|
+
- Transition driver analysis that surfaces top subcategories causing quadrant shifts with spike summaries
|
|
49
50
|
- Deterministic seeding option for reproducible GLMM runs (set `PRIORITYX_GLMM_SEED`)
|
|
50
51
|
|
|
51
52
|
## Use Cases
|
|
@@ -100,8 +100,9 @@ analysis = extract_transition_drivers(
|
|
|
100
100
|
quarter_to="2024-Q3",
|
|
101
101
|
entity_col="service",
|
|
102
102
|
timestamp_col="date",
|
|
103
|
-
subcategory_cols=["type", "category"], # Optional
|
|
104
|
-
|
|
103
|
+
subcategory_cols=["type", "category"], # Optional override; auto-detected if omitted
|
|
104
|
+
top_n_subcategories=5,
|
|
105
|
+
min_subcategory_delta=2,
|
|
105
106
|
)
|
|
106
107
|
```
|
|
107
108
|
|
|
@@ -115,11 +116,18 @@ Analyzes root causes of a quadrant transition.
|
|
|
115
116
|
- `quarter_to`: Ending quarter (e.g., "2024-Q3")
|
|
116
117
|
- `entity_col`: Entity column name
|
|
117
118
|
- `timestamp_col`: Timestamp column name
|
|
118
|
-
- `subcategory_cols`: Optional list of subcategory columns
|
|
119
|
-
- `
|
|
119
|
+
- `subcategory_cols`: Optional list of subcategory columns (auto-detected when omitted)
|
|
120
|
+
- `top_n_subcategories`: Limit of subcategory drivers (default: 3)
|
|
121
|
+
- `min_subcategory_delta`: Minimum delta required for subcategory inclusion (default: 1)
|
|
120
122
|
|
|
121
123
|
**Returns:**
|
|
122
|
-
- Dictionary with
|
|
124
|
+
- Dictionary with:
|
|
125
|
+
- `transition`: includes risk-level change and `is_concerning` flag
|
|
126
|
+
- `magnitude`: cumulative deltas plus period-specific weekly averages and complaint counts
|
|
127
|
+
- `spike_drivers`: summary notes aligned with spike indicators (`*X`, `*Y`, `*XY`)
|
|
128
|
+
- `subcategory_drivers`: per-column driver lists obeying the provided knobs
|
|
129
|
+
- `priority`: priority tier, trigger reason, spike axis
|
|
130
|
+
- `meta`: diagnostic flags (e.g., whether subcategory columns were auto-detected)
|
|
123
131
|
|
|
124
132
|
### classify_priority
|
|
125
133
|
|
|
@@ -222,11 +230,10 @@ Prints formatted summaries of analysis results.
|
|
|
222
230
|
```python
|
|
223
231
|
from priorityx.tracking.drivers import display_transition_drivers
|
|
224
232
|
|
|
225
|
-
display_transition_drivers(analysis
|
|
233
|
+
display_transition_drivers(analysis)
|
|
226
234
|
```
|
|
227
235
|
|
|
228
236
|
Prints transition driver analysis in human-readable format.
|
|
229
237
|
|
|
230
238
|
**Parameters:**
|
|
231
239
|
- `analysis`: Output from extract_transition_drivers()
|
|
232
|
-
- `show_keywords`: Whether to show keyword analysis (default: False)
|
|
@@ -62,9 +62,14 @@ if not transitions.empty:
|
|
|
62
62
|
quarter_from=first_transition["from_quarter"],
|
|
63
63
|
quarter_to=first_transition["transition_quarter"],
|
|
64
64
|
entity_col="service",
|
|
65
|
-
timestamp_col="date"
|
|
65
|
+
timestamp_col="date",
|
|
66
|
+
top_n_subcategories=5,
|
|
67
|
+
min_subcategory_delta=2
|
|
66
68
|
)
|
|
67
69
|
display_transition_drivers(analysis)
|
|
70
|
+
|
|
71
|
+
# subcategory columns (e.g., severity/product/topic) are auto-detected
|
|
72
|
+
# when not provided; pass subcategory_cols=[...] to override.
|
|
68
73
|
```
|
|
69
74
|
|
|
70
75
|
## Data Requirements
|
|
@@ -16,18 +16,17 @@ pip install git+https://github.com/okkymabruri/priorityx.git
|
|
|
16
16
|
|
|
17
17
|
## Running Examples
|
|
18
18
|
|
|
19
|
-
**IT Incidents** (1,621 incidents, 10 services)
|
|
19
|
+
**IT Incidents** (1,621 incidents, 10 services) — pulls CSV from GitHub raw
|
|
20
20
|
```bash
|
|
21
21
|
python examples/incidents/incident_monitoring.py
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
**Compliance Violations** (495 violations, 10 departments)
|
|
24
|
+
**Compliance Violations** (495 violations, 10 departments) — synthetic dataset
|
|
25
25
|
```bash
|
|
26
26
|
python examples/violations/violations_monitoring.py
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
**Software Bugs** (576 bugs, 10 components)
|
|
30
|
-
Pre-generated CSV only. Use as input for your own analysis.
|
|
29
|
+
**Software Bugs** (576 bugs, 10 components) — pulls CSV from GitHub raw
|
|
31
30
|
|
|
32
31
|
## Output
|
|
33
32
|
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# %%
|
|
2
|
+
# software bug tracking example (data pulled from GitHub raw)
|
|
3
3
|
import pandas as pd
|
|
4
4
|
|
|
5
5
|
from priorityx.core.glmm import fit_priority_matrix
|
|
6
6
|
from priorityx.viz.matrix import plot_priority_matrix
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
df = pd.read_csv("examples/bugs/bugs.csv")
|
|
8
|
+
RAW_DATA_URL = "https://raw.githubusercontent.com/okkymabruri/priorityx/main/examples/bugs/bugs.csv"
|
|
10
9
|
|
|
11
|
-
#
|
|
12
|
-
df
|
|
10
|
+
# load bug reports from GitHub raw
|
|
11
|
+
df = pd.read_csv(RAW_DATA_URL, parse_dates=["reported_date"])
|
|
12
|
+
df["date"] = df["reported_date"]
|
|
13
13
|
|
|
14
14
|
# fit priority matrix
|
|
15
15
|
temporal_granularity = "quarterly"
|
|
16
16
|
entity_name = "Component"
|
|
17
|
+
|
|
17
18
|
results, stats = fit_priority_matrix(
|
|
18
19
|
df,
|
|
19
20
|
entity_col="component",
|
|
@@ -33,9 +34,8 @@ plot_priority_matrix(
|
|
|
33
34
|
show_quadrant_labels=True,
|
|
34
35
|
save_plot=True,
|
|
35
36
|
save_csv=True,
|
|
36
|
-
output_dir="examples/bugs/plot",
|
|
37
37
|
)
|
|
38
38
|
print()
|
|
39
|
-
print("Outputs saved to
|
|
39
|
+
print("Outputs saved to plot/ and results/ (under the current working directory)")
|
|
40
40
|
|
|
41
41
|
# %%
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# %%
|
|
2
|
+
# it incident monitoring example (data pulled from GitHub raw)
|
|
2
3
|
|
|
3
4
|
import pandas as pd
|
|
4
5
|
|
|
6
|
+
RAW_DATA_URL = "https://raw.githubusercontent.com/okkymabruri/priorityx/main/examples/incidents/incidents.csv"
|
|
7
|
+
|
|
5
8
|
from priorityx.core.glmm import fit_priority_matrix
|
|
6
9
|
from priorityx.tracking.movement import track_cumulative_movement
|
|
7
10
|
from priorityx.tracking.transitions import extract_transitions
|
|
@@ -18,9 +21,9 @@ from priorityx.utils.helpers import (
|
|
|
18
21
|
save_dataframe_to_csv,
|
|
19
22
|
)
|
|
20
23
|
|
|
21
|
-
# load data
|
|
22
|
-
df = pd.read_csv("
|
|
23
|
-
|
|
24
|
+
# load data from GitHub raw
|
|
25
|
+
df = pd.read_csv(RAW_DATA_URL, parse_dates=["date"])
|
|
26
|
+
print("Loaded incidents from GitHub raw URL")
|
|
24
27
|
|
|
25
28
|
print(f"Loaded {len(df)} incidents for {df['service'].nunique()} services")
|
|
26
29
|
print(f"Date range: {df['date'].min()} to {df['date'].max()}")
|
|
@@ -52,7 +55,6 @@ plot_priority_matrix(
|
|
|
52
55
|
show_quadrant_labels=True,
|
|
53
56
|
save_plot=True,
|
|
54
57
|
save_csv=True,
|
|
55
|
-
output_dir="examples/incidents/plot",
|
|
56
58
|
)
|
|
57
59
|
|
|
58
60
|
# track movement
|
|
@@ -78,7 +80,6 @@ movement_path = save_dataframe_to_csv(
|
|
|
78
80
|
artifact="trajectories",
|
|
79
81
|
entity_name=entity_name,
|
|
80
82
|
temporal_granularity=temporal_granularity,
|
|
81
|
-
output_dir="examples/incidents/results",
|
|
82
83
|
)
|
|
83
84
|
print(f"Movement CSV saved: {movement_path}")
|
|
84
85
|
|
|
@@ -89,8 +90,6 @@ plot_entity_trajectories(
|
|
|
89
90
|
max_entities=5,
|
|
90
91
|
save_plot=True,
|
|
91
92
|
save_csv=True,
|
|
92
|
-
output_dir="examples/incidents/plot",
|
|
93
|
-
results_dir="examples/incidents/results",
|
|
94
93
|
)
|
|
95
94
|
|
|
96
95
|
# detect transitions
|
|
@@ -104,7 +103,6 @@ plot_transition_timeline(
|
|
|
104
103
|
entity_name=entity_name,
|
|
105
104
|
save_plot=True,
|
|
106
105
|
save_csv=True,
|
|
107
|
-
output_dir="examples/incidents/plot",
|
|
108
106
|
movement_df=movement,
|
|
109
107
|
)
|
|
110
108
|
|
|
@@ -139,13 +137,13 @@ if len(critical_transitions) > 0:
|
|
|
139
137
|
quarter_to=trans["transition_quarter"],
|
|
140
138
|
entity_col="service",
|
|
141
139
|
timestamp_col="date",
|
|
140
|
+
top_n_subcategories=5,
|
|
141
|
+
min_subcategory_delta=2,
|
|
142
142
|
)
|
|
143
143
|
|
|
144
144
|
display_transition_drivers(driver_analysis)
|
|
145
145
|
|
|
146
146
|
print()
|
|
147
|
-
print(
|
|
148
|
-
"Analysis complete. Check examples/incidents/plot/ and examples/incidents/results/"
|
|
149
|
-
)
|
|
147
|
+
print("Analysis complete. Check plot/ and results/ in the current working directory.")
|
|
150
148
|
|
|
151
149
|
# %%
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# %%
|
|
2
2
|
import random
|
|
3
3
|
from datetime import datetime, timedelta
|
|
4
4
|
|
|
@@ -12,6 +12,7 @@ from priorityx.viz.timeline import plot_transition_timeline
|
|
|
12
12
|
from priorityx.utils.helpers import (
|
|
13
13
|
display_quadrant_summary,
|
|
14
14
|
display_transition_summary,
|
|
15
|
+
save_dataframe_to_csv,
|
|
15
16
|
)
|
|
16
17
|
|
|
17
18
|
random.seed(42)
|
|
@@ -63,11 +64,6 @@ df = pd.DataFrame(data)
|
|
|
63
64
|
temporal_granularity = "quarterly"
|
|
64
65
|
entity_name = "Department"
|
|
65
66
|
|
|
66
|
-
PLOT_DIR = "examples/violations/plot"
|
|
67
|
-
RESULTS_DIR = "examples/violations/results"
|
|
68
|
-
os.makedirs(PLOT_DIR, exist_ok=True)
|
|
69
|
-
os.makedirs(RESULTS_DIR, exist_ok=True)
|
|
70
|
-
|
|
71
67
|
results, stats = fit_priority_matrix(
|
|
72
68
|
df,
|
|
73
69
|
entity_col="department",
|
|
@@ -86,7 +82,6 @@ plot_priority_matrix(
|
|
|
86
82
|
show_quadrant_labels=True,
|
|
87
83
|
save_plot=True,
|
|
88
84
|
save_csv=True,
|
|
89
|
-
output_dir=PLOT_DIR,
|
|
90
85
|
)
|
|
91
86
|
|
|
92
87
|
movement, meta = track_cumulative_movement(
|
|
@@ -98,17 +93,12 @@ movement, meta = track_cumulative_movement(
|
|
|
98
93
|
temporal_granularity=temporal_granularity,
|
|
99
94
|
)
|
|
100
95
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}.get(temporal_granularity, "Q")
|
|
107
|
-
movement_path = (
|
|
108
|
-
f"{RESULTS_DIR}/trajectories-{entity_name.lower()}-"
|
|
109
|
-
f"{granularity_suffix}-{timestamp}.csv"
|
|
96
|
+
movement_path = save_dataframe_to_csv(
|
|
97
|
+
movement,
|
|
98
|
+
artifact="trajectories",
|
|
99
|
+
entity_name=entity_name,
|
|
100
|
+
temporal_granularity=temporal_granularity,
|
|
110
101
|
)
|
|
111
|
-
movement.to_csv(movement_path, index=False)
|
|
112
102
|
print(f"Movement CSV saved: {movement_path}")
|
|
113
103
|
transitions = extract_transitions(movement, focus_risk_increasing=True)
|
|
114
104
|
|
|
@@ -120,9 +110,10 @@ plot_transition_timeline(
|
|
|
120
110
|
entity_name=entity_name,
|
|
121
111
|
save_plot=True,
|
|
122
112
|
save_csv=True,
|
|
123
|
-
output_dir=PLOT_DIR,
|
|
124
113
|
movement_df=movement,
|
|
125
114
|
)
|
|
126
115
|
|
|
127
116
|
print()
|
|
128
|
-
print("Outputs saved to
|
|
117
|
+
print("Outputs saved to plot/ and results/ in the current working directory.")
|
|
118
|
+
|
|
119
|
+
# %%
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "priorityx"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.3"
|
|
4
4
|
description = "Entity prioritization and escalation detection using GLMM statistical models"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Okky Mabruri", email = "okkymbrur@gmail.com"}
|
|
@@ -39,6 +39,8 @@ build-backend = "hatchling.build"
|
|
|
39
39
|
[dependency-groups]
|
|
40
40
|
dev = [
|
|
41
41
|
"jupyter>=1.1.1",
|
|
42
|
+
"jupytext>=1.18.1",
|
|
43
|
+
"mssql-python>=1.0.0",
|
|
42
44
|
"polars>=1.35.1",
|
|
43
45
|
"priorityx",
|
|
44
46
|
"pyarrow>=22.0.0",
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from typing import Dict, Literal, Optional, Tuple
|
|
4
4
|
from datetime import timedelta
|
|
5
5
|
import os
|
|
6
|
+
import warnings
|
|
6
7
|
import numpy as np
|
|
7
8
|
|
|
8
9
|
import pandas as pd
|
|
@@ -71,6 +72,7 @@ def fit_priority_matrix(
|
|
|
71
72
|
temporal_granularity: Literal["yearly", "quarterly", "semiannual"] = "yearly",
|
|
72
73
|
vcp_p: float = DEFAULT_VCP_P,
|
|
73
74
|
fe_p: float = DEFAULT_FE_P,
|
|
75
|
+
verbose: bool = False,
|
|
74
76
|
) -> Tuple[pd.DataFrame, Dict]:
|
|
75
77
|
"""
|
|
76
78
|
Fit Poisson GLMM to classify entities into priority quadrants.
|
|
@@ -87,6 +89,7 @@ def fit_priority_matrix(
|
|
|
87
89
|
temporal_granularity: Time aggregation level
|
|
88
90
|
vcp_p: Random effects prior scale
|
|
89
91
|
fe_p: Fixed effects prior scale
|
|
92
|
+
verbose: When True, print diagnostic logs; otherwise stay quiet
|
|
90
93
|
|
|
91
94
|
Returns:
|
|
92
95
|
Tuple of (results DataFrame, statistics dict)
|
|
@@ -94,6 +97,11 @@ def fit_priority_matrix(
|
|
|
94
97
|
# create copy to avoid modifying original
|
|
95
98
|
df = df.copy()
|
|
96
99
|
|
|
100
|
+
if not verbose:
|
|
101
|
+
warnings.filterwarnings(
|
|
102
|
+
"ignore", message="VB fitting did not converge", category=UserWarning
|
|
103
|
+
)
|
|
104
|
+
|
|
97
105
|
# ensure timestamp column is datetime
|
|
98
106
|
df[timestamp_col] = pd.to_datetime(df[timestamp_col])
|
|
99
107
|
|
|
@@ -129,7 +137,7 @@ def fit_priority_matrix(
|
|
|
129
137
|
df = df[df[entity_col].isin(valid_entities)]
|
|
130
138
|
n_after_volume_filter = df[entity_col].nunique()
|
|
131
139
|
n_filtered_volume = n_before_volume_filter - n_after_volume_filter
|
|
132
|
-
if n_filtered_volume > 0:
|
|
140
|
+
if verbose and n_filtered_volume > 0:
|
|
133
141
|
print(
|
|
134
142
|
f" Filtered {n_filtered_volume} entities (<{min_total_count} total count)"
|
|
135
143
|
)
|
|
@@ -308,22 +316,14 @@ def fit_priority_matrix(
|
|
|
308
316
|
fe_p=fe_p,
|
|
309
317
|
)
|
|
310
318
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
# Print first entity's data
|
|
321
|
-
first_entity = df_prepared[entity_col].iloc[0]
|
|
322
|
-
entity_data = df_prepared[df_prepared[entity_col] == first_entity]
|
|
323
|
-
print(f"\n[GLMM DEBUG] First entity '{first_entity}' data:")
|
|
324
|
-
debug_cols = [c for c in ["year", "quarter", "semester", entity_col, "count", "time"] if c in entity_data.columns]
|
|
325
|
-
print(entity_data[debug_cols].head(10).to_string())
|
|
326
|
-
|
|
319
|
+
if verbose:
|
|
320
|
+
print(f"\n[GLMM DEBUG] Formula: {formula}")
|
|
321
|
+
print(f"[GLMM DEBUG] N observations: {len(df_prepared)}")
|
|
322
|
+
print(f"[GLMM DEBUG] N entities: {df_prepared[entity_col].nunique()}")
|
|
323
|
+
print(f"[GLMM DEBUG] Year range: {df_prepared['year'].min()}-{df_prepared['year'].max()}")
|
|
324
|
+
print(f"[GLMM DEBUG] Time variable: mean={df_prepared['time'].mean():.6f}, std={df_prepared['time'].std():.6f}")
|
|
325
|
+
print(f"[GLMM DEBUG] Entity sample: {df_prepared[entity_col].unique()[:5].tolist()}")
|
|
326
|
+
print(f"[GLMM DEBUG] vcp_p={vcp_p}, fe_p={fe_p}")
|
|
327
327
|
# use variational bayes (returns posterior mean)
|
|
328
328
|
# avoids boundary convergence issues vs map
|
|
329
329
|
_apply_random_seed()
|