Skip to main content

Universal Data Cleaner

CI PyPI Python 3.10+ License: MIT Managed with uv

A small, production-oriented tabular cleaning transformer for pandas + scikit-learn.

It is designed for the part of an ML pipeline that is easy to get wrong: cleaning training data and inference data with exactly the same learned rules.

Why this exists

A common notebook pattern is:

df["Age"] = df["Age"].fillna(df["Age"].median())

That leaks information when it is run before the train/test split, and it silently breaks at inference time because the median is recomputed on the new batch.

DataCleaner fits on training data, stores the learned values, and reuses them in transform() and in saved artifacts.

What it handles

  • numeric coercion and median / mean / constant imputation
  • optional IQR outlier capping (learned from training data only)
  • categorical mode / constant imputation
  • optional unseen-category policy: keep or replace
  • boolean coercion and imputation
  • datetime parsing plus calendar feature extraction
  • optional missing-value indicator columns
  • optional constant-column dropping
  • stable output schema and column order
  • joblib save / load with artifact versioning
  • scikit-learn Pipeline, clone, and get_feature_names_out compatibility

The cleaner never mutates the input DataFrame and never drops inference rows.

Install from PyPI

pip install universal-data-cleaner

The distribution name is universal-data-cleaner; the import name is data_cleaner.

from data_cleaner import CleanerConfig, DataCleaner

Development setup with uv

git clone https://github.com/devlprkhan/universal-data-cleaner.git
cd universal-data-cleaner
uv sync

Run the test suite:

uv run pytest -q

Open the reference notebook:

uv run jupyter lab Universal_Data_Cleaner.ipynb

The notebook is also verified headlessly in CI-style environments with nbclient; both tools are in the dev dependency group.

Install directly from GitHub

uv add "git+https://github.com/devlprkhan/universal-data-cleaner.git"
# or
pip install "git+https://github.com/devlprkhan/universal-data-cleaner.git"

Quick start

import pandas as pd
from data_cleaner import CleanerConfig, DataCleaner

train = pd.DataFrame(
    {
        "age": [34, 41, None, 29],
        "salary": [70_000, 82_000, 91_000, 55_000],
        "dept": ["IT", "HR", "IT", None],
        "joined": ["2022-01-03", "2021-11-20", "2023-04-01", "bad-date"],
    }
)

config = CleanerConfig(
    datetime_columns=("joined",),
    add_missing_indicators=True,
    drop_constant_columns=True,
)

cleaner = DataCleaner(config).fit(train)
train_clean = cleaner.transform(train)
print(cleaner.cleaning_summary())
print(cleaner.outlier_summary())

For a column that should be numeric even though it arrived as dirty strings:

config = CleanerConfig(
    numeric_columns=("salary",),          # force numeric parsing
    datetime_columns=("joined",),        # parse dates instead of treating them as categories
    unseen_category="keep",              # or "fill" to replace unseen labels
)

Leak-safe workflow

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

cleaner = DataCleaner(config).fit(X_train)

X_train_clean = cleaner.transform(X_train)
X_test_clean = cleaner.transform(X_test)   # uses train statistics only

Save the fitted cleaner with the model artifact:

cleaner.save("artifacts/data_cleaner.joblib")
restored = DataCleaner.load("artifacts/data_cleaner.joblib")

scikit-learn Pipeline

from sklearn.compose import ColumnTransformer
from sklearn.linear_model import Ridge
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler

numeric = ["age", "salary", "joined__year"]
categorical = ["dept"]
boolean = []

preprocess = ColumnTransformer(
    [
        ("num", StandardScaler(), numeric),
        ("cat", OneHotEncoder(handle_unknown="ignore"), categorical),
        ("bool", "passthrough", boolean),
    ],
    remainder="drop",
)

pipeline = Pipeline(
    [
        ("cleaner", DataCleaner(config)),
        ("features", preprocess),
        ("model", Ridge(alpha=1.0)),
    ]
)
pipeline.fit(X_train, y_train)
predictions = pipeline.predict(X_test)

Public API

Name Purpose
CleanerConfig Validated cleaning configuration
DataCleaner Fit/transform cleaner with save/load
profile_dataframe Column-level missing/type/cardinality profile
dataset_summary Row/column/missing/duplicate summary
drop_duplicate_rows Explicit duplicate removal helper
assert_frame_clean Guard against missing/infinite output values

Important production notes

  • Fit the cleaner after splitting and only on training data.
  • Do not pass IDs, free-text notes, or the target column to the cleaner.
  • Keep DataSource-style constant columns out of the model, or let drop_constant_columns=True remove them.
  • unseen_category="keep" is the default because one-hot encoders with handle_unknown="ignore" can handle an unseen label safely.
  • Datetime columns are replaced by calendar features. Their missing values are represented by the generated feature NaNs plus an optional missing indicator.
  • IQR capping is skipped automatically when the IQR is zero, so constant or near-constant numeric columns are not accidentally destroyed.

Project layout

.
├── data_cleaner.py                    # reusable library module
├── Universal_Data_Cleaner.ipynb       # end-to-end reference workflow
├── tests/test_data_cleaner.py         # unit and integration tests
├── pyproject.toml                     # package metadata and dev tooling
├── uv.lock                            # reproducible dependency lock
├── README.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── SECURITY.md
└── LICENSE

Contributing

Contributions are welcome. See CONTRIBUTING.md for the local setup, test command, and pull-request expectations.

License

Released under the MIT License.

Metadata

Release files for universal-data-cleaner 2.0.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 universal-data-cleaner 2.0.0
File Size Uploaded Provenance
universal_data_cleaner-2.0.0.tar.gz 16.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for universal-data-cleaner 2.0.0
File Interpreter ABI Platform
universal_data_cleaner-2.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 28.5 kB

Release files / universal_data_cleaner-2.0.0.tar.gz

Download URL universal_data_cleaner-2.0.0.tar.gz
Size 16.5 kB
Tags Source
SHA-256 checksum
How to use checksums
05a0f720d02194ba07451d773fd18f75c717e85a3e80abc6f8afec1cce72ea93
BLAKE2b-256 checksum
How to use checksums
dae9fda65a221d9669b65c188e402b52ebfee8462647695a4bb3260c9aae464d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / universal_data_cleaner-2.0.0-py3-none-any.whl

Download URL universal_data_cleaner-2.0.0-py3-none-any.whl
Size 12.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a60b1b30d4d15b1c4031a63dd606fd7b50d6df32b61e5e1489da229b19ed8e0b
BLAKE2b-256 checksum
How to use checksums
9aa6f7a9dedd2009aee8c56609e8e5b2bd2e6357030968a7c1c4c3004c494111
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for universal-data-cleaner 2.0.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.

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