factrix.MetricsBundle
dataclass
¶
MetricsBundle(identity: tuple[str, int], metrics: Mapping[str, MetricOutput] = dict(), skipped: Mapping[str, str] = dict(), context: Mapping[str, Any] = dict())
Cell-level descriptive metrics for one factor at one horizon.
Parallel to :class:factrix.FactorProfile (the primary inferential
artifact). The bundle holds every standalone metric run_metrics
successfully evaluated for the cell, plus a skipped map of
metrics that could not auto-run (with reason).
Hashing is disabled (__hash__ = None) because the bundle holds
MetricOutput instances whose metadata is a mutable dict.
Group bundles by identity (a hashable tuple), not by the bundle
itself.
Attributes:
| Name | Type | Description |
|---|---|---|
identity |
tuple[str, int]
|
|
metrics |
Mapping[str, MetricOutput]
|
Metric name → |
skipped |
Mapping[str, str]
|
Metric name → reason string for metrics that could
not auto-run (excluded by the registry, requires explicit
kwargs, stage-1 helper failed, …). v1 surfaces this through
|
context |
Mapping[str, Any]
|
Sample-restriction / conditioning dimensions per #160.
v1 always empty; downstream slicers ( |
Examples:
>>> import factrix as fx
>>> from factrix.preprocess import compute_forward_return
>>> raw = fx.datasets.make_cs_panel(n_assets=20, n_dates=120)
>>> panel = compute_forward_return(raw, forward_periods=5)
>>> bundle = fx.run_metrics(panel, fx.AnalysisConfig.individual_continuous())
>>> isinstance(bundle, fx.MetricsBundle)
True
>>> "ic" in bundle
True
>>> ic_output = bundle["ic"]
>>> bundle.identity == ("factor", 5)
True
to_frame ¶
Long-form view of the bundle: one row per metric.
Schema (8 columns, stable regardless of bundle contents):
| column | type | source |
|---|---|---|
factor_id |
str | identity[0] |
forward_periods |
int | identity[1] |
metric |
str | mapping key |
value |
float | MetricOutput.value |
stat |
float \ | null |
significance |
str \ | null |
p_value |
float \ | null |
short_circuit_reason |
str \ | null |
metadata is not flattened — the per-metric shape is
heterogeneous (per-regime dicts, per-horizon entries,
Kolari-Pynnönen source labels, …) and a flat schema would
fight every consumer. Reach into bundle["name"].metadata
for the rest.
context.* is not flattened in v1 — context is
always empty here; downstream slicers populating context
is a v1.x extension that may grow the schema.
skipped entries do not appear; only successful and
short-circuited MetricOutput rows are emitted.
Examples:
>>> import factrix as fx
>>> from factrix.preprocess import compute_forward_return
>>> raw = fx.datasets.make_cs_panel(n_assets=20, n_dates=120)
>>> panel = compute_forward_return(raw, forward_periods=5)
>>> bundle = fx.run_metrics(panel, fx.AnalysisConfig.individual_continuous())
>>> df = bundle.to_frame()
>>> set(df.columns) >= {"factor_id", "metric", "value", "p_value"}
True
>>> df.height >= 1
True
Result type returned by run_metrics — holds every
standalone metric the cell successfully evaluated for one factor at one
horizon, plus a skipped map for metrics that could not auto-run.
Parallel to FactorProfile: both share the
identity tuple (factor_id, forward_periods) so downstream functions
(compare, survivors workflows) can join the two
artifact families row-by-row.
| Bundle | Profile |
|---|---|
run_metrics — descriptive surface (no false discovery rate (FDR) claim) |
evaluate — primary inferential decision (drives FDR) |
Many metrics per cell, each a MetricOutput |
One primary stat + sidecar stats dict |
compare(bundles) → cross-factor descriptive view |
compare(profiles) / compare(survivors) |
Typical use¶
import factrix as fx
cfg = fx.AnalysisConfig.individual_continuous(metric=fx.Metric.IC, forward_periods=5)
bundle = fx.run_metrics(panel, cfg, factor_col="momentum_12_1")
bundle.identity # ('momentum_12_1', 5)
bundle.metrics # dict[str, MetricOutput]
bundle.to_frame() # pl.DataFrame — flat tabular view for compare / plotting
bundle.skipped # {metric_name: reason} — metrics that short-circuited
For the wide multi-factor pattern (looping run_metrics with
factor_col= over candidate signals) see the
Batch screening guide.