mlpipe-cli 0.1.0__py3-none-any.whl
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.
- mlpipe/__init__.py +43 -0
- mlpipe/__main__.py +6 -0
- mlpipe/artifacts/__init__.py +23 -0
- mlpipe/artifacts/manager.py +246 -0
- mlpipe/artifacts/serialization.py +67 -0
- mlpipe/cli/__init__.py +5 -0
- mlpipe/cli/main.py +667 -0
- mlpipe/core/__init__.py +35 -0
- mlpipe/core/config.py +76 -0
- mlpipe/core/exceptions.py +65 -0
- mlpipe/core/pipeline.py +435 -0
- mlpipe/core/result.py +50 -0
- mlpipe/data/__init__.py +20 -0
- mlpipe/data/ingestion.py +138 -0
- mlpipe/data/profiling.py +227 -0
- mlpipe/data/splitting.py +130 -0
- mlpipe/data/validation.py +248 -0
- mlpipe/evaluation/__init__.py +11 -0
- mlpipe/evaluation/evaluator.py +146 -0
- mlpipe/evaluation/metrics.py +53 -0
- mlpipe/explainability/__init__.py +5 -0
- mlpipe/explainability/importance.py +65 -0
- mlpipe/models/__init__.py +13 -0
- mlpipe/models/classification.py +156 -0
- mlpipe/models/registry.py +32 -0
- mlpipe/models/regression.py +126 -0
- mlpipe/models/selection.py +24 -0
- mlpipe/preprocessing/__init__.py +21 -0
- mlpipe/preprocessing/builder.py +163 -0
- mlpipe/preprocessing/categorical.py +17 -0
- mlpipe/preprocessing/datetime.py +55 -0
- mlpipe/preprocessing/numeric.py +17 -0
- mlpipe/tuning/__init__.py +10 -0
- mlpipe/tuning/search.py +140 -0
- mlpipe/tuning/spaces.py +11 -0
- mlpipe/utils/__init__.py +13 -0
- mlpipe/utils/hashing.py +15 -0
- mlpipe/utils/logging.py +37 -0
- mlpipe/utils/timing.py +33 -0
- mlpipe/version.py +3 -0
- mlpipe_cli-0.1.0.dist-info/METADATA +264 -0
- mlpipe_cli-0.1.0.dist-info/RECORD +46 -0
- mlpipe_cli-0.1.0.dist-info/WHEEL +5 -0
- mlpipe_cli-0.1.0.dist-info/entry_points.txt +2 -0
- mlpipe_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- mlpipe_cli-0.1.0.dist-info/top_level.txt +1 -0
mlpipe/tuning/search.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Hyperparameter search and model training engine.
|
|
3
|
+
|
|
4
|
+
Runs cross-validation and hyperparameter optimization strictly on training data,
|
|
5
|
+
ensuring complete data leakage prevention.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
import time
|
|
10
|
+
from typing import Any, Dict, List, Optional
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
import pandas as pd
|
|
14
|
+
from sklearn.compose import ColumnTransformer
|
|
15
|
+
from sklearn.model_selection import KFold, RandomizedSearchCV, StratifiedKFold, cross_val_score
|
|
16
|
+
from sklearn.pipeline import Pipeline
|
|
17
|
+
|
|
18
|
+
from mlpipe.models.registry import ModelCandidate
|
|
19
|
+
from mlpipe.tuning.spaces import get_search_iterations
|
|
20
|
+
from mlpipe.utils.logging import get_logger
|
|
21
|
+
|
|
22
|
+
logger = get_logger("tuning")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class TuningResult:
|
|
27
|
+
"""Outcome of tuning a single candidate model."""
|
|
28
|
+
|
|
29
|
+
candidate_name: str
|
|
30
|
+
best_pipeline: Optional[Pipeline]
|
|
31
|
+
best_params: Dict[str, Any]
|
|
32
|
+
best_cv_score: float
|
|
33
|
+
training_time_s: float
|
|
34
|
+
error: Optional[str] = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def tune_candidate(
|
|
38
|
+
candidate: ModelCandidate,
|
|
39
|
+
preprocessor: ColumnTransformer,
|
|
40
|
+
X_train: pd.DataFrame,
|
|
41
|
+
y_train: pd.Series,
|
|
42
|
+
primary_metric: str,
|
|
43
|
+
cv_folds: int = 5,
|
|
44
|
+
mode: str = "balanced",
|
|
45
|
+
random_seed: int = 42,
|
|
46
|
+
) -> TuningResult:
|
|
47
|
+
"""
|
|
48
|
+
Train and tune a candidate model using RandomizedSearchCV on X_train.
|
|
49
|
+
|
|
50
|
+
Never touches test data. Preprocessing is encapsulated inside the Pipeline
|
|
51
|
+
so each CV fold fits preprocessing strictly on that fold's training portion.
|
|
52
|
+
"""
|
|
53
|
+
t_start = time.perf_counter()
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
# 1. Instantiate base estimator
|
|
57
|
+
base_estimator = candidate.create_estimator(random_seed=random_seed)
|
|
58
|
+
|
|
59
|
+
# 2. Construct complete pipeline
|
|
60
|
+
pipeline = Pipeline([
|
|
61
|
+
("preprocessor", preprocessor),
|
|
62
|
+
("estimator", base_estimator),
|
|
63
|
+
])
|
|
64
|
+
|
|
65
|
+
# 3. Determine CV splitter
|
|
66
|
+
n_samples = len(X_train)
|
|
67
|
+
effective_folds = min(cv_folds, n_samples)
|
|
68
|
+
|
|
69
|
+
if candidate.task == "classification":
|
|
70
|
+
val_counts = y_train.value_counts()
|
|
71
|
+
min_class = int(val_counts.min()) if len(val_counts) > 0 else 2
|
|
72
|
+
effective_folds = max(2, min(effective_folds, min_class))
|
|
73
|
+
cv = StratifiedKFold(n_splits=effective_folds, shuffle=True, random_state=random_seed)
|
|
74
|
+
else:
|
|
75
|
+
effective_folds = max(2, effective_folds)
|
|
76
|
+
cv = KFold(n_splits=effective_folds, shuffle=True, random_state=random_seed)
|
|
77
|
+
|
|
78
|
+
# 4. Get search space and format for Pipeline
|
|
79
|
+
raw_space = candidate.get_search_space(mode)
|
|
80
|
+
param_distributions = {
|
|
81
|
+
f"estimator__{k}": v for k, v in raw_space.items()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
n_iter = get_search_iterations(mode)
|
|
85
|
+
|
|
86
|
+
if param_distributions:
|
|
87
|
+
search = RandomizedSearchCV(
|
|
88
|
+
estimator=pipeline,
|
|
89
|
+
param_distributions=param_distributions,
|
|
90
|
+
n_iter=n_iter,
|
|
91
|
+
cv=cv,
|
|
92
|
+
scoring=primary_metric,
|
|
93
|
+
random_state=random_seed,
|
|
94
|
+
n_jobs=None,
|
|
95
|
+
refit=True,
|
|
96
|
+
error_score=np.nan,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
search.fit(X_train, y_train)
|
|
100
|
+
|
|
101
|
+
best_pipe = search.best_estimator_
|
|
102
|
+
best_cv = float(search.best_score_)
|
|
103
|
+
best_params = {
|
|
104
|
+
k.replace("estimator__", ""): (
|
|
105
|
+
float(round(v, 4)) if isinstance(v, (float, np.floating)) else v
|
|
106
|
+
)
|
|
107
|
+
for k, v in search.best_params_.items()
|
|
108
|
+
}
|
|
109
|
+
else:
|
|
110
|
+
# If no params to tune, fit and cross-validate directly
|
|
111
|
+
cv_scores = cross_val_score(
|
|
112
|
+
pipeline, X_train, y_train, cv=cv, scoring=primary_metric, n_jobs=-1
|
|
113
|
+
)
|
|
114
|
+
pipeline.fit(X_train, y_train)
|
|
115
|
+
best_pipe = pipeline
|
|
116
|
+
best_cv = float(cv_scores.mean())
|
|
117
|
+
best_params = {}
|
|
118
|
+
|
|
119
|
+
elapsed = round(time.perf_counter() - t_start, 2)
|
|
120
|
+
|
|
121
|
+
return TuningResult(
|
|
122
|
+
candidate_name=candidate.name,
|
|
123
|
+
best_pipeline=best_pipe,
|
|
124
|
+
best_params=best_params,
|
|
125
|
+
best_cv_score=round(best_cv, 4),
|
|
126
|
+
training_time_s=elapsed,
|
|
127
|
+
error=None,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
except Exception as e:
|
|
131
|
+
elapsed = round(time.perf_counter() - t_start, 2)
|
|
132
|
+
logger.warning("Training failed for %s: %s", candidate.name, e)
|
|
133
|
+
return TuningResult(
|
|
134
|
+
candidate_name=candidate.name,
|
|
135
|
+
best_pipeline=None,
|
|
136
|
+
best_params={},
|
|
137
|
+
best_cv_score=-9999.0,
|
|
138
|
+
training_time_s=elapsed,
|
|
139
|
+
error=str(e),
|
|
140
|
+
)
|
mlpipe/tuning/spaces.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Tuning budgets and search configuration."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_search_iterations(mode: str) -> int:
|
|
5
|
+
"""Return number of RandomizedSearchCV iterations for the training mode."""
|
|
6
|
+
mode = str(mode).lower()
|
|
7
|
+
if mode == "fast":
|
|
8
|
+
return 3
|
|
9
|
+
elif mode == "thorough":
|
|
10
|
+
return 20
|
|
11
|
+
return 8 # balanced
|
mlpipe/utils/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Utility modules for MLPipe."""
|
|
2
|
+
|
|
3
|
+
from mlpipe.utils.hashing import compute_file_hash
|
|
4
|
+
from mlpipe.utils.logging import configure_logging, get_logger
|
|
5
|
+
from mlpipe.utils.timing import Timer, time_block
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"compute_file_hash",
|
|
9
|
+
"configure_logging",
|
|
10
|
+
"get_logger",
|
|
11
|
+
"Timer",
|
|
12
|
+
"time_block",
|
|
13
|
+
]
|
mlpipe/utils/hashing.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Hashing utilities for data integrity and artifact verification."""
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Union
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute_file_hash(path: Union[str, Path]) -> str:
|
|
9
|
+
"""Compute SHA-256 hash of a file."""
|
|
10
|
+
path = Path(path)
|
|
11
|
+
hasher = hashlib.sha256()
|
|
12
|
+
with open(path, "rb") as f:
|
|
13
|
+
for chunk in iter(lambda: f.read(65536), b""):
|
|
14
|
+
hasher.update(chunk)
|
|
15
|
+
return hasher.hexdigest()
|
mlpipe/utils/logging.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Logging utilities for MLPipe."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import sys
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
_LOGGER_NAME = "mlpipe"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_logger(name: Optional[str] = None) -> logging.Logger:
|
|
11
|
+
"""Get the MLPipe logger."""
|
|
12
|
+
logger_name = _LOGGER_NAME if not name else f"{_LOGGER_NAME}.{name}"
|
|
13
|
+
return logging.getLogger(logger_name)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def configure_logging(verbose: bool = False) -> None:
|
|
17
|
+
"""Configure MLPipe logging format and verbosity."""
|
|
18
|
+
logger = logging.getLogger(_LOGGER_NAME)
|
|
19
|
+
logger.handlers.clear()
|
|
20
|
+
|
|
21
|
+
level = logging.DEBUG if verbose else logging.INFO
|
|
22
|
+
logger.setLevel(level)
|
|
23
|
+
|
|
24
|
+
handler = logging.StreamHandler(sys.stderr)
|
|
25
|
+
handler.setLevel(level)
|
|
26
|
+
|
|
27
|
+
if verbose:
|
|
28
|
+
formatter = logging.Formatter(
|
|
29
|
+
fmt="[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s",
|
|
30
|
+
datefmt="%H:%M:%S",
|
|
31
|
+
)
|
|
32
|
+
else:
|
|
33
|
+
formatter = logging.Formatter(fmt="%(message)s")
|
|
34
|
+
|
|
35
|
+
handler.setFormatter(formatter)
|
|
36
|
+
logger.addHandler(handler)
|
|
37
|
+
logger.propagate = False
|
mlpipe/utils/timing.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Timing utilities for ML execution benchmarking."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from contextlib import contextmanager
|
|
5
|
+
from typing import Generator
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Timer:
|
|
9
|
+
"""Timer utility to record elapsed execution time."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self.start_time: float = 0.0
|
|
13
|
+
self.end_time: float = 0.0
|
|
14
|
+
self.elapsed: float = 0.0
|
|
15
|
+
|
|
16
|
+
def start(self) -> "Timer":
|
|
17
|
+
self.start_time = time.perf_counter()
|
|
18
|
+
return self
|
|
19
|
+
|
|
20
|
+
def stop(self) -> float:
|
|
21
|
+
self.end_time = time.perf_counter()
|
|
22
|
+
self.elapsed = self.end_time - self.start_time
|
|
23
|
+
return self.elapsed
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@contextmanager
|
|
27
|
+
def time_block() -> Generator[Timer, None, None]:
|
|
28
|
+
"""Context manager to measure block execution time."""
|
|
29
|
+
timer = Timer().start()
|
|
30
|
+
try:
|
|
31
|
+
yield timer
|
|
32
|
+
finally:
|
|
33
|
+
timer.stop()
|
mlpipe/version.py
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mlpipe-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Production-ready tabular ML automation library and terminal CLI
|
|
5
|
+
Author: MLPipe Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Intended Audience :: Science/Research
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: pandas>=2.0.0
|
|
20
|
+
Requires-Dist: numpy>=1.24.0
|
|
21
|
+
Requires-Dist: scikit-learn>=1.3.0
|
|
22
|
+
Requires-Dist: joblib>=1.3.0
|
|
23
|
+
Requires-Dist: scipy>=1.10.0
|
|
24
|
+
Requires-Dist: typer[all]>=0.9.0
|
|
25
|
+
Requires-Dist: rich>=13.0.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# MLPipe
|
|
32
|
+
|
|
33
|
+
> **Production-ready tabular ML automation library and terminal CLI.**
|
|
34
|
+
> From raw CSV to evaluated, reproducible, deployable model pipelines in one command.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## ๐ Overview
|
|
39
|
+
|
|
40
|
+
**MLPipe** automates the repetitive engineering lifecycle for tabular machine learning models. Simply point MLPipe at your CSV dataset and designate a target column:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
Raw CSV Dataset
|
|
44
|
+
โ
|
|
45
|
+
Data Ingestion (Format validation & SHA-256 integrity hash)
|
|
46
|
+
โ
|
|
47
|
+
Data Profiling (Column types, distributions, missingness & flags)
|
|
48
|
+
โ
|
|
49
|
+
Pre-training Validation (Fatal structural errors & non-blocking warnings)
|
|
50
|
+
โ
|
|
51
|
+
Task Detection (Automatic classification vs. regression inference)
|
|
52
|
+
โ
|
|
53
|
+
Leakage-Free Splitting (Stratified or random train/test split)
|
|
54
|
+
โ
|
|
55
|
+
Automated Preprocessing (ColumnTransformer: imputation, scaling & encoding)
|
|
56
|
+
โ
|
|
57
|
+
Multi-Model Training & Tuning (RandomizedSearchCV strictly on training folds)
|
|
58
|
+
โ
|
|
59
|
+
CV-Based Leaderboard Ranking (Winning model selected by CV, not test set)
|
|
60
|
+
โ
|
|
61
|
+
Held-Out Test Evaluation (Unbiased final metrics & confusion matrix)
|
|
62
|
+
โ
|
|
63
|
+
Model Explainability (Recovered transformed feature importances & coefficients)
|
|
64
|
+
โ
|
|
65
|
+
Artifact Generation (Reusable pipeline, model, metadata & reports)
|
|
66
|
+
โ
|
|
67
|
+
Instant Predictions (CLI & Python inference)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
No hardcoded results. No fake training. Real scikit-learn models and metrics computed on your CPU machine.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## ๐ฆ Installation
|
|
75
|
+
|
|
76
|
+
Install locally in editable mode:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
git clone https://github.com/your-org/mlpipe.git
|
|
80
|
+
cd mlpipe
|
|
81
|
+
pip install -e .
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Verify the installation:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
mlpipe --version
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## โก Quick Start
|
|
93
|
+
|
|
94
|
+
### 1. Terminal CLI
|
|
95
|
+
|
|
96
|
+
Train an end-to-end classification pipeline:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
mlpipe train demo_data/customer_churn.csv --target churn
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Train a regression pipeline:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
mlpipe train demo_data/house_prices.csv --target price
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Generate predictions on new data:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
mlpipe predict ./mlpipe_runs/<run_id>/pipeline.joblib demo_data/customer_churn.csv --output predictions.csv
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 2. Python API
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from mlpipe import Pipeline
|
|
118
|
+
|
|
119
|
+
# 1. Initialize pipeline
|
|
120
|
+
pipeline = Pipeline(
|
|
121
|
+
target="churn",
|
|
122
|
+
task="auto", # auto-detects classification vs regression
|
|
123
|
+
mode="balanced", # "fast", "balanced", or "thorough"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# 2. Fit pipeline on CSV or DataFrame
|
|
127
|
+
result = pipeline.fit("demo_data/customer_churn.csv")
|
|
128
|
+
|
|
129
|
+
# 3. Inspect results
|
|
130
|
+
print("Best Model:", result.best_model)
|
|
131
|
+
print("Primary Metric:", result.primary_metric)
|
|
132
|
+
print("CV Score:", result.best_cv_score)
|
|
133
|
+
print("Test Score:", result.test_score)
|
|
134
|
+
print("Test Metrics:", result.metrics)
|
|
135
|
+
|
|
136
|
+
# 4. Save and reload pipeline
|
|
137
|
+
pipeline.save("./trained_models/churn_model")
|
|
138
|
+
|
|
139
|
+
loaded_pipeline = Pipeline.load("./trained_models/churn_model")
|
|
140
|
+
predictions = loaded_pipeline.predict("demo_data/customer_churn.csv")
|
|
141
|
+
print("Predictions:", predictions[:5])
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## ๐ ๏ธ CLI Command Reference
|
|
147
|
+
|
|
148
|
+
### `mlpipe train`
|
|
149
|
+
Train multiple candidate models, tune hyperparameters, rank on leaderboard, and save artifacts.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
mlpipe train <data.csv> --target <target_col> [OPTIONS]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Options:**
|
|
156
|
+
- `--target, -t`: Target column name to predict (required).
|
|
157
|
+
- `--task`: Task type override: `auto` (default), `classification`, or `regression`.
|
|
158
|
+
- `--mode, -m`: Training mode budget: `fast`, `balanced` (default), or `thorough`.
|
|
159
|
+
- `--output, -o`: Base directory to store run artifacts (default: `./mlpipe_runs`).
|
|
160
|
+
- `--format, -f`: Output format: `human` (default) or `json`.
|
|
161
|
+
- `--verbose`: Enable detailed debug logging.
|
|
162
|
+
|
|
163
|
+
### `mlpipe profile`
|
|
164
|
+
Inspect dataset summary, column types, statistics, missingness, and structural issues.
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
mlpipe profile demo_data/customer_churn.csv
|
|
168
|
+
mlpipe profile demo_data/customer_churn.csv --format json
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### `mlpipe validate`
|
|
172
|
+
Run pre-training validation checks on dataset and target.
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
mlpipe validate demo_data/customer_churn.csv --target churn
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### `mlpipe predict`
|
|
179
|
+
Generate predictions on a new CSV dataset using a saved pipeline.
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
mlpipe predict ./mlpipe_runs/<run_id>/pipeline.joblib new_data.csv --output preds.csv
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### `mlpipe inspect`
|
|
186
|
+
Inspect metadata, configuration, metrics, and generated artifacts from a previous run directory.
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
mlpipe inspect ./mlpipe_runs/<run_id>
|
|
190
|
+
mlpipe inspect ./mlpipe_runs/<run_id> --format json
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### `mlpipe version`
|
|
194
|
+
Display the current version of MLPipe.
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
mlpipe version
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## ๐ง Supported Models
|
|
203
|
+
|
|
204
|
+
### Classification
|
|
205
|
+
- **Logistic Regression** (L2 penalty, liblinear/lbfgs/saga solvers)
|
|
206
|
+
- **Random Forest Classifier** (trees, depth, sample split/leaf tuning)
|
|
207
|
+
- **HistGradientBoosting Classifier** (iterations, learning rate, leaf bounds)
|
|
208
|
+
- **Decision Tree Classifier** (depth, split thresholds, criteria)
|
|
209
|
+
- **K-Nearest Neighbors** (neighbors, weights, distance metrics)
|
|
210
|
+
|
|
211
|
+
### Regression
|
|
212
|
+
- **Ridge Regression** (regularization alpha, solver selection)
|
|
213
|
+
- **Random Forest Regressor** (trees, depth, sample bounds, features)
|
|
214
|
+
- **HistGradientBoosting Regressor** (iterations, rate, regularization)
|
|
215
|
+
- **Decision Tree Regressor** (depth, split criteria, sample leaves)
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## ๐ Data Leakage Prevention Guarantee
|
|
220
|
+
|
|
221
|
+
MLPipe adheres to strict data integrity standards:
|
|
222
|
+
1. **No Full-Data Transformations:** Preprocessing pipelines are never fitted on the entire dataset.
|
|
223
|
+
2. **Train/Test Split First:** The raw dataset is partitioned (default 80% train, 20% test) before column classification and transformer fitting.
|
|
224
|
+
3. **Cross-Validation Inside Pipelines:** During hyperparameter search, sklearn `Pipeline` objects fit transformers solely on the internal training fold of each split.
|
|
225
|
+
4. **CV-Based Model Selection:** The winning model is selected strictly based on CV score on the training set. The held-out test set is evaluated exactly once for unbiased reporting.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## ๐ Artifact Structure
|
|
230
|
+
|
|
231
|
+
Each completed training run generates a self-contained bundle under `./mlpipe_runs/<run_id>/`:
|
|
232
|
+
|
|
233
|
+
```text
|
|
234
|
+
mlpipe_runs/<run_id>/
|
|
235
|
+
โโโ pipeline.joblib # Complete fitted pipeline (preprocessor + estimator)
|
|
236
|
+
โโโ model.joblib # Fitted estimator alone
|
|
237
|
+
โโโ metrics.json # CV and test evaluation metrics
|
|
238
|
+
โโโ leaderboard.json # Complete ranked candidate comparison table
|
|
239
|
+
โโโ metadata.json # Dataset hash, seed, mode, environment & parameters
|
|
240
|
+
โโโ feature_importance.json # Top features with recovered transformed names
|
|
241
|
+
โโโ report.txt # Plain text human-readable run summary
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## ๐งช Running Tests
|
|
247
|
+
|
|
248
|
+
Run the complete test suite using `pytest`:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
pytest
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Run with verbose test output:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
pytest -v
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## ๐ License
|
|
263
|
+
|
|
264
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
mlpipe/__init__.py,sha256=9SL7L_xZkvqg-X_i94AzlvOy-N0X_agPY2tYxtPKvsM,1009
|
|
2
|
+
mlpipe/__main__.py,sha256=N655XDgrdsIN-pSBZ3niJVt4SMx-rA89GswQ1wtL02o,123
|
|
3
|
+
mlpipe/version.py,sha256=sEWauLYY0-L5PvpCgQKUvLpmAcG9sLEzOrLCQ3few-0,45
|
|
4
|
+
mlpipe/artifacts/__init__.py,sha256=FzoR6sWUHVBnxzLDaNHVIeVG8tMEKyNl1x1pdePaOe0,454
|
|
5
|
+
mlpipe/artifacts/manager.py,sha256=OH1rKzGzhqK72XFWzGL7nX85YsxeE7wJZRlNklfHGuY,9497
|
|
6
|
+
mlpipe/artifacts/serialization.py,sha256=7H05Ksipf7mMkEhRwuqxbMHjTrbrWU8ZqD5tdHSVvJk,2075
|
|
7
|
+
mlpipe/cli/__init__.py,sha256=EqXs6vMQyYCqwFubH-gx1PVjbLag8wEZeimgzyG5l1k,81
|
|
8
|
+
mlpipe/cli/main.py,sha256=mh4cX-gcuazLIB9JGA8MlAdKBMYnzxn80WW8u8trl50,26628
|
|
9
|
+
mlpipe/core/__init__.py,sha256=2qdbY5J_YzunTrhaRVPNRxUrnF4jG1ku_CS5dH_XWlE,766
|
|
10
|
+
mlpipe/core/config.py,sha256=eoHFi2TZJhz2RhBZVRvwN4EXZ-sEsIFhSmNSrmDmKdU,2398
|
|
11
|
+
mlpipe/core/exceptions.py,sha256=8Qq6xoFWp1ine9K2-vZDRKaJDWRqj_j1czQpe2_wk70,1559
|
|
12
|
+
mlpipe/core/pipeline.py,sha256=UbCVdn-QwPyHEBue7XGdDGL3xzpQIfF_xGi17rIMpjU,18342
|
|
13
|
+
mlpipe/core/result.py,sha256=yzZ5huwzz3tHWbzbeLGayPZfk0MMbdOg801aiKPBS9k,1633
|
|
14
|
+
mlpipe/data/__init__.py,sha256=sZxmu8PewKdOGMFX1HhTTiu7KBG3wYTc8uDY7WrD2cY,612
|
|
15
|
+
mlpipe/data/ingestion.py,sha256=ngGRvYJbH2qa_LArtw3iRx7OUDAWMVEM5YkUvy2BsQw,4156
|
|
16
|
+
mlpipe/data/profiling.py,sha256=cWTUXgiuFLv_mTOMjbKfCbJ9cSxTaCDWLnmI3CTX-xc,7772
|
|
17
|
+
mlpipe/data/splitting.py,sha256=8uUmRvkwqXr0uw03yGXb6mMn2MksVKmpNyguaueJAGU,4079
|
|
18
|
+
mlpipe/data/validation.py,sha256=VNCvW9N2PRk094Ms4Q45LftX2zSfjAV2NPbsOSuqTLI,9113
|
|
19
|
+
mlpipe/evaluation/__init__.py,sha256=uFunO9rZEQ3s_JvUtxfpdT4IhtYnRh9Azr-wFmPFRSA,369
|
|
20
|
+
mlpipe/evaluation/evaluator.py,sha256=1u0Iu8XVl8qGvtrZn6vPzpQrwcGo9KmxfqCJ_kYbF10,4740
|
|
21
|
+
mlpipe/evaluation/metrics.py,sha256=Tlb_qjQtEJXHeZnTrB4L94ZxzkeTVLkg0RxEEmorXsQ,1676
|
|
22
|
+
mlpipe/explainability/__init__.py,sha256=chP_Wj0BJu8sfyfKUkddVMj99rlnCEBjYPq8_VgmrWs,155
|
|
23
|
+
mlpipe/explainability/importance.py,sha256=Rm5gv5BkXwXbVmz18MCwXyA1wq5uU788pvfg5cMRAl0,2066
|
|
24
|
+
mlpipe/models/__init__.py,sha256=T8pwlu84QvslpEhKKDh9aluycpLLZ5vMdGQuJMigq6E,433
|
|
25
|
+
mlpipe/models/classification.py,sha256=Tov2ke_aU-p4itJBgsbSrGR3caeVVBMl3hJJtpcfMG0,5581
|
|
26
|
+
mlpipe/models/registry.py,sha256=iPzVd9JX56JOth0G9xdYDohxfDQex5wjkwXhvSpiTtc,1264
|
|
27
|
+
mlpipe/models/regression.py,sha256=EnvAjnTP4AxDOXry_nTf02KM-aGa_5QRVMqNJwCCAE4,4535
|
|
28
|
+
mlpipe/models/selection.py,sha256=BVmH306h-yRRvT4UMQrXxxpB6HX0g_CNXb44_uQgTHY,839
|
|
29
|
+
mlpipe/preprocessing/__init__.py,sha256=2j8rtLAiwhZXhZmCCmx9yieqDrA7X3hh7wZmZFwS5aw,651
|
|
30
|
+
mlpipe/preprocessing/builder.py,sha256=B1BYsf1aRaZTM7dvHBmsPZuGv0XVCLuQyCk-uwcZN9E,5407
|
|
31
|
+
mlpipe/preprocessing/categorical.py,sha256=xr3fyu7YURwo5tlSHB8VUTvenheh-61jJeKpSSPffzY,578
|
|
32
|
+
mlpipe/preprocessing/datetime.py,sha256=6rL4PNwrmPBJSNu8fjRkZXG8FtMjXdo4SxnJPSDDpI4,1838
|
|
33
|
+
mlpipe/preprocessing/numeric.py,sha256=dV593TybFvKA181J1wcWB-sq2eACy3YmE6OE3FkjT0g,552
|
|
34
|
+
mlpipe/tuning/__init__.py,sha256=9L73xQFbNMQaFv5Jb_jemFnfKlTBmM82P-kRjZcQaoo,262
|
|
35
|
+
mlpipe/tuning/search.py,sha256=w5CIgR3kCQqBoj7S2Wp0qzAbc9f5SYECLEEYxl0aMaU,4560
|
|
36
|
+
mlpipe/tuning/spaces.py,sha256=Q24XMqNwMy3ds0vh8WbDFCzCqiueJC3aS3baYLCGlsc,315
|
|
37
|
+
mlpipe/utils/__init__.py,sha256=f1L5EmOgp0d5jNJAm3gM-3qPbpQLOewAOxekPOYqptk,313
|
|
38
|
+
mlpipe/utils/hashing.py,sha256=tQKCHjByFO_hyU4PQwZOZZi1ozvpzW9X-eYnJlZc_2c,436
|
|
39
|
+
mlpipe/utils/logging.py,sha256=8P2a3uXH7gzAo3lOinFmCN1h8WHRIInEhqs0-AD7e24,1008
|
|
40
|
+
mlpipe/utils/timing.py,sha256=GIa1wi4N_O-lFz0eSsdJPDZty76HjNaxFL3Um7wwLCc,812
|
|
41
|
+
mlpipe_cli-0.1.0.dist-info/licenses/LICENSE,sha256=JTJyA0ZggMhgGY0nFJtstNzYedEE-sBRJFDvrB1eV-4,1076
|
|
42
|
+
mlpipe_cli-0.1.0.dist-info/METADATA,sha256=dKcmOICyKHx9gBIfMwoyT976fhyfDE68D_q888uO7Xo,8064
|
|
43
|
+
mlpipe_cli-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
44
|
+
mlpipe_cli-0.1.0.dist-info/entry_points.txt,sha256=xRznh8TJmM2kkk63dZ6q-xxnwS6osZNHrJ18hi_4QAQ,47
|
|
45
|
+
mlpipe_cli-0.1.0.dist-info/top_level.txt,sha256=yD70na0QWAVtUCmM4oDydp2ppLncPl5RZkL2evcNQGI,7
|
|
46
|
+
mlpipe_cli-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MLPipe Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mlpipe
|