Passa al contenuto principale

Architettura del progetto

1. Layout​

iot-anomaly-detection-clustering/
β”œβ”€β”€ README.md
β”œβ”€β”€ LICENSE MIT β€” Β© 2026 Federico CalΓ²
β”œβ”€β”€ pyproject.toml Build config + dipendenze
β”œβ”€β”€ requirements.txt Lock approssimativo
β”œβ”€β”€ mkdocs.yml Config documentazione (MkDocs Material)
β”‚
β”œβ”€β”€ .github/
β”‚ └── workflows/
β”‚ └── docs.yml Deploy automatico docs su GitHub Pages
β”‚
β”œβ”€β”€ src/iot_anomaly/ Libreria Python installabile
β”‚ β”œβ”€β”€ __init__.py
β”‚ β”œβ”€β”€ config.py Path, costanti, iperparametri
β”‚ β”œβ”€β”€ data.py Load + time-aware split
β”‚ β”œβ”€β”€ wrangling.py Missing values per asset
β”‚ β”œβ”€β”€ features.py TimeSeriesFeatureEngineer (rolling, diff, zscore)
β”‚ β”œβ”€β”€ clustering.py KMeans/MiniBatch/GMM + select_k
β”‚ β”œβ”€β”€ scoring.py Distanza centroide + soglia percentile
β”‚ β”œβ”€β”€ evaluation.py Metriche + plot diagnostici
β”‚ β”œβ”€β”€ inference.py detect_anomalies()
β”‚ └── pipeline.py Orchestrator + CLI iot-detect
β”‚
β”œβ”€β”€ notebooks/ Documentazione esecutiva
β”‚ β”œβ”€β”€ 01_eda.ipynb
β”‚ β”œβ”€β”€ 02_features_pipeline.ipynb
β”‚ β”œβ”€β”€ 03_clustering_threshold.ipynb
β”‚ └── 04_validation_inference.ipynb
β”‚
β”œβ”€β”€ docs/
β”‚ β”œβ”€β”€ teoria/ 5 file Markdown didattici
β”‚ └── scelte_tecniche/ Architettura, scelte di modello
β”‚
β”œβ”€β”€ data/raw/ iot_synth_anomaly_clustering.csv (gitignored)
β”œβ”€β”€ reports/ Output (figures, models, metrics β€” gitignored)
β”‚ β”œβ”€β”€ figures/
β”‚ β”œβ”€β”€ models/ *.joblib serializzati
β”‚ └── metrics.json
β”‚
β”œβ”€β”€ scripts/
β”‚ β”œβ”€β”€ build_notebooks.py
β”‚ └── run_full.sh
└── tests/

2. Principi di design​

Stesso pattern di ames-housing-price-pipeline:

2.1 Codice in src/, narrativa nei notebook​

La logica vive in src/iot_anomaly/. I notebook contengono solo importazioni, chiamate, e narrazione didattica. Modifiche al codice si riflettono automaticamente nei notebook (riavvia kernel).

2.2 Notebook generati da script​

scripts/build_notebooks.py Γ¨ la sorgente di veritΓ . Diff Git puliti.

2.3 Pipeline as code (sklearn-compatible)​

Il TimeSeriesFeatureEngineer Γ¨ un BaseEstimator + TransformerMixin. Il modello finale (clustering + scoring + soglia) Γ¨ incapsulato in un AnomalyDetector. L'inferenza ricarica un singolo joblib.

2.4 No leakage by construction​

  • Wrangling deterministico (ffill/bfill per asset) β€” puΓ² stare fuori dalla pipeline (non dipende da statistiche).
  • Imputazione, scaling, soglia β†’ sempre calcolate sul solo training.
  • Rolling back-looking, per asset (groupby('asset_id')).
  • Time-aware split, mai casuale.

3. Flusso di esecuzione​

3.1 Training completo​

iot-detect # full run, ~60s
iot-detect --quick # K=5 fisso, ~30s
iot-detect --use-pca # con PCA prima del clustering
iot-detect --threshold-percentile 95 # soglia piΓΉ aggressiva

Sequenza interna:

  1. load_raw() β†’ DataFrame ordinato per (asset, time).
  2. add_missing_flags + fill_missing_per_asset β†’ wrangling.
  3. TimeSeriesFeatureEngineer β†’ rolling, diff, zscore.
  4. time_split β†’ 7 giorni train / 3 giorni test.
  5. StandardScaler + (opzionale) PCA.
  6. select_k_by_silhouette su K ∈ {3..10}.
  7. fit_minibatch_kmeans + fit_anomaly_detector (soglia p99).
  8. evaluate su train e test vs anomaly_label e fault_code_true.
  9. Salvataggio joblib + metriche JSON + figure.

3.2 Inferenza​

from iot_anomaly.inference import detect_anomalies

import pandas as pd
df_new = pd.read_csv("nuovi_dati.csv", parse_dates=["timestamp"])
result = detect_anomalies(df_new)
print(result[result.anomaly_pred == 1])

detect_anomalies() riapplica wrangling, FE, scaling, scoring usando gli artefatti serializzati. Output: DataFrame originale + colonne anomaly_score, anomaly_pred.

4. Riproducibilità​

  • Stesso dataset: la pipeline carica solo data/raw/iot_synth_anomaly_clustering.csv.
  • Stesse versioni: requirements.txt pinnato a range minor.
  • Stesso seed: RANDOM_STATE=42 propagato a MiniBatchKMeans, silhouette_score (via sample), KMeans, GMM.

Con stesso ambiente, esecuzioni successive di iot-detect producono metriche bit-identiche.

5. Trade-off espliciti​

DecisioneVantaggioCosto
Time-aware split rigido (7+3)RealismoSolo 1 holdout, non K-fold temporale
MiniBatchKMeans default10Γ— piΓΉ veloce di KMeans fullInertia ~1-3% peggiore
Soglia p99 fissaConfigurabile, interpretabileNon ottimale per ogni asset
Niente label nel trainingGeneralizzazione a anomalie nuovePerformance inferiori vs supervised
FE temporale solo rolling+diff+zscoreInterpretabile, veloceNessuna feature multivariata (es. cross-correlations)

6. Estensioni naturali​

  1. GMM con BIC in alternativa a KMeans+silhouette.
  2. DBSCAN/HDBSCAN per cluster non sferici e detection di noise nativo.
  3. Soglia per asset: ogni asset ha la sua distribuzione; un percentile globale Γ¨ sub-ottimale.
  4. Feature multivariate: cross-correlation fra sensori, FFT su finestre brevi.
  5. Modelli sequenziali (LSTM autoencoder) per collective anomalies.
  6. Drift detection (KS-test) + retraining schedulato.
  7. API REST (FastAPI) che espone detect_anomalies().