LeonardoMdSA commited on
Commit
b2715a4
·
1 Parent(s): 009d022

main.py and README.md final touches

Browse files
Dockerfile CHANGED
@@ -19,8 +19,7 @@ COPY requirements.txt requirements-dev.txt ./
19
 
20
  # Install dependencies
21
  RUN pip install --no-cache-dir --upgrade pip \
22
- && pip install --no-cache-dir -r requirements.txt \
23
- && pip install --no-cache-dir -r requirements-dev.txt
24
 
25
  # Copy the entire repo
26
  COPY . .
 
19
 
20
  # Install dependencies
21
  RUN pip install --no-cache-dir --upgrade pip \
22
+ && pip install --no-cache-dir -r requirements.txt
 
23
 
24
  # Copy the entire repo
25
  COPY . .
README.md CHANGED
@@ -9,81 +9,121 @@ pinned: false
9
  license: mit
10
  ---
11
 
12
- # Under Construction
13
-
14
- Building a production-ready ML inference service with post-deployment drift detection, governance, and alerting, demonstrating real MLOps practices rather than offline modeling.
15
-
16
- py -3.9 -m venv .venv
17
-
18
- .venv\Scripts\activate
19
-
20
- python -m pip install --upgrade pip
21
-
22
- pip install -r requirements.txt
23
-
24
- uvicorn app.main:app --reload
25
-
26
- # Repo Structure
27
-
28
- ml-inference-drift-service/
29
- Dockerfile
30
- LICENSE
31
- README.md
32
- requirements-dev.txt
33
- requirements.txt
34
- app/
35
- main.py
36
- api/
37
- background_drift.py
38
- dashboard_data.py
39
- routes.py
40
- schemas.py
41
- traffic_daemon.py
42
- core/
43
- config.py
44
- logging.py
45
- templates.py
46
- inference/
47
- predictor.py
48
- monitoring/
49
- data_loader.py
50
- drift.py
51
- governance.py
52
- static/
53
- styles.css
54
- templates/
55
- dashboard.html
56
- utils/
57
- alerts.py
58
- data/
59
- processed/
60
- credit_default_clean.csv
61
- current_data.csv
62
- production/
63
- predictions_log.csv
64
- raw/
65
- credit_default.csv
66
- database/
67
- logs/
68
- models/
69
- v1/
70
- features.json
71
- reference_data.csv
72
- v2/
73
- reports/
74
- evidently/
75
- drift_report.html
76
- drift_report.json
77
- scripts/
78
- prepare_data.py
79
- simulate_inference.py
80
- train.py
81
- tests/
82
- conftest.py
83
- integration/
84
- test_api.py
85
- test_governance.json
86
- test_governance.py
87
- test_run_drift.py
88
- unit/
89
- test_schemas.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  license: mit
10
  ---
11
 
12
+ # ML Inference Service with Drift Detection
13
+
14
+ ## Overview
15
+
16
+ This project is an end-to-end machine learning inference service with post-deployment drift detection and monitoring. It exposes a REST API for model predictions, continuously monitors data for drift using a rolling window, and provides a dashboard to visualize recent predictions and drift metrics.
17
+
18
+ The system is designed to be deployed locally via Docker or on Hugging Face Spaces, with minimal dependencies and a simple front-end dashboard.
19
+
20
+ ## Repository Structure
21
+
22
+ ```
23
+ ML Inference Service with Drift Detection/
24
+ ├─ app/
25
+ │ ├─ api/ # FastAPI routes, background tasks, and drift logic
26
+ │ ├─ inference/ # Model wrapper and predictor logic
27
+ │ ├─ monitoring/ # Drift checks, governance, and data loaders
28
+ │ ├─ templates/ # HTML templates for dashboard
29
+ │ ├─ utils/ # Utility scripts like validators and alert senders
30
+ │ ├─ core/ # Configurations, constants
31
+ │ └─ main.py # FastAPI entry point with lifespan tasks
32
+ ├─ data/
33
+ │ ├─ processed/ # Input CSVs for predictions
34
+ │ ├─ production/ # Predictions log CSV
35
+ ├─ models/ # Model artifacts and reference datasets
36
+ ├─ reports/ # Drift and dashboard JSON/HTML outputs
37
+ │ └─ evidently/ # Drift report JSON
38
+ ├─ tests/ # Unit and integration tests
39
+ ├─ Dockerfile # Container configuration
40
+ ├─ requirements.txt # Python dependencies
41
+ └─ README.md
42
+ ```
43
+
44
+ ## Installation (Local / venv)
45
+
46
+ 1. Clone the repository:
47
+
48
+ ```bash
49
+ git clone <repo_url>
50
+ cd ML Inference Service with Drift Detection
51
+ ```
52
+ 2. Create a virtual environment and activate it:
53
+
54
+ ```bash
55
+ py 3.9 -m venv .venv
56
+ source .venv/bin/activate # Linux/macOS
57
+ .\.venv\Scripts\activate # Windows
58
+ ```
59
+ 3. Install dependencies:
60
+
61
+ ```bash
62
+ python -m pip install --upgrade pip
63
+
64
+ pip install -r requirements-dev.txt
65
+ ```
66
+
67
+ ## Running the API Locally
68
+
69
+ 1. Start the FastAPI server:
70
+
71
+ ```bash
72
+ uvicorn app.main:app --reload
73
+ ```
74
+ 2. Open the dashboard:
75
+
76
+ * Localhost: [http://127.0.0.1:8000/](http://127.0.0.1:8000/)
77
+ 3. Predictions can be submitted via the API `/predict` endpoint (multipart CSV upload).
78
+
79
+ ## Testing
80
+
81
+ 1. Run all tests with pytest:
82
+
83
+ ```bash
84
+ pytest -v
85
+ ```
86
+ 2. Integration tests cover API endpoints, predictions, schema validation, and governance alerts.
87
+
88
+ ## How It Works (Logic Layers)
89
+
90
+ 1. **API Layer**: FastAPI routes handle `/predict`, `/dashboard`, `/health`, and `/run-drift`. Predictions are appended to `data/production/predictions_log.csv`.
91
+ 2. **Inference Layer**: `Predictor` wraps the model, loads features from `FEATURES_PATH`, and performs batch predictions.
92
+ 3. **Background Drift Loop**: Continuously monitors recent predictions (rolling window up to 5,000 rows), runs feature-level drift checks, and writes results to `reports/evidently/drift_report.json`.
93
+ 4. **Governance**: Checks metrics like PSI, F1, and regression accuracy against thresholds and logs alerts. Sends notifications via email or Slack (if configured).
94
+ 5. **Dashboard**: Reads `drift_report.json` and displays recent predictions and drift metrics via Plotly charts.
95
+
96
+ ## Technology Stack
97
+
98
+ * Python 3.9
99
+ * FastAPI
100
+ * Pandas / NumPy
101
+ * Joblib (for model serialization)
102
+ * Evidently (drift detection)
103
+ * Plotly (frontend charts)
104
+ * SQLite (optional, currently unused)
105
+ * Docker (for containerized deployment)
106
+ * Hugging Face Spaces (optional deployment)
107
+
108
+ ## Recommendations / Important Notes
109
+
110
+ * **CSV Rolling Window**: `MAX_DRIFT_ROWS` limits the predictions log to 5,000 rows. Older rows are removed to prevent oversized files.
111
+ * **Email Alerts**: SMTP server must be configured; otherwise, alert sending will fail gracefully.
112
+ * **HF Spaces**: The dashboard runs at `/` endpoint by default for compatibility.
113
+ * **Database**: `database/app.db` is currently unused and can be removed if desired.
114
+ * **UI File Upload**: The legacy CSV upload field in the dashboard can be removed if batch uploads are not needed.
115
+
116
+ ## References / Docs
117
+
118
+ * [FastAPI Documentation](https://fastapi.tiangolo.com/)
119
+ * [Evidently AI](https://evidentlyai.com/)
120
+ * [Plotly Charts](https://plotly.com/javascript/)
121
+
122
+ ## Contact / Author
123
+
124
+ * Darkray Accel
125
+ * GitHub: [https://github.com/LeonardoMdSACode](https://github.com/LeonardoMdSACode)
126
+
127
+ ## License
128
+
129
+ This project is licensed under the MIT License. See the LICENSE file for details.
app/api/routes.py CHANGED
@@ -97,6 +97,6 @@ async def predict_file(background_tasks: BackgroundTasks, file: UploadFile = Fil
97
  def health():
98
  return {"status": "ok"}
99
 
100
- @router.get("/dashboard")
101
  def dashboard(request: Request):
102
  return templates.TemplateResponse("dashboard.html", {"request": request})
 
97
  def health():
98
  return {"status": "ok"}
99
 
100
+ @router.get("/")
101
  def dashboard(request: Request):
102
  return templates.TemplateResponse("dashboard.html", {"request": request})
app/main.py CHANGED
@@ -132,7 +132,6 @@ from contextlib import asynccontextmanager
132
 
133
  @asynccontextmanager
134
  async def lifespan(app: FastAPI):
135
- init_db()
136
  tasks = [
137
  asyncio.create_task(traffic_loop()),
138
  asyncio.create_task(drift_loop(10))
 
132
 
133
  @asynccontextmanager
134
  async def lifespan(app: FastAPI):
 
135
  tasks = [
136
  asyncio.create_task(traffic_loop()),
137
  asyncio.create_task(drift_loop(10))
data/production/predictions_log.csv CHANGED
@@ -60,3 +60,35 @@ credit_limit,age,pay_delay_sep,pay_delay_aug,bill_amt_sep,bill_amt_aug,pay_amt_s
60
  200000.0,42,2,0,60000.0,58000.0,10000.0,9000.0,,0,0.4295814923706167,Low,v1,2026-01-15 16:25:09.547744+00:00
61
  50000.0,35,0,-1,12000.0,11000.0,3000.0,2500.0,,0,0.20681478861472152,Low,v1,2026-01-15 16:28:31.134432+00:00
62
  200000.0,42,2,0,60000.0,58000.0,10000.0,9000.0,,0,0.4295814923706167,Low,v1,2026-01-15 16:28:31.134432+00:00
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  200000.0,42,2,0,60000.0,58000.0,10000.0,9000.0,,0,0.4295814923706167,Low,v1,2026-01-15 16:25:09.547744+00:00
61
  50000.0,35,0,-1,12000.0,11000.0,3000.0,2500.0,,0,0.20681478861472152,Low,v1,2026-01-15 16:28:31.134432+00:00
62
  200000.0,42,2,0,60000.0,58000.0,10000.0,9000.0,,0,0.4295814923706167,Low,v1,2026-01-15 16:28:31.134432+00:00
63
+ 20000.0,33,0,0,20276.0,20134.0,1326.0,1326.0,0,0,0.24103223300443963,Low,v1,2026-01-15 16:34:59.730603+00:00
64
+ 80000.0,36,1,2,74328.0,75515.0,3000.0,0.0,1,0,0.41621943737111305,Low,v1,2026-01-15 16:35:02.719871+00:00
65
+ 170000.0,34,-1,-1,2435.0,0.0,0.0,0.0,0,0,0.11781894939497005,Low,v1,2026-01-15 16:35:02.719871+00:00
66
+ 200000.0,27,0,0,185143.0,188678.0,7000.0,7512.0,0,0,0.1469885132838565,Low,v1,2026-01-15 16:35:02.719871+00:00
67
+ 50000.0,37,5,4,19859.0,19268.0,0.0,0.0,0,1,0.9285871468011194,High,v1,2026-01-15 16:35:02.719871+00:00
68
+ 150000.0,29,-1,2,2599.0,1530.0,0.0,390.0,0,0,0.1753792670431056,Low,v1,2026-01-15 16:35:09.038969+00:00
69
+ 300000.0,26,0,0,293880.0,242669.0,11128.0,47009.0,0,0,0.06550496865854624,Low,v1,2026-01-15 16:35:14.486395+00:00
70
+ 500000.0,32,0,0,422713.0,406204.0,15000.0,16000.0,0,0,0.06593387266081487,Low,v1,2026-01-15 16:35:14.486395+00:00
71
+ 10000.0,43,0,0,4834.0,1803.0,1038.0,1054.0,1,0,0.2643145792109844,Low,v1,2026-01-15 16:35:14.486395+00:00
72
+ 50000.0,29,0,0,39124.0,40474.0,2000.0,1700.0,0,0,0.2225164441301266,Low,v1,2026-01-15 16:35:14.486395+00:00
73
+ 250000.0,31,-1,0,377399.0,78416.0,10045.0,3194.0,0,0,0.01920239774479085,Low,v1,2026-01-15 16:35:14.486395+00:00
74
+ 20000.0,38,0,0,16465.0,18470.0,3000.0,1473.0,0,0,0.248346177111492,Low,v1,2026-01-15 16:35:20.908878+00:00
75
+ 400000.0,48,0,0,112789.0,115910.0,5000.0,6624.0,0,0,0.16522251285591869,Low,v1,2026-01-15 16:35:29.336088+00:00
76
+ 50000.0,24,-1,-1,1572.0,1572.0,1572.0,1572.0,0,0,0.11850361149255435,Low,v1,2026-01-15 16:35:29.336088+00:00
77
+ 110000.0,29,0,0,107336.0,107195.0,5320.0,7845.0,0,0,0.17930034502932266,Low,v1,2026-01-15 16:35:32.875958+00:00
78
+ 360000.0,50,-1,-1,1858.0,0.0,0.0,0.0,0,0,0.11367438414700433,Low,v1,2026-01-15 16:35:32.875958+00:00
79
+ 290000.0,26,0,0,291861.0,254619.0,9596.0,7700.0,0,0,0.09692545030438433,Low,v1,2026-01-15 16:35:32.875958+00:00
80
+ 80000.0,43,0,0,78374.0,80472.0,4000.0,4000.0,0,0,0.22216256487741134,Low,v1,2026-01-15 16:35:32.875958+00:00
81
+ 50000.0,35,0,-1,12000.0,11000.0,3000.0,2500.0,,0,0.20681478861472152,Low,v1,2026-01-15 16:39:25.200768+00:00
82
+ 200000.0,42,2,0,60000.0,58000.0,10000.0,9000.0,,0,0.4295814923706167,Low,v1,2026-01-15 16:39:25.200768+00:00
83
+ 500000.0,26,0,0,16162.0,18581.0,3000.0,1335.0,0,0,0.15298331771846604,Low,v1,2026-01-15 16:39:41.490774+00:00
84
+ 260000.0,29,2,0,19006.0,19113.0,6005.0,1525.0,1,0,0.4303606392434953,Low,v1,2026-01-15 16:39:41.490774+00:00
85
+ 60000.0,33,-1,0,14932.0,12840.0,5000.0,10390.0,0,0,0.12818843100695615,Low,v1,2026-01-15 16:39:41.490774+00:00
86
+ 170000.0,54,-1,-1,186.0,116.0,116.0,0.0,0,0,0.14040673151255778,Low,v1,2026-01-15 16:39:49.465272+00:00
87
+ 200000.0,29,-1,-1,3655.0,3036.0,3084.0,3475.0,0,0,0.10386777515897552,Low,v1,2026-01-15 16:39:49.465272+00:00
88
+ 310000.0,53,-2,-2,1126.0,2603.0,2635.0,0.0,0,0,0.059470708342318636,Low,v1,2026-01-15 16:39:49.465272+00:00
89
+ 320000.0,29,-2,-2,5118.0,3743.0,6783.0,8063.0,0,0,0.041545173334793836,Low,v1,2026-01-15 16:39:56.188731+00:00
90
+ 50000.0,44,0,0,43828.0,40684.0,1947.0,1829.0,0,0,0.24317333333089378,Low,v1,2026-01-15 16:39:56.188731+00:00
91
+ 280000.0,36,-2,-2,2874.0,2874.0,2888.0,2888.0,0,0,0.050791529010223366,Low,v1,2026-01-15 16:39:56.188731+00:00
92
+ 280000.0,36,-2,-2,198.0,1979.0,1979.0,500.0,0,0,0.05293378034616363,Low,v1,2026-01-15 16:39:56.188731+00:00
93
+ 60000.0,40,0,0,28738.0,30216.0,4000.0,1010.0,1,0,0.23867262599538985,Low,v1,2026-01-15 16:39:56.188731+00:00
94
+ 400000.0,29,0,0,5074.0,4097.0,1097.0,3716.0,0,0,0.17183267351342854,Low,v1,2026-01-15 16:40:01.268559+00:00
database/app.db DELETED
Binary file (12.3 kB)
 
reports/evidently/drift_report.html CHANGED
The diff for this file is too large to render. See raw diff
 
reports/evidently/drift_report.json CHANGED
@@ -1,5 +1,5 @@
1
  {
2
- "n_rows": 57,
3
  "results": [
4
  {
5
  "row": 0,
@@ -342,44 +342,224 @@
342
  "prediction": "No Default",
343
  "probability": 0.2165,
344
  "risk_level": "Low"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
  }
346
  ],
347
  "drift": [
348
  {
349
  "column": "dataset",
350
- "score": 0.875
351
  },
352
  {
353
  "column": "age",
354
- "score": 0.23371009362458137
355
  },
356
  {
357
  "column": "bill_amt_aug",
358
- "score": 0.15297297061013115
359
  },
360
  {
361
  "column": "bill_amt_sep",
362
- "score": 0.15343706502680868
363
  },
364
  {
365
  "column": "credit_limit",
366
- "score": 0.31403434449489975
367
  },
368
  {
369
  "column": "pay_amt_aug",
370
- "score": 0.11849030297054779
371
  },
372
  {
373
  "column": "pay_amt_sep",
374
- "score": 0.12469609378058553
375
  },
376
  {
377
  "column": "pay_delay_aug",
378
- "score": 0.2553718164587327
379
  },
380
  {
381
  "column": "pay_delay_sep",
382
- "score": 0.07397843471719741
383
  }
384
  ]
385
  }
 
1
  {
2
+ "n_rows": 87,
3
  "results": [
4
  {
5
  "row": 0,
 
342
  "prediction": "No Default",
343
  "probability": 0.2165,
344
  "risk_level": "Low"
345
+ },
346
+ {
347
+ "row": 57,
348
+ "prediction": "No Default",
349
+ "probability": 0.2068,
350
+ "risk_level": "Low"
351
+ },
352
+ {
353
+ "row": 58,
354
+ "prediction": "No Default",
355
+ "probability": 0.4296,
356
+ "risk_level": "Low"
357
+ },
358
+ {
359
+ "row": 59,
360
+ "prediction": "No Default",
361
+ "probability": 0.2068,
362
+ "risk_level": "Low"
363
+ },
364
+ {
365
+ "row": 60,
366
+ "prediction": "No Default",
367
+ "probability": 0.4296,
368
+ "risk_level": "Low"
369
+ },
370
+ {
371
+ "row": 61,
372
+ "prediction": "No Default",
373
+ "probability": 0.241,
374
+ "risk_level": "Low"
375
+ },
376
+ {
377
+ "row": 62,
378
+ "prediction": "No Default",
379
+ "probability": 0.4162,
380
+ "risk_level": "Low"
381
+ },
382
+ {
383
+ "row": 63,
384
+ "prediction": "No Default",
385
+ "probability": 0.1178,
386
+ "risk_level": "Low"
387
+ },
388
+ {
389
+ "row": 64,
390
+ "prediction": "No Default",
391
+ "probability": 0.147,
392
+ "risk_level": "Low"
393
+ },
394
+ {
395
+ "row": 65,
396
+ "prediction": "Default",
397
+ "probability": 0.9286,
398
+ "risk_level": "High"
399
+ },
400
+ {
401
+ "row": 66,
402
+ "prediction": "No Default",
403
+ "probability": 0.1754,
404
+ "risk_level": "Low"
405
+ },
406
+ {
407
+ "row": 67,
408
+ "prediction": "No Default",
409
+ "probability": 0.0655,
410
+ "risk_level": "Low"
411
+ },
412
+ {
413
+ "row": 68,
414
+ "prediction": "No Default",
415
+ "probability": 0.0659,
416
+ "risk_level": "Low"
417
+ },
418
+ {
419
+ "row": 69,
420
+ "prediction": "No Default",
421
+ "probability": 0.2643,
422
+ "risk_level": "Low"
423
+ },
424
+ {
425
+ "row": 70,
426
+ "prediction": "No Default",
427
+ "probability": 0.2225,
428
+ "risk_level": "Low"
429
+ },
430
+ {
431
+ "row": 71,
432
+ "prediction": "No Default",
433
+ "probability": 0.0192,
434
+ "risk_level": "Low"
435
+ },
436
+ {
437
+ "row": 72,
438
+ "prediction": "No Default",
439
+ "probability": 0.2483,
440
+ "risk_level": "Low"
441
+ },
442
+ {
443
+ "row": 73,
444
+ "prediction": "No Default",
445
+ "probability": 0.1652,
446
+ "risk_level": "Low"
447
+ },
448
+ {
449
+ "row": 74,
450
+ "prediction": "No Default",
451
+ "probability": 0.1185,
452
+ "risk_level": "Low"
453
+ },
454
+ {
455
+ "row": 75,
456
+ "prediction": "No Default",
457
+ "probability": 0.1793,
458
+ "risk_level": "Low"
459
+ },
460
+ {
461
+ "row": 76,
462
+ "prediction": "No Default",
463
+ "probability": 0.1137,
464
+ "risk_level": "Low"
465
+ },
466
+ {
467
+ "row": 77,
468
+ "prediction": "No Default",
469
+ "probability": 0.0969,
470
+ "risk_level": "Low"
471
+ },
472
+ {
473
+ "row": 78,
474
+ "prediction": "No Default",
475
+ "probability": 0.2222,
476
+ "risk_level": "Low"
477
+ },
478
+ {
479
+ "row": 79,
480
+ "prediction": "No Default",
481
+ "probability": 0.2068,
482
+ "risk_level": "Low"
483
+ },
484
+ {
485
+ "row": 80,
486
+ "prediction": "No Default",
487
+ "probability": 0.4296,
488
+ "risk_level": "Low"
489
+ },
490
+ {
491
+ "row": 81,
492
+ "prediction": "No Default",
493
+ "probability": 0.153,
494
+ "risk_level": "Low"
495
+ },
496
+ {
497
+ "row": 82,
498
+ "prediction": "No Default",
499
+ "probability": 0.4304,
500
+ "risk_level": "Low"
501
+ },
502
+ {
503
+ "row": 83,
504
+ "prediction": "No Default",
505
+ "probability": 0.1282,
506
+ "risk_level": "Low"
507
+ },
508
+ {
509
+ "row": 84,
510
+ "prediction": "No Default",
511
+ "probability": 0.1404,
512
+ "risk_level": "Low"
513
+ },
514
+ {
515
+ "row": 85,
516
+ "prediction": "No Default",
517
+ "probability": 0.1039,
518
+ "risk_level": "Low"
519
+ },
520
+ {
521
+ "row": 86,
522
+ "prediction": "No Default",
523
+ "probability": 0.0595,
524
+ "risk_level": "Low"
525
  }
526
  ],
527
  "drift": [
528
  {
529
  "column": "dataset",
530
+ "score": 0.75
531
  },
532
  {
533
  "column": "age",
534
+ "score": 0.15611149622024934
535
  },
536
  {
537
  "column": "bill_amt_aug",
538
+ "score": 0.12250072824204197
539
  },
540
  {
541
  "column": "bill_amt_sep",
542
+ "score": 0.18763213901625655
543
  },
544
  {
545
  "column": "credit_limit",
546
+ "score": 0.1713948991364952
547
  },
548
  {
549
  "column": "pay_amt_aug",
550
+ "score": 0.08246967085476054
551
  },
552
  {
553
  "column": "pay_amt_sep",
554
+ "score": 0.11861811820004925
555
  },
556
  {
557
  "column": "pay_delay_aug",
558
+ "score": 0.21519799744256923
559
  },
560
  {
561
  "column": "pay_delay_sep",
562
+ "score": 0.07734517509505544
563
  }
564
  ]
565
  }