Skip to main content

mlpreflight

Run this before you train your classifier.

mlpreflight answers one question: is my classification dataset ready to model, and if not, exactly what should I fix?

It inspects your data before any model is trained and reports, column by column, what is risky, why it matters and what to do about it. It is not an AutoML tool, a modelling framework or a model trainer. It runs before those, and tells you whether the numbers they produce can be trusted.

  • One call, no setup. inspect(df, target="churn") - no schema objects, no configuration.
  • Column-level answers. Every finding names the exact columns responsible and the statistic that triggered it.
  • A decision, not just statistics. A 0-100 readiness score, a Critical / Warning / Passed breakdown, and a KEEP / INVESTIGATE / REMOVE list of features.
  • Honest about what it did not check. A check that could not run is reported as Skipped, never as Passed.
  • Lightweight. Depends only on pandas and numpy.

Installation

pip install mlpreflight

Requires Python 3.10 or newer and pandas 2.0 or newer. Tested on Python 3.12 and 3.13 with pandas 2.3 and 3.0.

Quickstart

1. Inspect a whole dataset

import pandas as pd
import mlpreflight as pf

df = pd.read_csv("churn.csv")

report = pf.inspect(df, target="Churn")
report.summary()

Tip: import mlpreflight as pf avoids shadowing Python's built-in inspect module. from mlpreflight import inspect also works.

Real output on a synthetic telecom churn dataset (8,000 rows, with one planted leaky column):

+============================================================+
|                     MLPREFLIGHT REPORT                     |
+============================================================+
| Dataset             8,000 x 16                             |
| MODEL READINESS     55 / 100                               |
|                                                            |
| Critical            1                                      |
| Warnings            3                                      |
| Passed              7                                      |
| Skipped             6  (not assessed)                      |
+------------------------------------------------------------+
| TARGET                                                     |
|                                                            |
| Target              Churn                                  |
| Classes             2                                      |
|   class 0           69.9%                                  |
|   class 1           30.1%                                  |
+------------------------------------------------------------+
| FEATURE RISK                                               |
|                                                            |
| [!] Potential target leakage                               |
|    -> CancellationTicketID                                 |
| [~] High-cardinality categorical features                  |
|    -> CancellationTicketID                                 |
| [~] Identifier-like columns used as features               |
|    -> customerID                                           |
+------------------------------------------------------------+
| TARGET PATTERNS                                            |
|                                                            |
| - class 1 averages 21% lower `tenure` than class 0         |
| - class 1 averages 10% higher `MonthlyCharges` than        |
| class 0                                                    |
+------------------------------------------------------------+
| RECOMMENDED FEATURES                                       |
|                                                            |
| KEEP                13 features                            |
| INVESTIGATE         customerID                             |
| REMOVE              CancellationTicketID                   |
+------------------------------------------------------------+
| RECOMMENDATION                                             |
|                                                            |
| DO NOT TRAIN FINAL MODEL YET                               |
+============================================================+

(Shortened here; the real report also includes data-quality details, recommendations per finding and any assumptions made.)

2. Check the quality of your train/test split

Pass your held-out set to also check split integrity and train/test compatibility:

from sklearn.model_selection import train_test_split

train, test = train_test_split(df, test_size=0.2, random_state=1, stratify=df["Churn"])

report = pf.inspect(
    train,
    target="Churn",
    test=test,
    time_col="signup_date",     # optional: enables temporal leakage checks
    entity_col="customerID",    # optional: enables entity-overlap checks
)
report.summary()

Without test=, the six split-dependent checks are reported as Skipped, so a dataset is never shown as "clean" for checks that did not run.

3. Drill down

report.details("critical")             # full what / why / action for every Critical finding
report.explain("CancellationTicketID")  # everything wrong with one column, with statistics
report.recommended_features()           # {"keep": [...], "investigate": [...], "remove": [...]}
report.column_report()                  # column -> list of issues, as a dict
report.score_breakdown()                # every point deducted from the score

4. Export

report.to_html("preflight_report.html")   # standalone file, no external assets
report.to_json("preflight_report.json")   # machine-readable

5. Use it as a CI/CD gate

report = pf.inspect(train, target="Churn", test=test)
report.to_json("preflight_report.json")

if report.has_blocking_issues:      # True if any Critical finding exists
    raise SystemExit("Preflight failed - see preflight_report.json")

API

mlpreflight.inspect(
    train,               # DataFrame, including the target column
    target,              # name of the target column
    test=None,           # optional held-out DataFrame (enables split checks)
    time_col=None,       # optional event-time column (enables temporal leakage check)
    entity_col=None,     # optional entity column, e.g. customer_id (enables entity-overlap check)
) -> Report

If time_col or entity_col is not given, the library tries to infer it when exactly one obvious candidate exists. Any such guess is listed under ASSUMPTIONS MADE in the report, and findings that depend on it carry reduced confidence. Pass them explicitly when you know them.

Report attributes and methods

Member What it gives you
score Model readiness score, 0-100
verdict Plain-language decision, e.g. DO NOT TRAIN FINAL MODEL YET
critical, warnings, passed, skipped Lists of findings by outcome
has_blocking_issues True if any Critical finding exists
summary() Console summary
details(severity=None) Full findings, optionally for one severity
explain(column) Drill-down for one column
recommended_features() KEEP / INVESTIGATE / REMOVE lists
target_patterns() Plain-language relationships between top features and the target
column_report() Column -> issues mapping
score_breakdown() Itemised deductions behind the score
to_html(path), to_json(path), to_dict() Exports

Every finding has the same shape: check_id, category, title, severity, what, why, recommendation, confidence, and per-column evidence.

What it checks

Category Check Flagged when
Dataset & Target Health Missing values A feature is >40% missing (Critical above 80%)
Duplicate rows Any fully duplicated rows (Critical above 5%)
Constant columns One value in >99% of rows
Target quality Target has missing values or fewer than 2 classes (Critical)
Sample size Fewer than 50 rows per feature (Critical below 10)
Leakage & Split Integrity Target leakage Feature has rank correlation >= 0.95 with the target (Critical); 0.80-0.95 is a Warning
Identifier columns Near-unique or identifier-named columns used as features
Train/test row overlap Identical rows in both sets (Critical above 1%)
Entity overlap Same entity in train and test (Critical above 5%)
Temporal leakage Training rows dated after the earliest test row (Critical above 5%)
Train/Test Compatibility Numeric shift Population Stability Index > 0.1 (Critical above 0.25)
Unseen categories Categories in test that never appear in train
Target shift Class proportions differ by 5 points or more
Feature Risk High cardinality A categorical feature has more than 50 distinct values
Redundancy Numeric feature pairs with absolute correlation > 0.95
Classification Risk Class imbalance Majority:minority ratio of 3:1 or more (Critical above 20:1 or fewer than 50 minority rows)
Target Patterns Directional summaries Informational only; never affects the score

Split-dependent checks (row overlap, entity overlap, temporal leakage, numeric shift, unseen categories, target shift) need test=.

How the score works

The score is deterministic and can be reconstructed by hand:

  • It starts at 100.
  • Each Critical finding deducts 18 x weight x confidence points; each Warning deducts 6 x weight x confidence.
  • Any Critical finding caps the score at 60; warnings alone cap it at 90.
  • report.score_breakdown() lists every deduction.

Verdicts: any Critical -> DO NOT TRAIN FINAL MODEL YET; score 90+ -> READY TO TRAIN; otherwise TRAIN WITH CAUTION - REVIEW WARNINGS.

Known limitations (v0.1)

This is an early release. Please read these before relying on it:

  • Leakage detection is statistical. It catches the symptom of leakage (a feature that is suspiciously predictive). It cannot know whether a feature will actually be available at prediction time. A leak that is not statistically obvious will not be found.
  • Categorical association is approximate. Non-numeric columns are encoded as category codes before a rank correlation is computed, so for nominal categoricals with many levels the strength can be under- or over-estimated.
  • A random split will trigger the temporal check. If you split with train_test_split, some training rows will naturally be dated after some test rows. That is expected; the flag is only a real problem if you intended a chronological split.
  • Thresholds are fixed defaults and not yet configurable. They have not been validated across a wide range of real datasets, so expect some false positives and false negatives.
  • Missing-value advice is generic. It does not yet check whether a column's missingness is itself associated with the target (in which case adding an "is missing" indicator would leak the target).
  • Target patterns support binary targets only. Other checks are designed for classification in general, but multi-class targets are less tested.
  • Tested on Python 3.12 and 3.13 with pandas 2.3 and 3.0 only. Other versions are untested.

Contributing

Issues and pull requests are welcome at https://github.com/AvinAshok2050/mlpreflight.git.

git clone https://github.com/AvinAshok2050/mlpreflight.git
cd mlpreflight
pip install -e ".[dev]"
python -m pytest tests/ -q

Each check is a small function that takes the dataset context and returns findings; adding one means adding one function and registering it.

License

MIT. See LICENSE.

Copyright (c) 2026 Avin Ashok

Metadata

Release files for mlpreflight 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mlpreflight 0.1.0
File Size Uploaded Provenance
mlpreflight-0.1.0.tar.gz 31.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for mlpreflight 0.1.0
File Interpreter ABI Platform
mlpreflight-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 62.5 kB

Release files / mlpreflight-0.1.0.tar.gz

Download URL mlpreflight-0.1.0.tar.gz
Size 31.8 kB
Tags Source
SHA-256 checksum
How to use checksums
9899cf7982ec746d823e6f84984387b21296807fe8d2eee9e95c4b25524b4e03
BLAKE2b-256 checksum
How to use checksums
49b2a5dab8a8a096f232073528d153c43338b91039934bc0c95b22b2bf2d1ad9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release files / mlpreflight-0.1.0-py3-none-any.whl

Download URL mlpreflight-0.1.0-py3-none-any.whl
Size 30.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7a5aca157e685cfa40b0fb1c99adb12bd6a3239a21df0cc6a5d751a227bbd530
BLAKE2b-256 checksum
How to use checksums
4703edd98c5f53f5d8b3e0fa3f2b74dcc8b1fc2c688db47a00c7685334f30a0f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Security for mlpreflight 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page