Architettura della pipeline
1. Vista a 3 layerβ
La pipeline Γ¨ organizzata in tre layer ortogonali:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application layer β
β CLI (fraud-train, fraud-predict) β
β Notebook 01β04 (didattici) β
β pytest (test_features, test_inference) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β chiama
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Pipeline orchestration β
β pipeline.run_full_pipeline() β
β inference.predict_fraud() β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β compone
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Domain modules (single responsibility) β
β data | features | preprocessing | models β
β tuning | threshold | evaluation β
β config (costanti, niente logica) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Ogni layer dipende solo da quelli sotto. La separazione consente:
- Test in isolamento (mocking dei layer inferiori).
- Sostituzione locale: cambiare modello implica toccare solo
models.py. - Riutilizzo: i notebook chiamano le stesse funzioni della CLI.
2. Mappa dei moduli src/fraud_pipeline/β
| Modulo | ResponsabilitΓ | Linee |
|---|---|---|
config.py | Path filesystem, costanti, schema dataset, iperparametri default, dataclass PipelineConfig | ~150 |
data.py | I/O CSV, schema validation, ordinamento cronologico, split temporale, smoke-test sampling | ~170 |
features.py | FraudFeatureEngineer (transformer sklearn): temporali, geografiche, aggregati cliente | ~210 |
preprocessing.py | ColumnTransformer: numeric (imputer + scaler), nominal (imputer + OneHotEncoder) | ~110 |
models.py | Pipeline candidate (LogReg, RF, opzionalmente XGBoost) con class_weight | ~135 |
tuning.py | TimeSeriesSplit + GridSearchCV / RandomizedSearchCV su scoring average_precision | ~190 |
threshold.py | CostMatrix, optimal_threshold_by_cost, threshold_sweep | ~190 |
evaluation.py | compute_metrics, curve PR/ROC, confusion matrix, feature importance | ~220 |
inference.py | predict_fraud(tx), lazy load model + threshold, CLI fraud-predict | ~190 |
pipeline.py | Orchestratore + entry point CLI fraud-train | ~280 |
Tutti i moduli sono piccoli e focalizzati (β€300 righe). Nessun monolite.
3. Flusso dati end-to-endβ
βββββββββββββββββββββββββββββββββββ
β data/raw/fraudTrain.csv β
β data/raw/fraudTest.csv β
ββββββββββββββ¬βββββββββββββββββββββ
β
β data.load_train_test()
βββββββββββββββββββββββββββββββββββ
β DataFrame ordinato cronologic. β
β + schema validato β
ββββββββββββββ¬βββββββββββββββββββββ
β
β data.split_features_target()
βββββββββ΄ββββββββ
β β
X_train, X_test,
y_train y_test
β β
β β
Pipeline: |
feature_engineer βββββββββ
(sklearn) ββ
preprocessor ββ fit -> transform -> predict
model (LogReg/RF/XGB) ββ
ββ
β βΌβ
β TimeSeriesSplit CV
Tuning (AUC-PR) |
| |
β |
best_model |
| |
β |
predict_proba(X_test)β
| |
β β
CostMatrix [MODEL]
| |
β β
optimal_threshold |
| β
ββββββ Persistenza βββββ reports/models/
βββ best_model.joblib
βββ threshold.json
4. Pipeline sklearn: tre step concatenatiβ
L'oggetto sklearn.pipeline.Pipeline finale ha la struttura:
Pipeline(steps=[
("feature_engineer", FraudFeatureEngineer()), # custom transformer
("preprocessor", ColumnTransformer(...)), # imputer + scaler + OHE
("model", LogisticRegression(...)), # o RF/XGB
])
PerchΓ© un singolo Pipelineβ
fit_predict_proba: l'API sklearnpipeline.predict_proba(X)esegue automaticamente: feature engineering β preprocessing β modello. Niente codice custom.- No leakage in CV: ogni fold della
TimeSeriesSpliteseguepipeline.fitsolo sul subset di training. - Serializzazione bit-identica:
joblib.dump(pipeline, "model.joblib")salva tutto. L'inferenza Γ¨ esattamente quella del training.
5. CLIβ
Due entry point dichiarati in pyproject.toml:
[project.scripts]
fraud-train = "fraud_pipeline.pipeline:main_train"
fraud-predict = "fraud_pipeline.inference:main_predict"
fraud-trainβ
fraud-train # full pipeline
fraud-train --quick # smoke-test 50k righe
fraud-train --xgboost # include XGBoost
fraud-train --cost-fn 200 --cost-fp 10 # cost matrix custom
Output:
reports/models/best_model.joblibreports/models/threshold.jsonreports/cv_summary.csvreports/holdout_metrics.jsonreports/threshold_analysis.csvreports/figures/*.png
fraud-predictβ
fraud-predict --input transactions.csv --output predictions.csv
fraud-predict --input transactions.csv --output predictions.csv --threshold 0.20
Legge il CSV, applica il modello, scrive un CSV con colonne fraud_probability, is_fraud, threshold.
6. File persistenti: separazione di concernsβ
| Cartella | Contenuto | Gitignored? |
|---|---|---|
data/raw/ | CSV Kaggle originali | Sì (470 MB) |
data/processed/ | (riservato per snapshot intermedi) | Sì |
data/external/ | (riservato per dati esterni) | Sì |
reports/models/ | .joblib + threshold.json | Sì (>200 MB) |
reports/figures/ | Plot PNG (PR, ROC, confusion matrix) | Sì |
reports/cv_summary.csv | Tabella confronto modelli | Sì |
reports/holdout_metrics.json | Metriche test out-of-time | Sì |
reports/threshold_analysis.csv | Sweep di soglie | Sì |
Tutto ciΓ² che Γ¨ ricostruibile da fraud-train viene gitignored (vedi .gitignore). Il repo committato resta sotto pochi MB.
7. Notebook didatticiβ
I 4 notebook in notebooks/ sono rigenerabili da scripts/build_notebooks.py. Vantaggi:
- Sorgente in Python: diff Git puliti.
- RiproducibilitΓ : chiunque rigenera notebook identici.
- No metadata casuali: kernel locale, output cache non committati.
python scripts/build_notebooks.py
jupyter lab notebooks/
I notebook importano funzioni dai moduli src/fraud_pipeline/: niente duplicazione di logica. Sono "pagine eseguibili" della documentazione.
8. Testβ
tests/ contiene smoke test minimi:
test_features.py: feature engineer produce le colonne attese, non muta l'input, non leak-a sul cliente.test_inference.py:predict_fraudaccetta dict/DataFrame, gestisce threshold, alignment colonne.
Eseguibili con:
pytest tests/ -v
I test che richiedono il modello reale (test_predict_fraud_with_real_model) sono pytest.mark.skipif se best_model.joblib non esiste β non bloccano lo sviluppo locale.
9. CI/CD: GitHub Actionsβ
.github/workflows/docs.yml builda il sito MkDocs Material e lo pubblica su GitHub Pages a ogni push su main.
Tre job sequenziali:
- build:
mkdocs build --strict(fallisce se ci sono link rotti). - upload: artifact
./site. - deploy:
actions/deploy-pages@v4.
Trigger: push a main o workflow_dispatch (manuale).
10. RiproducibilitΓ β
Tre garanzie:
- Stesso seed:
RANDOM_SEED = 42inconfig.py, propagato a sklearn. - Stesse versioni:
pyproject.tomlpinna a range minor (es.numpy>=2.0,<3.0). - Schema check:
data._validate_schemafallisce esplicitamente se i CSV cambiano forma.
Risultato: fraud-train --quick produce metriche identiche su esecuzioni successive (entro tolleranza float64 dovuta al thread parallelism n_jobs=-1; per riproducibilitΓ bit-perfect impostare n_jobs=1).
11. Estensioni futureβ
In ordine di valore aggiunto:
- Target encoding per
merchant(con prior bayesiano e validation set). - Calibrazione probabilitΓ via
CalibratedClassifierCV(isotonicosigmoid). - API REST con FastAPI + Docker per inferenza online.
- Drift detection (KS-test mensile sulla distribuzione di score).
- Monitoring dashboard (Streamlit/Grafana).
- Walk-forward sliding window in alternativa a
TimeSeriesSplitespandente. - SHAP values per explanability per-transazione.
- Ensemble stacking LogReg + RF con meta-learner LogReg.