-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
This page is the structural reference for eruption_forecast: every module under src/,
the top-level pipeline, how the model and ensemble classes relate, what flows between
stages on disk, and the utility surface that holds the rest together.
src/eruption_forecast/
βββ __init__.py - public exports
βββ logger.py - loguru wrapper (enable/disable/set_level/set_directory) + per-category error files (register_error_category, get_category_logger; telegram category ships pre-registered)
βββ data_container.py - BaseDataContainer ABC for TremorData / LabelData
β
βββ config/
β βββ base_config.py - shared config primitives
β βββ constants.py - ERUPTION_PROBABILITY_THRESHOLD, defaults
β βββ forecast_config.py - ForecastConfig + per-stage sub-configs
β βββ training_config.py - TrainingConfig (standalone TrainingModel)
β βββ prediction_config.py - PredictionConfig (standalone PredictionModel)
β βββ evaluation_config.py - EvaluationConfig (standalone EvaluationModel)
β βββ explanation_config.py - ExplanationConfig (standalone ExplanationModel)
β
βββ dataclass/
β βββ station_data.py - StationData (immutable nslc identity)
β βββ classifier_ensemble_summary.py - ClassifierEnsembleSummary, EruptionWindow, SeedSummary, ProbabilityPick
β βββ classifier_explanation.py - SeedExplanation, ClassifierExplanation (SHAP payloads)
β
βββ decorators/
β βββ notify.py - @notify decorator (Telegram success/error notifications)
β βββ timer.py - @timer decorator (elapsed-time logger, optional Telegram forward)
β
βββ notification/
β βββ telegram.py - TelegramNotification (send_message / send_document / send_photo / send_media_group)
β
βββ ensemble/
β βββ base_ensemble.py - BaseEnsemble (joblib save/load mixin)
β βββ seed_ensemble.py - SeedEnsemble (one classifier Γγ°γ€ N seeds)
β βββ classifier_ensemble.py - ClassifierEnsemble (N classifiers)
β βββ metrics_ensemble.py - MetricsEnsemble (metrics engine)
β βββ explainer_ensemble.py - ExplainerEnsemble (per-seed SHAP engine)
β
βββ features/
β βββ constants.py
β βββ tremor_matrix_builder.py - TremorMatrixBuilder (windowed alignment)
β βββ features_builder.py - FeaturesBuilder (tsfresh extraction)
β βββ feature_selector.py - FeatureSelector (tsfresh FDR or RF importance)
β βββ feature_count_sweep.py - β Experimental. FeatureCountSweep + sweep_feature_count (post-hoc top_n_features recommender)
β
βββ label/
β βββ constants.py
β βββ label_builder.py - LabelBuilder (sliding window)
β βββ dynamic_label_builder.py - DynamicLabelBuilder (per-eruption build)
β βββ label_data.py - LabelData (CSV wrapper)
β
βββ model/
β βββ constants.py
β βββ base_model.py - BaseModel ABC (dates, I/O, dual-mode save/load + cache identity)
β βββ forecast_model.py - ForecastModel orchestrator
β βββ training_model.py - TrainingModel(BaseModel)
β βββ prediction_model.py - PredictionModel(BaseModel)
β βββ evaluation_model.py - EvaluationModel(BaseModel)
β βββ explanation_model.py - ExplanationModel(BaseModel)
β βββ classifier_model.py - ClassifierModel (estimator + grid)
β βββ classifier_comparator.py - ClassifierComparator (cross-classifier rank)
β
βββ plots/
β βββ styles.py
β βββ tremor_plots.py - plot_tremor
β βββ feature_plots.py - feature-importance plots
β βββ forecast_plots.py - plot_forecast, plot_forecast_from_file
β βββ evaluation_plots.py - ROC, PR, confusion, threshold, importance
β βββ explanation_plots.py - SHAP waterfall / beeswarm / bar / aggregate
β βββ label_plots.py - plot_label_distribution + scenario comparison
β
βββ sources/
β βββ base.py - SeismicDataSource ABC
β βββ sds.py - Local SeisComP archive reader
β βββ fdsn.py - FDSN client with local SDS caching
β
βββ tremor/
β βββ calculate_tremor.py - CalculateTremor (orchestrator)
β βββ rsam.py, dsar.py, shannon_entropy.py - per-metric kernels
β βββ tremor_data.py - TremorData (CSV wrapper)
β
βββ utils/
βββ array.py, benchmark.py, dataframe.py, date_utils.py
βββ formatting.py, ml.py, pathutils.py
βββ validation.py, window.py
ββββββββββββββββ ββββββββββββββββββββββ βββββββββββββββββββ
β Seismic β β CalculateTremor β β TremorData β
β archive β βββΊ β (rsam/dsar/ β ββΊ β (CSV wrapper) β
β (SDS|FDSN) β β entropy/bands) β β β
ββββββββββββββββ ββββββββββββββββββββββ ββββββββββ¬βββββββββ
β
ββββββββββββββββββββββββββββ feature pipeline βββββββββββ΄ββββββ
β LabelBuilder TremorMatrixBuilder β
β DynamicLabelBuilder βββΊ FeaturesBuilder (tsfresh) β
β FeatureSelector (FDR or RF) β
ββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
βΌ
ββββββββββββββββββββββββββ
β TrainingModel β
β build_label β β
β extract_features β β
β fit (N seeds Γγ°γ€ M cv) β
ββββ¬ββββββββββββββββββββ¬ββ
β writes β assembles
βΌ βΌ
ββββββββββββββββββ ββββββββββββββββββββββββββ
β SeedEnsemble Γγ°γ€ β β ClassifierEnsemble β
β N classifiers β ββΊ β (all SeedEnsembles) β
ββββββββββββββββββ ββββββββββββ¬ββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββ
β PredictionModel β
β build_label β β
β extract_features β β
β forecast (per-seed proba) β
ββββββββββββββββ¬ββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββ΄βββββββββββββββββββ
βΌ βΌ
ββββββββββββββββββββββββ ββββββββββββββββββββββββββ
β EvaluationModel β β forecast-results_ β
β dispatch on .kind: β β *.csv + forecast β
β training | predict β ββ MetricsEnsemble βββΊ β PNG/PDF β
ββββββββββββ¬ββββββββββββ ββββββββββββββββββββββββββ
β writes (n_samples, n_seeds) y_proba / y_pred matrices
βΌ
ββββββββββββββββββββββββ
β ClassifierComparator β ranking_*.csv + comparison figures
ββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ExplanationModel (BaseModel) β
β dispatch on upstream model.kind: training | prediction β
β β
β ExplainerEnsemble β
β β per-seed shap.TreeExplainer (RF / lite-rf / GB / XGB) β
β β ClassifierExplanation.pkl per classifier β
β β per-seed bar + beeswarm under classifiers/{Clf}/figures β
β β per-eruption waterfall under eruptions/{date}/ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ForecastModel is the orchestrator that calls every box in sequence.
The dashed arrows are also the method-chain order:
fm.calculate(...).train(...).predict(...).evaluate(...).explain(...).
CalculateTremor reads seismic traces day-by-day from a SeismicDataSource and
dispatches each day to the configured tremor kernels (rsam.py, dsar.py, shannon_entropy.py).
Per-day CSVs are written to tremor/daily/, then concatenated into the merged tremor
CSV at the station root. TremorData is a thin wrapper that exposes df, start_date, end_date,
sampling-rate validation, and the CSV filename / basename / filetype triple.
Two builders share the same output shape (id, is_erupted) but differ in how positives are placed:
-
LabelBuilder- sliding window over the full date range;day_to_forecastcontrols the look-ahead window.include_eruption_date=False(default) still marks the eruption day as positive, givingday_to_forecast + 1positive days per eruption. -
DynamicLabelBuilder- extendsLabelBuilderwith a per-eruption three-phase build: (1) zero frames per eruption, (2) concat + deduplicate datetimes, (3) mark positives per eruption. Solves the issue where overlapping look-ahead windows collide inLabelBuilder.
LabelBuilder - one global window over the full date range
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
include_eruption_date=False (default)
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1
β β β
dtf start day-before eruption
eruption (also 1)
β dtf days strictly before eruption + eruption day = dtf+1 positives
include_eruption_date=True
0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
β β
dtf start eruption (counted in dtf)
β exactly dtf days ending on the eruption day
DynamicLabelBuilder - per-eruption build, overlapping windows deduped
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Phase 1: initiate (all zeros)
Eruption A window Eruption B window
[0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0]
Phase 2: concat + deduplicate datetimes
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] β unified, sorted, unique
Phase 3: mark positives per eruption
Erup A (2025εΉ΄03ζ20ζ₯, dtf=2): Mar 18β20 β 1
Erup B (2025εΉ΄03ζ23ζ₯, dtf=2): Mar 21β23 β 1
[0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1]
β β
Erup A Erup B
LabelData parses parameters (window_size, window_step, window_step_unit, day_to_forecast)
directly out of the label filename so a CSV alone is enough to rehydrate the build context.
labels (id, is_erupted) tremor_df
β β
βΌ βΌ
ββββββββββββββββββββββββββββββββββββββββββ
β TremorMatrixBuilder β
β windowed slices aligned to labels β
ββββββββββββββββββββββ¬ββββββββββββββββββββ
βΌ
ββββββββββββββββββββββββββββββββββββββββββ
β FeaturesBuilder β
β tsfresh extraction (per-column) β
β training: relevance-filter on labels β
β prediction: no filtering β
ββββββββββββββββββββββ¬ββββββββββββββββββββ
βΌ
ββββββββββββββββββββββββββββββββββββββββββ
β FeatureSelector β
β method="tsfresh": FDR p-value filter β
β method="random_forest": permutation β
β importance β
β β top-N feature names per seed β
ββββββββββββββββββββββββββββββββββββββββββ
TremorMatrixBuilder.build() validates sample counts per window against minimum_completion
and skips short windows so tsfresh never sees ragged input.
FeaturesBuilder runs per-column independent extractions so adding a new tremor
band does not invalidate the cached results for the others.
The model layer follows a mixin pattern:
-
BaseModel- abstract base for every stage. Owns the date/window grid, the lazytremor_dataaccessor,output_dirresolution,n_jobsclamping, the content-addressable cache identity helpers (build_identity,compute_hash,_canonicalize,tremor_fingerprint,cache_path), and the dual-mode joblibsave(identity=None, path=None)/ cache-onlyload(stage_dir, identity). Whenidentityis supplied,save()writes to{stage_dir}/{hash}.{ClassName}.pkl(plus a.params.jsonsidecar). Whenidentityis omitted, the legacy{output_dir}/{ClassName}_{basename}.pkljoblib dump is preserved for standalone manual saves. Subclasses implementset_directories,create_directories,validate,describe,to_dict,to_prompt,build_label,extract_features, and overridestage_dir+build_identitywhen they participate in the cache. -
TrainingModel(BaseModel)-build_label β extract_features β fit.fit()runs per-seedGridSearchCVinjoblib.Parallelover the selected classifiers, writes a per-classifier trained-model JSON registry viasave_model_json, bundles every seed into aSeedEnsembleand every classifier into aClassifierEnsemble, then callsself.save(self.build_identity())so the cache pickle lands at{training_dir}/{hash}.TrainingModel.pklwith a matching sidecar. -
PredictionModel(BaseModel)-build_label β extract_features β forecast. Cache identity embeds the upstreamtraining_hash(a constructor param threaded byForecastModel.predict), so re-training automatically invalidates downstream forecasts.forecast()callsself.save(self.build_identity()); cache files live at{prediction_dir}/{hash}.PredictionModel.pkl. -
EvaluationModel(BaseModel)- no cache; dispatches onmodel.kind("training"or"prediction"). Output is namespaced underevaluation/{kind}/so both modes can coexist. -
ExplanationModel(BaseModel)- per-seed SHAP explanations over a fittedClassifierEnsemble. Reuses the upstreamTrainingModelorPredictionModeland dispatches onmodel.kind. Restricted to tree classifiers (RF / lite-rf / GB / XGB); non-tree classifiers are skipped at theExplainerEnsembleloop with a warning. Output is namespaced underexplanation/{kind}/; cache pickles land at{explanation_dir}/{hash}.ExplanationModel.pkl(already mode-namespaced so training-reuse and prediction-reuse caches never collide). -
ForecastModel- the orchestrator. Not aBaseModelsubclass - it ownsCalculateTremor, builds the four stage classes lazily, and captures stage kwargs into aForecastConfigfor round-tripping.
ClassifierModel is the per-classifier descriptor (sklearn estimator + hyperparameter grid + slug).
ClassifierComparator consumes the in-memory MetricsEnsemble cached on EvaluationModel to rank classifiers head-to-head.
BaseEnsemble (joblib save/load mixin)
β
ββββββββββ΄βββββββββ
βΌ βΌ
SeedEnsemble ClassifierEnsemble
1 classifier Γγ°γ€ N classifiers Γγ°γ€
N fitted seeds 1 SeedEnsemble each
+ per-seed + features (sorted union
feature lists across all SeedEnsembles)
+ features + factories (from_any, from_json,
(sorted union from_dict, from_seed_ensembles)
across all
seeds)
MetricsEnsemble (standalone - not a BaseEnsemble subclass)
wraps ClassifierEnsemble + features + y_true
writes only (n_samples, n_seeds) y_proba / y_pred CSV matrices
metrics / y_probas / y_preds stay in memory
ExplainerEnsemble (standalone - not a BaseEnsemble subclass)
wraps ClassifierEnsemble + features
writes per-classifier ClassifierExplanation.pkl
+ per-seed shap_values/{seed:05d}.pkl
+ per-seed bar / beeswarm + per-eruption waterfall plots
MetricsEnsemble and ExplainerEnsemble are both deliberately kept out of ensemble/__init__.py and imported via their full module paths (eruption_forecast.ensemble.metrics_ensemble, eruption_forecast.ensemble.explainer_ensemble) to keep the subpackage free of import cycles back through utils.ml and plots/.
SeismicDataSource is the read interface: get(date) -> obspy.Stream. Two concrete implementations:
-
SDS- pure local read from{root}/{year}/{network}/{station}/{channel}.D/{file}. -
FDSN- pulls from a remote FDSN service, then caches the downloaded MSEED into a local SDS layout (download_dir). Repeat calls with the same date hit the local cache.
apply_nature_style() normalises every figure to a Nature/Science-friendly palette and font stack.
Each plot module is a thin functional wrapper around matplotlib (and seaborn where appropriate) - see Visualization for the catalog and output paths.
ForecastConfig is the round-trip record for ForecastModel. Its six sub-configs match the stage method signatures one-for-one:
ForecastConfig
βββ model: BaseForecastConfig
βββ calculate: ForecastCalculateConfig | None
βββ train: ForecastTrainConfig | None
βββ predict: ForecastPredictConfig | None
βββ evaluate: ForecastEvaluateConfig | None
βββ explain: ForecastExplainConfig | None
TrainingConfig, PredictionConfig, EvaluationConfig, and ExplanationConfig each mirror their stage model's __init__ directly and are the standalone equivalents used when the model runs outside ForecastModel. Every stage model auto-calls save_config() at the end of its main run method (fit() / forecast() / evaluate() / explain()), so a standalone run always leaves a YAML snapshot next to its artefacts. The upstream model parameter on EvaluationConfig and ExplanationConfig is intentionally omitted because it is always a live model instance.
notify(task) wraps a function with success and error Telegram messages (MarkdownV2 body, hostname, elapsed time, exception details). timer(name, send_to=None) logs the wrapped function's elapsed wall-clock time via loguru; passing send_to="telegram" also mirrors the message to Telegram.
Both decorators delegate to TelegramNotification (notification/telegram.py), a fluent-chain client wrapping the Telegram Bot API. It exposes send_message(...), send_document(...), send_photo(...), and send_media_group(...); every send method returns self so calls can be chained (tn.send_message(...).send_document(...)). Credentials are resolved from constructor arguments or the TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID environment variables. Every network failure is logged and swallowed, so a dead network never blocks the caller. scenarios.py uses this class directly to ship each per-scenario forecast PNG next to a title message.
Nine focused modules that the rest of the codebase pulls from - see the table in 6.
βββββββββββββββββββββββββββ
β BaseModel β
β (ABC) β
β β’ dates, output_dir β
β β’ tremor_data (lazy) β
β β’ n_jobs clamp β
β β’ save() / load() β
ββββββββββββββ¬βββββββββββββ
β inherits
ββββββββββββββββββ¬ββββββββββββΌββββββββββββββββ¬βββββββββββββββββ
βΌ βΌ βΌ βΌ βΌ
βββββββββββββββββ βββββββββββββββββ ββββββββββββββββ βββββββββββββββββββββ
β TrainingModel β βPredictionModelβ βEvaluationMdl β β ExplanationModel β
β (BaseModel) β β (BaseModel) β β(BaseModel) β β (BaseModel) β
β β β β β β β β
β build_label β β β build_label β β β dispatch on β β explain β β
β extract_feat ββ β extract_feat ββ β model.kind β β ExplainerEns. β
β fit (N seeds) β β forecast β β evaluate/ β β plot β β
β β β β β compare β β per-seed + β
β β β β β β β waterfall β
ββββββββββ¬βββββββ ββββββββββ¬βββββββ ββββββββ¬ββββββββ ββββββββββ¬βββββββββββ
β produces β consumes β uses β reuses
βΌ β βΌ β
ββββββββββββββββββββββββββ β ββββββββββββββββββββββββββ β
β ClassifierEnsemble βββ β MetricsEnsemble β β
β βββββββββββββββββββ β β β’ (n_samples Γγ°γ€ n_seeds)β β
β β’ from_any / from_jsonβ β y_proba / y_pred CSV β β
β β’ from_seed_ensembles β β β’ metrics in memory β β
ββββββββββββ¬ββββββββββββββ βββββββββββββ¬βββββββββββββ β
β bundles β aggregates β
βΌ βΌ βΌ
ββββββββββββββββββββββββββ ββββββββββββββββββββββββββ ββββββββββββββββββββ
β SeedEnsemble Γγ°γ€ M β β ClassifierComparator β β ExplainerEnsembleβ
β βββββββββββββββββββββ β β β’ get_ranking() β β β’ TreeExplainer β
β β’ predict_proba β β β’ plot_all() β β per seed β
β β’ predict_with_ β ββββββββββββββββββββββββββ β β’ ClassifierExplnβ
β uncertainty β β per classifier β
ββββββββββββ¬ββββββββββββββ ββββββββββββββββββββ
β inherits
βΌ
βββββββββββββββββββββββββββ
β BaseEnsemble β
β (joblib save/load) β
βββββββββββββββββββββββββββ
Scope cheat-sheet:
| Class | Scope (per ...) | Mixin / Inheritance | Cache |
|---|---|---|---|
BaseModel |
- | ABC (cache identity + dual-mode save/load) | self |
BaseEnsemble |
- | mixin | β |
TrainingModel |
One date span | BaseModel |
β |
PredictionModel |
One forecast window grid | BaseModel |
β |
EvaluationModel |
One trained model | BaseModel |
β |
ExplanationModel |
One trained ensemble | BaseModel |
β |
SeedEnsemble |
1 classifier Γγ°γ€ N seeds | BaseEnsemble |
β |
ClassifierEnsemble |
M classifiers Γγ°γ€ N seeds | BaseEnsemble |
β |
MetricsEnsemble |
1 ensemble Γγ°γ€ 1 dataset | standalone | β |
ExplainerEnsemble |
1 ensemble Γγ°γ€ 1 dataset | standalone | β |
ClassifierComparator |
M classifiers, post-eval | standalone | β |
ForecastModel |
Full pipeline | standalone orchestrator | via stages |
| Stage | Driver class | Reads | Writes |
|---|---|---|---|
| Tremor | CalculateTremor |
SeismicDataSource.get(date) |
tremor/daily/*.csv, merged {nslc}_{start}_{end}.csv
|
| Label | LabelBuilder |
Tremor index, eruption dates | training/features/{cv}/features-label_*.csv |
| Tremor matrix | TremorMatrixBuilder |
Tremor CSV + labels |
training/tremor/tremor_matrix_*.csv (+ per_method/) |
| Features | FeaturesBuilder |
Tremor matrix | training/features/{cv}/features-matrix_*.parquet |
| Feature selection | FeatureSelector |
Features + labels |
training/features/{cv}/seed/{seed:05d}.csv + top_N_features.csv
|
| Training fit | TrainingModel |
Selected features + labels |
training/classifiers/{clf}/{cv}/models/*.pkl + SeedEnsemble_*.pkl + ClassifierEnsemble_*.{pkl,json}
|
| Prediction grid | PredictionModel |
Tremor CSV + window grid | prediction/features/features-{matrix,label}_*.csv |
| Forecast | PredictionModel.forecast |
Forecast features + ensemble |
prediction/results/{clf}/{seed:05d}.csv + forecast-results_*.csv + prediction/figures/forecast_*.{png,pdf}
|
| Evaluation | EvaluationModel.evaluate |
y_proba + y_true |
evaluation/{kind}/classifiers/{Clf}/predictions/{y_proba,y_pred}.csv + figures/aggregate/{plot}.{png,csv} + (when plot_per_seed=True) figures/{plot}/{seed:05d}.png
|
| Compare | ClassifierComparator |
Cached MetricsEnsemble
|
evaluation/{kind}/comparison/metrics/ranking_*.csv + comparison/figures/*.png
|
| Explanation | ExplanationModel.explain |
ClassifierEnsemble + features |
explanation/{kind}/classifiers/{Clf}/ClassifierExplanation_*.pkl + shap_values/{seed:05d}.pkl + figures/{bar,beeswarm}/{seed:05d}.png
|
| Waterfalls | ExplainerEnsemble.plot_waterfall |
ClassifierExplanation + eruption dates |
explanation/{kind}/eruptions/{date}/{Clf}_{datetime}_seed=_index=.png |
ββββββββββββββββββββββββββββββββββββββββββ
β tremor/{nslc}_{start}_{end}.csv β β CalculateTremor
βββββββββββ¬βββββββββββββββββββββββββββββββ
β used by Training / Prediction / Evaluation
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β training/ β
β features/{cv}/ β
β features-matrix_*.parquet βββΊ features-label_*.csv β
β β β
β βΌ β
β seed/{seed:05d}.csv βββΊ resampled/{seed:05d}.csv β
β significant_features.csv βββΊ top_features.csv β
β βββΊ top_{N}_features.csv + .png β
β β
β classifiers/ β
β {clf}/{cv}/models/{seed:05d}.pkl β
β {clf}/{cv}/SeedEnsemble_*.pkl β
β ClassifierEnsemble_{cv}.{pkl,json} β
βββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ClassifierEnsemble bundle
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β prediction/ β
β features/features-matrix_*.parquet + features-label_*.csv β
β results/{clf}/{seed:05d}.csv β
β figures/forecast_*.{png,pdf} β
β forecast-results_*.csv (top-level dump) β
βββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ClassifierEnsemble + features + y_true (rebuilt or training-derived)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β evaluation/{training|prediction}/ β
β classifiers/{Clf}/ β
β predictions/{y_proba,y_pred}.csv (n_samples Γγ°γ€ n_seeds) β
β figures/aggregate/{plot_name}.{png,csv} β
β figures/{plot_name}/{seed:05d}.png (plot_per_seed=True) β
β labels/y_true.csv (prediction reuse only)β
β MetricsEnsemble.pkl (optional, via save()) β
β comparison/ β
β metrics/ranking_*.csv β
β figures/*.png β
βββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ClassifierEnsemble + features
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β explanation/{training|prediction}/ β
β classifiers/{Clf}/ β
β ClassifierExplanation_{Clf}.pkl β
β shap_values/{seed:05d}.pkl β
β figures/{bar,beeswarm}/{seed:05d}.png β
β eruptions/{YYYY-MM-DD}/ β
β {Clf}_{datetime}_seed=_index=.png β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Stage-internal caches (no separate cache/ subtree): β
β training/{hash}.TrainingModel.pkl + .params.json β β BaseModel.save
β prediction/{hash}.PredictionModel.pkl + .params.json β
β explanation/{kind}/{hash}.ExplanationModel.pkl + sidecarβ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
A cache hit on TrainingModel short-circuits everything in the training/ box;
a cache hit on PredictionModel short-circuits the prediction/ box;
a cache hit on ExplanationModel short-circuits the per-classifier SHAP pass.
Evaluation is never cached - the on-disk matrices act as the cache and MetricsEnsemble.compute() is idempotent in memory once y_probas is populated.
| Module | Key functions |
|---|---|
utils/array.py |
detect_maximum_outlier, remove_maximum_outlier, remove_outliers, detect_anomalies_zscore, mask_zero_values, filter_nans, count_valid_values, get_completeness, confidence_interval, compute_model_probabilities, save_forecast_seed
|
utils/benchmark.py |
benchmark_feature_selection (side-by-side FeatureSelector method comparison) |
utils/window.py |
construct_windows, calculate_window_metrics, get_windows_information, chunk_daily_data, shannon_entropy, to_safe_array
|
utils/date_utils.py |
to_datetime, normalize_dates, sort_dates, parse_label_filename, to_datetime_index
|
utils/ml.py |
random_under_sampler, resample, load_features_resampled, temporal_train_test_split, get_significant_features, get_classifier_models, grid_search_cv, save_model_json, compute_seed, build_y_true, build_classifier_ensemble_summary, compute_threshold_metrics, compute_aggregate_threshold_metrics
|
utils/validation.py |
validate_random_state, validate_date_ranges, validate_window_step, validate_columns, check_sampling_consistency
|
utils/pathutils.py |
pdf_metadata, resolve_output_dir, ensure_dir, save_figure, save_figure_as_pdf, save_data, load_json, load_pickle, setup_nslc_directories, generate_features_filepaths
|
utils/dataframe.py |
load_label_csv, load_datetime_indexed, load_features_matrix, load_select_features, load_feature_aliases, update_top_features_csv, concat_features, concat_significant_features, find_common_features, merge_features_matrix, get_envelope_values, remove_anomalies, to_series
|
utils/formatting.py |
slugify, slugify_class_name, shorten_feature_name, humanize_feature_name, get_classifier_label
|
utils/ml.save_model_json writes the per-classifier trained-model JSON registry (one record per seed, each with the inline top-N feature list and the path to the seed's .pkl). TrainingModel.build_seed_ensemble reads that registry via SeedEnsemble.from_any to package every seed into a SeedEnsemble, and the per-classifier SeedEnsembles are then merged into a ClassifierEnsemble (build_classifier_ensemble). All three steps run at the end of TrainingModel.fit().
utils/formatting.slugify is what turns "Scenario 1" into scenario-1 for the per-scenario output_dir used in scenarios.py.