specsr.data.splits¶
Group-aware train/test splitting for the augmented spectra datasets.
Background¶
The augmented .npz datasets contain 21 rows per physical galaxy: one
original followed by 20 stochastic realizations (Gaussian redshift offset plus
10%-amplitude flux noise). Every row carries the same sky position as its
parent, and the id column is only a running row index – it does not encode
provenance.
The original get_or_make_split drew a flat rng.permutation(N) over all
rows, so ~16-17 augmented siblings of each test galaxy landed in the training
set. Because the augmentations are near-duplicates, this leaked the test set
into training and inflated every reported held-out metric.
This module splits on the parent galaxy instead, so all 21 rows of a galaxy fall on the same side of the split.
Grouping key¶
Parents are recovered from (ra, dec, field), which augmentation leaves
untouched. This is preferred over the positional formula
parent(i) = i if i < G else (i - G) // n_aug
because it additionally merges genuine duplicate observations of the same object. The DR3 file has 1,187 rows spanning only 1,163 distinct sky positions (23 objects appear more than once); those duplicates would straddle a positional split. The DR4 file is clean (2,507 galaxies, uniform 21x), and there the two schemes agree exactly.
Module Attributes
Bumped when the three-way scheme changes, so old caches are never reused. |
Functions
|
Fail loudly if any guarantee of the three-way split is violated. |
|
Fail loudly if any galaxy has rows on both sides of the split. |
|
Group-aware replacement for the original flat-permutation splitter. |
|
Cached three-way split for a built product. |
|
Return |
|
|
|
Split galaxies (not rows) into train/test, then expand back to rows. |
|
Split galaxies three ways, evaluating on real spectra only. |
|
Return an integer parent-galaxy label per row. |
- specsr.data.splits.parent_group_ids(dataset_path=None, ra=None, dec=None, field=None)[source]¶
Return an integer parent-galaxy label per row.
Pass either
dataset_pathor thera/dec/fieldarrays. Rows sharing a sky position (and field) get the same label.
- specsr.data.splits.make_group_split(groups, train_frac=0.8, seed=42)[source]¶
Split galaxies (not rows) into train/test, then expand back to rows.
train_fracis applied to the number of galaxies. Because every galaxy contributes the same number of rows in these datasets, the resulting row fractions match closely; they are not forced to match exactly.
- specsr.data.splits.assert_no_group_leakage(train_idx, test_idx, groups)[source]¶
Fail loudly if any galaxy has rows on both sides of the split.
- specsr.data.splits.get_or_make_split(dataset_path, N, train_frac=0.8, seed=42, split_dir='splits')[source]¶
Group-aware replacement for the original flat-permutation splitter.
Signature matches the previous helper so call sites need no changes, but cache files use a distinct
groupsplit_prefix: old leakysplit_*.npzfiles are ignored rather than reused.
- specsr.data.splits.SPLIT_SCHEME_3WAY = 'groupsplit3-v1'¶
Bumped when the three-way scheme changes, so old caches are never reused.
- specsr.data.splits.make_group_split_3way(groups, is_original, train_frac=0.8, val_frac=0.1, seed=42, allow_empty_test=False)[source]¶
Split galaxies three ways, evaluating on real spectra only.
Returns
(train_idx, val_idx, test_idx)as row indices.Two separate guarantees, for two separate problems:
Galaxies never straddle a boundary. All 21 rows of a galaxy (1 original + 20 augmentations) land in the same partition. A split drawn over rows put ~16 near-duplicate siblings of every held-out galaxy into training.
Validation and test contain only originals. Augmentation is a training-time technique: a synthetic realization is not an observation. Evaluating on augmented rows would report performance on perturbations rather than on real spectra, and would compute statistics over 21x correlated rows, understating uncertainties — the effective sample size is the number of galaxies, not the number of rows.
Why validation and test are separate. Training saves a checkpoint whenever the monitored metric improves, so over N epochs the saved model is the best of N draws on whatever set is monitored. Reporting that same set conflates genuine convergence with a favourable fluctuation, and the two cannot be separated using the set the selection was made on. Validation makes decisions; test is measured once.
- specsr.data.splits.assert_clean_3way(train_idx, val_idx, test_idx, groups, is_original)[source]¶
Fail loudly if any guarantee of the three-way split is violated.
- specsr.data.splits.get_or_make_split_3way(dataset_path, train_frac=0.8, val_frac=0.1, seed=42, split_dir='splits', allow_empty_test=False)[source]¶
Cached three-way split for a built product.
Requires the product to carry
parent_idandis_original; products built before those existed are rejected rather than guessed at.
- specsr.data.splits.get_training_split(dataset_path, train_frac=0.8, val_frac=0.2, seed=42, split_dir='splits', allow_empty_test=True)[source]¶
Return
(train_idx, val_idx, split_path)for a training run.Deliberately does not return the test indices. Training monitors the validation set for checkpoint selection and the learning-rate schedule; the test set must not be loaded during training at all, so that the number eventually reported is not the best of many draws on the set being reported.
Retrieve the test indices separately, once, at evaluation time:
_, _, test_idx, _ = get_or_make_split_3way(path)