Skip to content

feat: add required_features() and missing-data validation#212

Open
marcbal77 wants to merge 6 commits into
bio-learn:masterfrom
marcbal77:feature/required-features
Open

feat: add required_features() and missing-data validation#212
marcbal77 wants to merge 6 commits into
bio-learn:masterfrom
marcbal77:feature/required-features

Conversation

@marcbal77

Copy link
Copy Markdown
Member

Summary

Adds a public, stable required_features() method to every model plus a generic input-validation step so clocks raise a clear, actionable error when a GeoData lacks the markers or metadata they need. This is the consumer side of the clinical-clock work, split out of #203 per review.

API (stable at 1.0)

New biolearn.features module:

  • RequiredFeatures(layer, features, metadata): a frozen dataclass that is also a Mapping, so it behaves as the documented {"layer", "features", "metadata"} dict and as an object with .layer / .features / .metadata. All three keys are always present.
  • MissingFeaturesError(ValueError): raised on missing inputs. Subclasses ValueError, so existing except ValueError handlers keep working while callers can catch this specific case.
  • validate_required_features(model, geo_data): the single validator.

Every model gains required_features():

gallery.get("Horvathv1").required_features()
# {"layer": "dnam", "features": [...], "metadata": []}

Validation scope

Hard-fail validation is wired only where a missing feature corrupts the result: LinearMethylationModel (the exact linear combination, which previously carried its own private check). Clocks that tolerate partial inputs by design keep their current behavior and expose required_features() for introspection only: PCLinearTransformationModel (intersect and center-fill), LinearTranscriptomicModel (inner join), MiAge, EpiTOC2, AltumAge, Deconvolution, GPAge, and the proteomic clock. GrimageModel and HurdleAPIModel keep their existing bespoke checks.

The validator encodes the one axis asymmetry between layers in a single place (_LAYER_FRAME): dnam / rna / protein are features-as-rows (features in .index); clinical is samples-as-rows (biomarkers in .columns), matching metadata.

Tests

New test_features.py:

  • RequiredFeatures dict and object behavior; all three keys always present.
  • The validator per layer (dnam index vs clinical columns), metadata checks, and backward-compatible ValueError.
  • A regression test that a tolerant clock (EpiTOC2) still runs when a required CpG is missing.
  • A gallery-wide smoke test that every model returns a valid RequiredFeatures, including forwarding through ImputationDecorator.

Full suite: 221 passed, 5 skipped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant