Skip to main content

Guide: Model Training

Once the feature set has been extracted, the SpectralClassifier class orchestrates model training, optimization, and evaluation. It encapsulates a complete scikit-learn / imblearn pipeline, supports about a dozen models, and automatically logs results to Weights & Biases.

Starting point

All training logic is in src/pipeline/classifier.py. The orchestration notebook is 00_master_pipeline.ipynb.


Quick start​

from src.pipeline.classifier import SpectralClassifier

# XGBoost training in pure spectroscopic mode
clf = SpectralClassifier(model_type="XGBoost", prediction_target="main_class")
clf, feature_cols, X, y = clf.train_and_evaluate(
features_df,
spectro_only=True, # excludes ra, dec, redshift and most Gaia columns (see §3)
)

# Save artifacts
clf.save_model("data/models/spectral_classifier_xgboost.pkl")

Reference result achieved in spectro_only=True mode:

BA
89.2%
Balanced accuracy
balanced accuracy · 5 classes
On types A, F, G, K, M
F1
0.883
Macro F1
test set · N = 60,947
Accuracy 87.4%
AUC
0.986
ROC-AUC macro
global discriminability
1.000 = perfect
ST_350k_xgb_AFGKM_v6 · run 20260522T161236Z · G2 · 349,998 spectra
v6 · includes 4 Gaia/photometric features — see Data Leakage Audit

1. Available models​

SpectralClassifier supports 11 classifiers through the model_type parameter. Switching models is trivial — the pipeline, tuning, and W&B logging adapt automatically.

"XGBoost"
89.2% BA · v6
Champion
XGBClassifier
Tree gradient boosting — AstroSpectro pipeline champion
"LightGBM"
Fast
LGBMClassifier
Leaf-wise gradient boosting — very fast on large datasets
"CatBoost"
Robust
CatBoostClassifier
Ordered gradient boosting — native handling of missing and categorical values
"ExtraTrees"
Fast
ExtraTreesClassifier
Extremely randomised trees — very fast, good diversification
"RandomForest"
Baseline
RandomForestClassifier
Random forests — historical project baseline
"Ensemble"
Combined
VotingClassifier
Soft vote XGB + LightGBM + ExtraTrees — best generalisation
"SVM"
Classic
SVC (calibrated)
Calibrated Support Vector Machine — good on small datasets, slow at scale
"MLP"
Neural
MLPClassifier
Dense multilayer network — lightweight neural alternative
"LogisticRegression"
Linear
LR multiclass
OvR logistic regression — interpretable linear baseline
"KNN"
Geometric
KNeighborsClassifier
K nearest neighbours — useful for spectral structure analysis
"LDA"
Classic
LinearDiscriminantAnalysis
Linear discriminant analysis — classic projective baseline
Switching models is trivial: SpectralClassifier(model_type="LightGBM") — the pipeline, tuning and W&B logging adapt automatically.
v6 · includes 4 Gaia/photometric features — see Data Leakage Audit

2. The training process​

Data preparation​

SpectralClassifier automatically prepares the data before training:

  1. Cleaning: Spectra without a valid subclass and classes with < 10 samples are excluded.
  2. Feature selection: In spectro_only=True mode, positional, observing-condition and most Gaia columns are filtered out (see §3 for the Gaia columns that remain).
  3. Train/test split: 80/20 stratified by class.

Pipeline and W&B tracking​

imblearn.Pipeline — fitted on X_train only · no leakage into X_test · hover for details
∅
SimpleImputer
Zero strategy
→
σ
StandardScaler
z-score on training set only
→
⊕
optional
SMOTE
(optional)
→
▶
Classifier
XGBoost / LightGBM / ...
The pipeline loaded from .pkl includes the scaler and imputer — no additional data preparation is required for prediction.

Hyperparameter tuning​

Option A — GridSearchCV (default):

# Stratified cross-validation k=5 · metric: balanced_accuracy
clf.train_and_evaluate(features_df, spectro_only=True)

Option B — Optuna (Bayesian optimization):

The Optuna infrastructure is deployed for large-scale exploration. It is especially useful for exploring n_estimators, max_depth, learning_rate, colsample, subsample, reg_alpha/lambda on the ~139k available spectra.

clf.train_and_evaluate(
features_df,
spectro_only=True,
tuner="optuna",
n_trials=200,
)

3. spectro_only=True mode​

Required for publications

Enable this mode for all rigorous scientific results. It ensures that the model learns to classify stars from their intrinsic physics only, without any observational bias.

clf.train_and_evaluate(features_df, spectro_only=True)

Automatically excluded features:

  • Angular coordinates: ra, dec
  • Observing conditions: redshift, seeing, snr_*, jd, fiber_id, magnitude_*
  • Gaia columns: parallax, bp_rp, teff_gspphot, logg_gspphot, v_tan_kms, etc.

ra, dec and redshift are excluded because they can correlate with spectral type through LAMOST observational biases (observation programs targeted by type) rather than through stellar physics. The exported run reports do not show a measurable accuracy gain from this exclusion: in the 100k runs, v3 (before spectro_only) and v4 (spectro_only) reach a balanced accuracy of 86.4% and 86.4% respectively, and v5 (spectro_only plus isotonic calibration) 87.3%.

In practice, spectro_only does not remove every Gaia column: the reference run still selected 4 Gaia/photometric features, among them M_G (also M_BP, M_RP and ag_gspphot), so M_G is not excluded in that run.

v6 · includes 4 Gaia/photometric features — see Data Leakage Audit

4. Saving and artifacts​

At the end of each run, the pipeline automatically generates the following files:

Artefact structure
📂data/
📁models/
└─📄spectral_classifier_xgboost_<ISO>.pkl
Main
~12 MB
📁reports/<ISO>/
└─📄spectral_classifier_xgboost_<ISO>_meta.json
Meta
└─📄confusion_matrix.png
Figure
Hover a file for description
📋
Contents of _meta.json
model_type
Classifier type
prediction_target
Prediction target
best_params_
Final hyperparameters
class_labels
Labels A/F/G/K/M
feature_names_used
Complete list of input features
selected_features_
Features retained after selection
trained_on_file
Source file (reproducibility)
python_version
Python version
sklearn_version
scikit-learn version
xgboost_version
XGBoost version

Load and predict​

clf_loaded = SpectralClassifier.load_model(
"data/models/spectral_classifier_xgboost_20260213T225019Z.pkl"
)

# The loaded pipeline includes the scaler and imputer
# No additional data preparation is required
predictions = clf_loaded.model_pipeline.predict(X_new)
probabilities = clf_loaded.model_pipeline.predict_proba(X_new)

5. Complete evaluation​

After training, clf.evaluate() automatically generates:

clf.evaluate(X_test, y_test, plot=True)
OutputDescription
Classification reportPrecision / Recall / F1 by class (A, F, G, K, M)
Confusion matrixNormalized — shows the expected F/G confusion
ROC and PR curvesOne-vs-rest by class
ECE scoreExpected Calibration Error — probability quality
Feature importanceXGBoost gain or permutation importance

6. Reproducibility​

Each run produces a unique ISO timestamp identifier. To reproduce an exact run:

# Retrieve the training source file
import json
with open("data/reports/20260213T225019Z/spectral_classifier_xgboost_20260213T225019Z_meta.json") as f:
meta = json.load(f)

print(meta["trained_on_file"]) # → the features CSV used for training
print(meta["best_params_"]) # → final hyperparameters
print(meta["n_features_used"]) # → number of features used by this run
print(meta["balanced_accuracy"]) # → balanced accuracy of this run