Quickstart

This page walks through the core library API. Every step uses the norm route; swap in deriv1 / deriv2 to work on the derivative representations.

1. Build the processed data

The three route files are generated once from the bundled reference sources:

xpectra-process-raw            # writes processed_data/{norm,deriv1,deriv2}...csv.xz

2. Load labeled and unlabeled spectra

from xpectra import TrustConfig, load_labeled, load_unknown

trust = TrustConfig()
trust.ensure_dirs()

lab = load_labeled("norm", trust)
X, y, wn = lab["X_raw"], lab["y"], lab["wavenumbers"]
class_names = lab["class_names"]
study = lab["study"]

# 4,056 unlabeled weathered field spectra on the same wavenumber grid
unk = load_unknown("norm", lab["feature_columns"], wn, trust)
Xu = unk["X_raw"]

3. Calibrate a classifier (leakage-safe)

CalibratedModel keeps the StandardScaler inside the cross-validation used for calibration, so no fold ever sees test statistics.

from sklearn.model_selection import train_test_split
from xpectra import CalibratedModel, expected_calibration_error
from xpectra.protocols import get_estimator

X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
model = CalibratedModel(get_estimator("Random Forest (200)"), method="isotonic", cv=5).fit(X_tr, y_tr)
proba = model.predict_proba(X_te)
ece, table = expected_calibration_error(y_te, proba, n_bins=15)
print(f"ECE = {ece:.3f}")

4. Measure the generalization gap (LOSO)

from xpectra.protocols import run_generalization

res = run_generalization("XGBoost (100)", "norm", X, y, study, trust)
print(res["random_macro_f1"], res["loso_macro_f1_present"])

5. Detect out-of-distribution spectra and abstain

from xpectra import Mahalanobis, AbstainingClassifier, unknown_composition

detector = Mahalanobis(n_components=20).fit(X_tr, y_tr)
abstainer = AbstainingClassifier(model, detector)
abstainer.fit_tau(X_te, target_coverage=0.90)   # threshold from held-out data

labels, kept = abstainer.predict(Xu, class_names)
composition = unknown_composition(labels, class_names)
print(composition)

6. Weathering indicator

import numpy as np
from xpectra import carbonyl_index

ci = carbonyl_index(Xu, wn)                       # defaults match TrustConfig bands
print("median carbonyl index:", np.nanmedian(ci))

See API reference for the full reference and Study reproduction workflows to reproduce the complete study.