-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
src/eruption_forecast/
├── data_container.py # BaseDataContainer — shared ABC for TremorData & LabelData
├── tremor/ # Seismic tremor processing
│ ├── calculate_tremor.py # CalculateTremor — main orchestrator
│ ├── rsam.py # Real Seismic Amplitude Measurement
│ ├── dsar.py # Displacement Seismic Amplitude Ratio
│ ├── shanon_entropy.py # Shannon Entropy metric
│ └── tremor_data.py # TremorData — wraps tremor CSV
├── label/ # Training label generation
│ ├── label_builder.py # LabelBuilder — sliding window labelling
│ └── label_data.py # LabelData — wraps label CSV
├── features/ # Feature extraction & selection
│ ├── features_builder.py # FeaturesBuilder — tsfresh extraction
│ ├── feature_selector.py # FeatureSelector — 3-method selection
│ └── tremor_matrix_builder.py # TremorMatrixBuilder — windowed alignment
├── model/ # ML model training & prediction
│ ├── forecast_model.py # ForecastModel — full pipeline orchestrator
│ ├── model_trainer.py # ModelTrainer — multi-seed training
│ ├── model_predictor.py # ModelPredictor — inference & forecasting
│ ├── model_evaluator.py # ModelEvaluator — single-seed evaluation
│ ├── multi_model_evaluator.py # MultiModelEvaluator — aggregate evaluation
│ ├── seed_ensemble.py # SeedEnsemble — all seeds, 1 classifier
│ ├── classifier_ensemble.py # ClassifierEnsemble — N SeedEnsembles
│ └── classifier_model.py # ClassifierModel — classifier + grid management
├── sources/ # Seismic data source adapters
│ ├── base.py # SeismicDataSource — abstract base class
│ ├── sds.py # SDS reader (SeisComP Data Structure)
│ └── fdsn.py # FDSN web service client with local caching
├── config/ # Pipeline configuration
│ └── pipeline_config.py # PipelineConfig + sub-config dataclasses
├── plots/ # Visualization utilities
│ ├── tremor_plots.py
│ ├── feature_plots.py
│ ├── evaluation_plots.py
│ └── shap_plots.py
├── utils/ # Focused utility modules
│ ├── array.py # Z-score outlier detection
│ ├── window.py # Sliding window construction
│ ├── date_utils.py # Date conversion and filename parsing
│ ├── dataframe.py # DataFrame helpers
│ ├── ml.py # Resampling and feature utilities
│ ├── validation.py # Centralised validation (dates, random state, columns, sampling)
│ ├── pathutils.py # Path resolution relative to root_dir
│ └── formatting.py # Text formatting
└── decorators/ # Function decorators
└── notify.py # Telegram notification decorator
| Principle | What it means in practice |
|---|---|
| Single Responsibility | Each module has one purpose — rsam.py only computes RSAM, date_utils.py only handles dates |
| DRY (Don't Repeat Yourself) | Shared behaviour extracted into base classes (BaseDataContainer, SeismicDataSource) and utilities (validate_random_state, load_labels_from_csv) |
| Explicit Imports | No hidden re-exports; import exactly what you need: from eruption_forecast.utils.date_utils import to_datetime
|
| Minimal Dependencies | Each utility module imports only its own direct dependencies |
| Fluent API | All pipeline classes support method chaining via return self
|
| Data Leakage Prevention | Train/test split always happens before resampling and feature selection |
| Cached Properties |
TremorData and LabelData use @cached_property so attributes are computed once |
Raw Seismic Data (SDS / FDSN)
│
▼
┌─────────────────────┐
│ CalculateTremor │ RSAM + DSAR + Entropy → tremor.csv
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ LabelBuilder │ Binary labels → label_*.csv
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ TremorMatrixBuilder │ Windowed matrix → tremor_matrix_*.csv
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ FeaturesBuilder │ 700+ features → all_extracted_features_*.csv
└─────────┬───────────┘
│
▼
┌─────────────────────────────────────────────┐
│ ModelTrainer │
│ ┌─────────────┐ ┌──────────────────────┐ │
│ │FeatureSelect│ │ ClassifierModel │ │
│ │ or │ │ (10 classifiers, │ │
│ │ combined │ │ 3 CV strategies) │ │
│ └─────────────┘ └──────────────────────┘ │
│ ↓ train_and_evaluate() ↓ train() │
│ 80/20 split + metrics Full dataset │
└─────────┬───────────────────────────────────┘
│ trained_model_*.csv + *.pkl
│
│ (optional) trainer.merge_models()
│ → merged_model_*.pkl (SeedEnsemble)
▼
┌─────────────────────────────────────────────┐
│ ModelPredictor │
│ ┌──────────────────────────────────────┐ │
│ │ predict() / predict_best() │ │
│ │ (evaluation mode — requires labels) │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ predict_proba() │ │
│ │ (forecast mode — no labels needed) │ │
│ └──────────────────────────────────────┘ │
│ Single model, merged pkl, or multi-model │
│ consensus │
└─────────────────────────────────────────────┘
workflow.py is the top-level research script. It runs the full pipeline in two
parallel branches (train-with-evaluation and train-for-forecast), guarded by
boolean stage flags so any completed stage can be skipped on re-runs.
┌─────────────────────────────────────────────────────────────────────────────┐
│ workflow.py — Stage Flow │
└─────────────────────────────────────────────────────────────────────────────┘
[RUN_CALCULATE]
│
▼
┌─────────────────┐
│ Stage 1 │ CalculateTremor
│ calculate() │ SDS → RSAM / DSAR / Entropy → tremor_*.csv
│ │ dates: 2025年01月01日 → 2025年08月24日
└────────┬────────┘
│
│ for mode in ["train", "forecast"]:
│
├───────────────────────────────────────────────────────────────────┐
│ │
│ mode = "train" mode = "forecast" │
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ build_label() │ 2025年01月01日 → 2025年08月24日 │ build_label() │ 2025年01月01日 → 2025年07月27日
│ │ window_step=6h, dtf=2 │ │ window_step=6h, dtf=2
│ │ (full range — test split sees │ │ (shorter — leaves
│ │ all eruption events) │ │ forecast headroom)
└────────┬────────┘ └────────┬────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ extract_ │ FeaturesBuilder │ extract_ │ FeaturesBuilder
│ features() │ rsam_f2/f3/f4, dsar_f3-f4 │ features() │ (same kwargs)
│ │ 700+ tsfresh features → CSV │ │
└────────┬────────┘ └────────┬────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ train() │ ModelTrainer │ train() │ ModelTrainer
│ with_eval=True │ classifiers: lite-rf, rf │ with_eval=False│ (same classifiers)
│ │ cv: stratified, seeds: 100 │ │ cv: stratified, seeds: 100
│ │ 80/20 split → metrics JSON per seed │ │ full dataset → no metrics
│ │ → trainings/evaluations/... │ │ → trainings/predictions/...
└────────┬────────┘ └────────┬────────┘
│ │
│ [RUN_EVALUATE_PER_MODEL] ▼
▼ ┌─────────────────┐
┌─────────────────┐ │ forecast() │ ModelPredictor
│ MultiModel │ per-classifier aggregate plots │ │ predict_proba
│ Evaluator │ ROC, PR, calibration, confusion, │ │ 2025年07月28日 → 2025年08月20日
│ (loop per clf) │ SHAP beeswarm, seed stability, ... │ │ → predictions.csv
└────────┬────────┘ └─────────────────┘
│
│ [RUN_COMPARE_MODELS] (requires ≥ 2 classifiers)
▼
┌─────────────────┐
│ Classifier │ cross-classifier metric bar,
│ Comparator │ seed stability, ROC overlay,
│ │ comparison grid → ranking CSV
└────────┬────────┘
│
▼
┌─────────────────┐
│ save_config() │ [SAVE_CONFIG] → config_workflow.yaml
└─────────────────┘
Stage flags (module-level booleans):
┌──────────────────────────┬────────────────────────────────────────────┐
│ RUN_CALCULATE │ Stage 1 — tremor calculation │
│ RUN_EVALUATE_PER_MODEL │ MultiModelEvaluator plots per classifier │
│ RUN_COMPARE_MODELS │ ClassifierComparator cross-classifier plots │
│ SAVE_CONFIG │ Persist pipeline YAML │
└──────────────────────────┴────────────────────────────────────────────┘
CalculateTremor processes raw seismic data into tremor metrics:
- Reads seismic data from SDS (SeisComP Data Structure) format or FDSN web services
- Calculates three metrics across multiple frequency bands in parallel:
- RSAM (Real Seismic Amplitude Measurement): Mean amplitude per band
- DSAR (Displacement Seismic Amplitude Ratio): Ratio between consecutive bands
- Shannon Entropy: Signal complexity, single broadband column
- Default frequency bands:
(0.01-0.1), (0.1-2), (2-5), (4.5-8), (8-16) Hz - Supports multiprocessing via
n_jobs; outputs 10-minute interval CSVs
Key classes:
-
CalculateTremor: Main orchestrator (calculate_tremor.py) -
RSAM: Mean amplitude metrics (rsam.py) -
DSAR: Amplitude ratios between bands (dsar.py) -
ShanonEntropy: Signal complexity metric (shanon_entropy.py) -
TremorData: Loads and validates tremor CSV files (tremor_data.py) -
SDS: Reads SeisComP Data Structure files (sources/sds.py) -
FDSN: Downloads seismic data from FDSN web services with local SDS caching (sources/fdsn.py)
Workflow:
from eruption_forecast.tremor.calculate_tremor import CalculateTremor # From SDS archive calculate = CalculateTremor( station="OJN", channel="EHZ", start_date="2025-01-01", end_date="2025-01-03", n_jobs=4 ).from_sds(sds_dir="/path/to/sds").run() # Output CSV columns: rsam_f0, rsam_f1, dsar_f0-f1, entropy, etc. # From FDSN web service calculate = CalculateTremor( station="OJN", channel="EHZ", start_date="2025-01-01", end_date="2025-01-03", ).from_fdsn(client_url="https://service.iris.edu").run()
LabelBuilder generates binary labels for supervised learning:
- Creates sliding time windows and labels them erupted (1) or not (0)
- Uses
day_to_forecastto look ahead N days before eruptions - Label filenames follow:
label_YYYY-MM-DD_YYYY-MM-DD_ws-X_step-X-unit_dtf-X.csv
Key classes:
-
LabelBuilder: Creates labeled windows (label_builder.py) -
LabelData: Loads label CSV and parses parameters from filename (label_data.py)
TremorMatrixBuilder slices tremor time-series into windows aligned with labels:
- Takes tremor DataFrame and label DataFrame as input
- Validates sample counts per window
- Concatenates all windows into a unified matrix with
id,datetime, and tremor columns
FeaturesBuilder extracts tsfresh features from the tremor matrix:
- Operates in two modes:
- Training mode (labels provided): Filters windows to match labels, saves aligned label CSV
- Prediction mode (no labels): Extracts all features, disables relevance filtering
- Runs tsfresh extraction per tremor column independently
Key classes:
-
FeaturesBuilder: Orchestrates tsfresh feature extraction (features_builder.py) -
FeatureSelector: Two-stage selection — tsfresh (statistical FDR) → RandomForest (importance) (feature_selector.py)- Methods:
"tsfresh","random_forest","combined"
- Methods:
ModelTrainer trains classifiers across multiple random seeds:
- Supports 10 classifiers:
rf,gb,xgb,svm,lr,nn,dt,knn,nb,voting - CV strategies:
shuffle,stratified,timeseries - Uses
RandomUnderSamplerto handle class imbalance - Two training modes:
-
train_and_evaluate(): 80/20 split → resample train → feature selection → CV → evaluate on test set → save -
train(): Resample full dataset → feature selection → CV → save (no metrics)
-
Key classes:
-
ModelTrainer: Multi-seed training and evaluation (model_trainer.py)-
fit(with_evaluation=True): Dispatches totrain_and_evaluate()ortrain()based on flag -
n_jobs: outer seed workers;grid_search_n_jobs: innerGridSearchCV/FeatureSelectorworkers
-
-
ClassifierModel: Manages classifier instances and hyperparameter grids (classifier_model.py) -
ModelEvaluator: Computes metrics and plots for a fitted model (model_evaluator.py)- Methods:
get_metrics(),summary(),plot_all(),from_files() -
cv_nameparameter (default"cv"): slugified into the default output pathoutput/trainings/evaluations/{clf-slug}/{cv-slug}/whenoutput_dirisNone
- Methods:
-
MultiModelEvaluator: Aggregate evaluation across all seeds (multi_model_evaluator.py)- Methods:
plot_all(),plot_roc(),get_aggregate_metrics(),save_aggregate_metrics()
- Methods:
-
ModelPredictor: Runs inference in evaluation or forecast mode (model_predictor.py)-
predict()/predict_best(): Requires labels (evaluation mode) -
predict_proba(): Unlabelled forecasting with per-classifier + consensus output
-
-
PipelineConfig: Serialisable pipeline configuration (src/eruption_forecast/config/pipeline_config.py)
┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ TRAINING PHASE │
│ │
│ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ │
│ │ ModelTrainer (one classifier) │ │
│ │ │ │
│ │ .fit(with_evaluation=True) .fit(with_evaluation=False) │ │
│ │ │ │ │ │
│ │ train_and_evaluate() train() │ │
│ │ 80/20 split → resample full dataset → resample │ │
│ │ → feature select → CV → feature select → CV │ │
│ │ → eval on test set (no evaluation) │ │
│ └───────────────────┬──────────────────────────────────────────────────────────────────────────┘ │
│ │ produces (per seed) │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ trained_model_*.pkl │ metrics/*.json features/*.csv registry.csv │
│ └────────────┬───────────┘ │
│ │ │
│ ┌────────────┴─────────────────────────────────────────────┐ │
│ │ .merge_models() │ .merge_classifier_models() │
│ ▼ ▼ │
└──────────┼──────────────────────────────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────┐ ┌───────────────────────────────────────────────┐
│ SeedEnsemble │ │ ClassifierEnsemble │
│ (all seeds, 1 classifier) │◄───────────────────── │ (multiple SeedEnsembles, N classifiers) │
│ │ contains 1..N seeds │ │
│ .predict_proba(X) │ │ .from_seed_ensembles(dict) │
│ → (n_samples, 2) │ │ .from_registry_dict(dict) │
│ │ │ │
│ .predict_with_uncertainty │ │ .predict_proba(X) → consensus (n_samples, 2) │
│ → (mean, std, conf, pred)│ │ │
│ │ │ .predict_with_uncertainty(X) │
│ .save() / .load() │ │ → (mean, std, conf, pred, per_clf_dict) │
└─────────────────────────────┘ │ │
│ .classifiers .__getitem__ .__len__ │
│ .save() / .load() │
└───────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ EVALUATION PHASE │
│ │
│ ┌──────────────────────────┐ ┌────────────────────────────────┐ ┌────────────────────────┐ │
│ │ ModelEvaluator │ │ MultiModelEvaluator │ │ ClassifierComparator │ │
│ │ (1 fitted model/seed) │ │ (all seeds, 1 classifier) │ │ (N classifiers) │ │
│ │ │ │ │ │ │ │
│ │ .get_metrics() │ │ .get_aggregate_metrics() │ │ .get_ranking_table() │ │
│ │ .summary() │ │ .save_aggregate_metrics() │ │ .save_ranking_table() │ │
│ │ .plot_all() (8 plots) │ │ .plot_all() (10 plots) │ │ .plot_all() │ │
│ │ .from_files() │ │ ─────────────────────────── │ │ ──────────────────── │ │
│ │ ─────────────────────── │ │ reads: metrics/*.json │ │ wraps N instances of │ │
│ │ inputs: │ │ registry.csv │ │ MultiModelEvaluator │ │
│ │ fitted model │ │ │ │ (one per classifier) │ │
│ │ X_test, y_test │ │ outputs: │ │ │ │
│ │ selected_features │ │ aggregate_metrics.csv │ │ outputs: │ │
│ │ │ │ aggregate_*.png/.csv │ │ ranking_table.csv │ │
│ │ called internally by │ │ seed_stability_*.png │ │ comparison plots │ │
│ │ ModelTrainer per seed │ │ freq_band_contribution.png │ │ │ │
│ └──────────────────────────┘ └────────────────────────────────┘ └────────────────────────┘ │
│ ▲さんかく ▲さんかく ▲さんかく │
│ │ │ │ │
│ called per seed reads per-seed metrics reads per-clf │
│ during training & registry CSV metrics/registries │
└─────────────────────────────────────────────────────────────────────────────────────────────────────┘
SCOPE SUMMARY
─────────────────────────────────────────────────────────────────────────────
ModelEvaluator → 1 model, 1 seed, 1 classifier (micro)
MultiModelEvaluator → N models, N seeds, 1 classifier (per-classifier)
ClassifierComparator → N models, N seeds, N classifiers (cross-classifier)
SeedEnsemble → N seeds, 1 classifier (inference)
ClassifierEnsemble → N seeds, N classifiers (inference, consensus)
─────────────────────────────────────────────────────────────────────────────
Two abstract base classes establish shared contracts:
| Class | Module | Purpose |
|---|---|---|
BaseDataContainer |
data_container.py |
Abstract interface (start_date_str, end_date_str, data) shared by TremorData and LabelData
|
SeismicDataSource |
sources/base.py |
Abstract interface (get(date)) and shared _make_log_prefix(date) helper for SDS and FDSN
|
These classes are exported from the package root (from eruption_forecast import BaseDataContainer) and from eruption_forecast.sources respectively.
| Stage | Input | Output |
|---|---|---|
CalculateTremor |
Raw SDS/FDSN waveforms |
tremor_*.csv — DateTime index, RSAM/DSAR/entropy columns |
LabelBuilder |
Date range + eruption dates |
label_*.csv — DateTime index, id, is_erupted columns |
TremorMatrixBuilder |
tremor DataFrame + label DataFrame |
tremor_matrix_*.csv — long-format with id, datetime, tremor columns |
FeaturesBuilder |
tremor matrix + labels |
all_extracted_features_*.csv, label_features_*.csv
|
ModelTrainer |
features CSV + labels CSV |
models/*.pkl, trained_model_*.csv, metrics files |
ModelPredictor |
trained_model_*.csv + new tremor |
predictions.csv, eruption_forecast.png
|
| Module | Key Functions |
|---|---|
utils/array.py |
detect_maximum_outlier(), remove_outliers() — Z-score based |
utils/window.py |
construct_windows(), calculate_window_metrics()
|
utils/date_utils.py |
to_datetime(), normalize_dates(), parse_label_filename()
|
utils/ml.py |
random_under_sampler(), get_significant_features(), load_labels_from_csv()
|
utils/validation.py |
validate_random_state(), validate_date_ranges(), validate_window_step(), validate_columns(), check_sampling_consistency()
|
utils/pathutils.py |
resolve_output_dir() — resolves relative paths against root_dir
|
utils/dataframe.py |
DataFrame shape/column validation helpers |
utils/formatting.py |
Human-readable text formatting (elapsed time, file sizes, etc.) |
-
SeismicDataSource(sources/base.py): Abstract base class declaring theget(date)interface and_make_log_prefix(date)helper shared by all adapters. -
SDS(sds.py): Reads SeisComP Data Structure files directly from a local archive. Inherits fromSeismicDataSource. -
FDSN(fdsn.py): Downloads from any FDSN web service with transparent local SDS caching. Inherits fromSeismicDataSource.-
download_diris created automatically if absent - Downloaded files are cached as SDS miniSEED so subsequent runs skip the network
-
PipelineConfig holds sub-configs for each pipeline stage:
| Dataclass | Stage it covers |
|---|---|
ModelConfig |
ForecastModel constructor parameters |
CalculateConfig |
calculate() parameters |
BuildLabelConfig |
build_label() parameters |
ExtractFeaturesConfig |
extract_features() parameters |
TrainConfig |
train() parameters |
ForecastConfig |
forecast() parameters |
Configs are serialised to YAML or JSON via PipelineConfig.save() and loaded via ForecastModel.from_config(). See the Configuration wiki page.