panelcast 0.14.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- panelcast/__init__.py +73 -0
- panelcast/_data/datasets/aero.yaml +82 -0
- panelcast/_data/datasets/aoty_full.yaml +37 -0
- panelcast/_data/examples/aerospace/descriptor.yaml +82 -0
- panelcast/_data/examples/aerospace/flights.csv +40 -0
- panelcast/cli/__init__.py +51 -0
- panelcast/cli/backtest_cmd.py +94 -0
- panelcast/cli/commands.py +814 -0
- panelcast/cli/doctor_cmd.py +61 -0
- panelcast/cli/main.py +66 -0
- panelcast/cli/preflight_cmd.py +101 -0
- panelcast/cli/run.py +1000 -0
- panelcast/cli/runs_cmd.py +528 -0
- panelcast/cli/select_cmd.py +238 -0
- panelcast/cli/stack_cmd.py +62 -0
- panelcast/cli/stages.py +350 -0
- panelcast/config/descriptor.py +404 -0
- panelcast/config/gates.py +47 -0
- panelcast/config/loader.py +70 -0
- panelcast/config/pipeline_yaml.py +328 -0
- panelcast/data/alignment.py +95 -0
- panelcast/data/chronology.py +87 -0
- panelcast/data/cleaning.py +541 -0
- panelcast/data/imputation.py +82 -0
- panelcast/data/ingest.py +196 -0
- panelcast/data/lineage.py +210 -0
- panelcast/data/manifests.py +205 -0
- panelcast/data/split.py +308 -0
- panelcast/data/split_types.py +99 -0
- panelcast/data/validation.py +244 -0
- panelcast/doctor.py +178 -0
- panelcast/evaluation/__init__.py +62 -0
- panelcast/evaluation/calibration.py +619 -0
- panelcast/evaluation/conformal.py +137 -0
- panelcast/evaluation/cv.py +394 -0
- panelcast/evaluation/decomposition.py +112 -0
- panelcast/evaluation/metrics.py +355 -0
- panelcast/evaluation/ppc.py +205 -0
- panelcast/evaluation/prior_predictive.py +384 -0
- panelcast/evaluation/ranking.py +132 -0
- panelcast/evaluation/slices.py +223 -0
- panelcast/features/__init__.py +24 -0
- panelcast/features/album_type.py +140 -0
- panelcast/features/artist.py +56 -0
- panelcast/features/base.py +208 -0
- panelcast/features/basis.py +141 -0
- panelcast/features/collaboration.py +158 -0
- panelcast/features/core.py +115 -0
- panelcast/features/errors.py +107 -0
- panelcast/features/gbm_offset.py +324 -0
- panelcast/features/genre.py +211 -0
- panelcast/features/history.py +181 -0
- panelcast/features/packs/__init__.py +7 -0
- panelcast/features/packs/aoty.py +26 -0
- panelcast/features/pca.py +5 -0
- panelcast/features/pipeline.py +185 -0
- panelcast/features/registry.py +125 -0
- panelcast/features/temporal.py +172 -0
- panelcast/gpu_memory/__init__.py +48 -0
- panelcast/gpu_memory/admission.py +83 -0
- panelcast/gpu_memory/calibration_store.py +262 -0
- panelcast/gpu_memory/estimate.py +248 -0
- panelcast/gpu_memory/measure.py +129 -0
- panelcast/gpu_memory/platform.py +134 -0
- panelcast/gpu_memory/query.py +194 -0
- panelcast/gpu_memory/runtime_predictor.py +160 -0
- panelcast/io/paths.py +27 -0
- panelcast/io/readers.py +20 -0
- panelcast/io/writers.py +9 -0
- panelcast/model_preflight.py +385 -0
- panelcast/model_preflight_data.py +125 -0
- panelcast/models/__init__.py +1 -0
- panelcast/models/baselines/__init__.py +37 -0
- panelcast/models/baselines/core.py +480 -0
- panelcast/models/bayes/__init__.py +72 -0
- panelcast/models/bayes/diagnostics.py +450 -0
- panelcast/models/bayes/fit.py +827 -0
- panelcast/models/bayes/io.py +382 -0
- panelcast/models/bayes/likelihoods.py +835 -0
- panelcast/models/bayes/model.py +1035 -0
- panelcast/models/bayes/model_math.py +43 -0
- panelcast/models/bayes/predict.py +615 -0
- panelcast/models/bayes/priors.py +350 -0
- panelcast/models/bayes/rollout.py +214 -0
- panelcast/models/bayes/transforms.py +126 -0
- panelcast/paths.py +107 -0
- panelcast/pipelines/__init__.py +67 -0
- panelcast/pipelines/backtest.py +340 -0
- panelcast/pipelines/build_features.py +496 -0
- panelcast/pipelines/compare_baselines.py +390 -0
- panelcast/pipelines/create_splits.py +425 -0
- panelcast/pipelines/diagnose.py +257 -0
- panelcast/pipelines/errors.py +194 -0
- panelcast/pipelines/evaluate.py +2087 -0
- panelcast/pipelines/manifest.py +367 -0
- panelcast/pipelines/orchestrator.py +1958 -0
- panelcast/pipelines/predict_next.py +929 -0
- panelcast/pipelines/prepare_dataset.py +287 -0
- panelcast/pipelines/publication.py +1296 -0
- panelcast/pipelines/sensitivity.py +1340 -0
- panelcast/pipelines/stages.py +807 -0
- panelcast/pipelines/stamps.py +84 -0
- panelcast/pipelines/train_bayes.py +1876 -0
- panelcast/pipelines/training_summary.py +198 -0
- panelcast/preflight/__init__.py +236 -0
- panelcast/preflight/cache.py +177 -0
- panelcast/preflight/calibrate.py +249 -0
- panelcast/preflight/check.py +250 -0
- panelcast/preflight/full_check.py +737 -0
- panelcast/preflight/mini_run.py +407 -0
- panelcast/preflight/output.py +240 -0
- panelcast/py.typed +0 -0
- panelcast/reporting/__init__.py +57 -0
- panelcast/reporting/curves.py +166 -0
- panelcast/reporting/figures.py +1181 -0
- panelcast/reporting/html_report.py +219 -0
- panelcast/reporting/model_card.py +1144 -0
- panelcast/reporting/tables.py +667 -0
- panelcast/select/__init__.py +34 -0
- panelcast/select/confirmation.py +373 -0
- panelcast/select/orchestrate.py +510 -0
- panelcast/select/prior_screen.py +198 -0
- panelcast/select/rules.py +200 -0
- panelcast/select/runner.py +1130 -0
- panelcast/select/scoring.py +424 -0
- panelcast/select/space.py +453 -0
- panelcast/select/stacking.py +499 -0
- panelcast/select/tiers.py +219 -0
- panelcast/utils/environment.py +150 -0
- panelcast/utils/git_state.py +177 -0
- panelcast/utils/hashing.py +93 -0
- panelcast/utils/jax_cache.py +57 -0
- panelcast/utils/logging.py +152 -0
- panelcast/utils/random.py +69 -0
- panelcast/visualization/__init__.py +68 -0
- panelcast/visualization/charts.py +535 -0
- panelcast/visualization/dashboard.py +612 -0
- panelcast/visualization/export.py +306 -0
- panelcast/visualization/theme.py +101 -0
- panelcast-0.14.0.dist-info/METADATA +316 -0
- panelcast-0.14.0.dist-info/RECORD +145 -0
- panelcast-0.14.0.dist-info/WHEEL +5 -0
- panelcast-0.14.0.dist-info/entry_points.txt +2 -0
- panelcast-0.14.0.dist-info/licenses/LICENSE +21 -0
- panelcast-0.14.0.dist-info/top_level.txt +1 -0
panelcast/__init__.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""panelcast — hierarchical Bayesian prediction for bounded scores of events
|
|
2
|
+
nested in entities over time, configured by a YAML descriptor.
|
|
3
|
+
|
|
4
|
+
The names re-exported here are the supported public API and follow semantic
|
|
5
|
+
versioning from the next minor release; see ``docs/API.md`` for the guarantee.
|
|
6
|
+
Everything reached through ``panelcast.*`` submodules is internal and may change
|
|
7
|
+
without notice. Attribute access is lazy (PEP 562), so ``import panelcast`` stays
|
|
8
|
+
cheap and does not eagerly import jax.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from importlib import import_module
|
|
14
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
15
|
+
from typing import TYPE_CHECKING, Any
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
__version__ = version("panelcast")
|
|
19
|
+
except PackageNotFoundError: # running from a source tree without an install
|
|
20
|
+
__version__ = "0.0.0+unknown"
|
|
21
|
+
|
|
22
|
+
# Each public name mapped to the submodule it is lazily imported from. Keep this
|
|
23
|
+
# minimal — every entry is a semver promise (see docs/API.md), and importing a
|
|
24
|
+
# submodule here would defeat the point of the lazy seam.
|
|
25
|
+
_LAZY_EXPORTS = {
|
|
26
|
+
"DatasetDescriptor": "panelcast.config.descriptor",
|
|
27
|
+
"load_descriptor": "panelcast.config.descriptor",
|
|
28
|
+
"PipelineConfig": "panelcast.pipelines.orchestrator",
|
|
29
|
+
"PipelineOrchestrator": "panelcast.pipelines.orchestrator",
|
|
30
|
+
"run_pipeline": "panelcast.pipelines.orchestrator",
|
|
31
|
+
"FeatureRegistry": "panelcast.features",
|
|
32
|
+
"FeatureBlock": "panelcast.features.base",
|
|
33
|
+
"build_default_registry": "panelcast.features",
|
|
34
|
+
"LikelihoodSpec": "panelcast.models.bayes.likelihoods",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if TYPE_CHECKING: # let type checkers resolve the names without importing jax
|
|
38
|
+
from panelcast.config.descriptor import DatasetDescriptor, load_descriptor
|
|
39
|
+
from panelcast.features import FeatureRegistry, build_default_registry
|
|
40
|
+
from panelcast.features.base import FeatureBlock
|
|
41
|
+
from panelcast.models.bayes.likelihoods import LikelihoodSpec
|
|
42
|
+
from panelcast.pipelines.orchestrator import (
|
|
43
|
+
PipelineConfig,
|
|
44
|
+
PipelineOrchestrator,
|
|
45
|
+
run_pipeline,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def __getattr__(name: str) -> Any:
|
|
50
|
+
module = _LAZY_EXPORTS.get(name)
|
|
51
|
+
if module is None:
|
|
52
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
53
|
+
return getattr(import_module(module), name)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def __dir__() -> list[str]:
|
|
57
|
+
# Keep the default module surface (dunders, __all__, eager imports,
|
|
58
|
+
# submodules) discoverable alongside the lazily exported public names.
|
|
59
|
+
return sorted({*globals(), *_LAZY_EXPORTS})
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
__all__ = [
|
|
63
|
+
"__version__",
|
|
64
|
+
"DatasetDescriptor",
|
|
65
|
+
"load_descriptor",
|
|
66
|
+
"PipelineConfig",
|
|
67
|
+
"PipelineOrchestrator",
|
|
68
|
+
"run_pipeline",
|
|
69
|
+
"FeatureRegistry",
|
|
70
|
+
"FeatureBlock",
|
|
71
|
+
"build_default_registry",
|
|
72
|
+
"LikelihoodSpec",
|
|
73
|
+
]
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Aerospace worked example — a self-contained, non-music domain.
|
|
2
|
+
#
|
|
3
|
+
# Airframes fly sequential test flights, each scored 0-10. Identical copies of
|
|
4
|
+
# this descriptor ship in the checkout and wheel; the raw path is anchored at
|
|
5
|
+
# the checkout or package-data root so `panelcast demo` runs with no external
|
|
6
|
+
# data.
|
|
7
|
+
#
|
|
8
|
+
# Every key omitted here keeps its AOTY default — see
|
|
9
|
+
# src/panelcast/config/descriptor.py. Walkthrough: docs/PORTING.md.
|
|
10
|
+
|
|
11
|
+
name: aero
|
|
12
|
+
|
|
13
|
+
# --- raw source ----------------------------------------------------------
|
|
14
|
+
raw_path_env: AERO_DATASET_PATH
|
|
15
|
+
raw_path_default: examples/aerospace/flights.csv
|
|
16
|
+
encoding: utf-8
|
|
17
|
+
raw_column_map:
|
|
18
|
+
"Flight Date": Flight_Date
|
|
19
|
+
"Perf Score": Perf_Score
|
|
20
|
+
"Sensor Samples": Sensor_Samples
|
|
21
|
+
"Test Crew": Test_Crew
|
|
22
|
+
"Flight ID": Flight_ID
|
|
23
|
+
"Campaign Year": Year
|
|
24
|
+
"Thrust Margin": Thrust_Margin
|
|
25
|
+
"Payload Fraction": Payload_Fraction
|
|
26
|
+
required_raw_columns:
|
|
27
|
+
- Airframe
|
|
28
|
+
- "Flight ID"
|
|
29
|
+
- "Campaign Year"
|
|
30
|
+
- "Flight Date"
|
|
31
|
+
- "Perf Score"
|
|
32
|
+
- "Sensor Samples"
|
|
33
|
+
- "Test Crew"
|
|
34
|
+
- "Thrust Margin"
|
|
35
|
+
- "Payload Fraction"
|
|
36
|
+
optional_raw_columns: []
|
|
37
|
+
|
|
38
|
+
# --- identity / sequencing ------------------------------------------------
|
|
39
|
+
entity_col: Airframe
|
|
40
|
+
event_col: Flight_ID
|
|
41
|
+
# No per-event group column in this domain — the entity_group_pooling gate is
|
|
42
|
+
# structurally unusable (inheriting AOTY's primary_genre would misdescribe it).
|
|
43
|
+
entity_group_col: null
|
|
44
|
+
date_col: Flight_Date
|
|
45
|
+
parsed_date_col: Flight_Date_Parsed
|
|
46
|
+
year_col: Year
|
|
47
|
+
date_format: "%Y-%m-%d" # ISO, unlike AOTY's "April 10, 2018"
|
|
48
|
+
|
|
49
|
+
# --- targets ----------------------------------------------------------------
|
|
50
|
+
target_col: Perf_Score
|
|
51
|
+
target_bounds: [0.0, 10.0]
|
|
52
|
+
model_prefix: perf
|
|
53
|
+
n_obs_col: Sensor_Samples
|
|
54
|
+
# Sensor samples count telemetry points, not independent raters whose mean is the
|
|
55
|
+
# score, so the beta_binomial likelihood is not meaningful here.
|
|
56
|
+
n_obs_is_aggregation_count: false
|
|
57
|
+
secondary_target_col: null
|
|
58
|
+
secondary_prefix: null
|
|
59
|
+
secondary_n_obs_col: null
|
|
60
|
+
|
|
61
|
+
# --- cleaning semantics ----------------------------------------------------
|
|
62
|
+
multi_entity_col: Test_Crew
|
|
63
|
+
multi_entity_separator: " + "
|
|
64
|
+
unknown_entity_sentinel: null
|
|
65
|
+
min_year: 2015
|
|
66
|
+
|
|
67
|
+
# --- dataset preparation -----------------------------------------------------
|
|
68
|
+
min_obs_thresholds: [5, 10, 25]
|
|
69
|
+
primary_min_obs: 5
|
|
70
|
+
processed_name_template: "perf_minobs_{min_ratings}"
|
|
71
|
+
|
|
72
|
+
# --- features -----------------------------------------------------------------
|
|
73
|
+
feature_packs: []
|
|
74
|
+
feature_blocks:
|
|
75
|
+
- name: temporal
|
|
76
|
+
- name: entity_history
|
|
77
|
+
- name: core_numeric
|
|
78
|
+
params:
|
|
79
|
+
columns: [Thrust_Margin, Payload_Fraction]
|
|
80
|
+
ablation_groups:
|
|
81
|
+
temporal: [temporal]
|
|
82
|
+
artist: [entity_history]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# AOTY dataset descriptor.
|
|
2
|
+
#
|
|
3
|
+
# Every DatasetDescriptor field defaults to the AOTY literal it replaced, so
|
|
4
|
+
# this file only needs to (re)state the name: `--dataset aoty_full` must be
|
|
5
|
+
# byte-identical to running with no --dataset flag at all (verified by
|
|
6
|
+
# tests/e2e/test_domain_portability.py).
|
|
7
|
+
#
|
|
8
|
+
# Full field reference: src/panelcast/config/descriptor.py.
|
|
9
|
+
# Worked non-music example: configs/datasets/aero.yaml + docs/PORTING.md.
|
|
10
|
+
#
|
|
11
|
+
# Operational note: processed data, splits, features and models all live under
|
|
12
|
+
# relative paths (data/, models/, outputs/) — run each domain from its own
|
|
13
|
+
# working directory to keep artifacts isolated. A --data-root option is a
|
|
14
|
+
# post-publication stretch item.
|
|
15
|
+
|
|
16
|
+
name: aoty
|
|
17
|
+
|
|
18
|
+
# Commented examples of the AOTY defaults this file inherits (do not uncomment
|
|
19
|
+
# unless you mean to override):
|
|
20
|
+
#
|
|
21
|
+
# raw_path_env: AOTY_DATASET_PATH
|
|
22
|
+
# raw_path_default: data/raw/all_albums_full.csv
|
|
23
|
+
# encoding: utf-8-sig
|
|
24
|
+
# entity_col: Artist
|
|
25
|
+
# event_col: Album
|
|
26
|
+
# target_col: User_Score
|
|
27
|
+
# target_bounds: [0.0, 100.0]
|
|
28
|
+
# model_prefix: user
|
|
29
|
+
# n_obs_col: User_Ratings
|
|
30
|
+
# secondary_target_col: Critic_Score
|
|
31
|
+
# secondary_prefix: critic
|
|
32
|
+
# secondary_n_obs_col: Critic_Reviews
|
|
33
|
+
# date_format: "%B %d, %Y"
|
|
34
|
+
# min_obs_thresholds: [5, 10, 25]
|
|
35
|
+
# primary_min_obs: 10
|
|
36
|
+
# processed_name_template: "user_score_minratings_{min_ratings}"
|
|
37
|
+
# feature_packs: [aoty]
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Aerospace worked example — a self-contained, non-music domain.
|
|
2
|
+
#
|
|
3
|
+
# Airframes fly sequential test flights, each scored 0-10. Identical copies of
|
|
4
|
+
# this descriptor ship in the checkout and wheel; the raw path is anchored at
|
|
5
|
+
# the checkout or package-data root so `panelcast demo` runs with no external
|
|
6
|
+
# data.
|
|
7
|
+
#
|
|
8
|
+
# Every key omitted here keeps its AOTY default — see
|
|
9
|
+
# src/panelcast/config/descriptor.py. Walkthrough: docs/PORTING.md.
|
|
10
|
+
|
|
11
|
+
name: aero
|
|
12
|
+
|
|
13
|
+
# --- raw source ----------------------------------------------------------
|
|
14
|
+
raw_path_env: AERO_DATASET_PATH
|
|
15
|
+
raw_path_default: examples/aerospace/flights.csv
|
|
16
|
+
encoding: utf-8
|
|
17
|
+
raw_column_map:
|
|
18
|
+
"Flight Date": Flight_Date
|
|
19
|
+
"Perf Score": Perf_Score
|
|
20
|
+
"Sensor Samples": Sensor_Samples
|
|
21
|
+
"Test Crew": Test_Crew
|
|
22
|
+
"Flight ID": Flight_ID
|
|
23
|
+
"Campaign Year": Year
|
|
24
|
+
"Thrust Margin": Thrust_Margin
|
|
25
|
+
"Payload Fraction": Payload_Fraction
|
|
26
|
+
required_raw_columns:
|
|
27
|
+
- Airframe
|
|
28
|
+
- "Flight ID"
|
|
29
|
+
- "Campaign Year"
|
|
30
|
+
- "Flight Date"
|
|
31
|
+
- "Perf Score"
|
|
32
|
+
- "Sensor Samples"
|
|
33
|
+
- "Test Crew"
|
|
34
|
+
- "Thrust Margin"
|
|
35
|
+
- "Payload Fraction"
|
|
36
|
+
optional_raw_columns: []
|
|
37
|
+
|
|
38
|
+
# --- identity / sequencing ------------------------------------------------
|
|
39
|
+
entity_col: Airframe
|
|
40
|
+
event_col: Flight_ID
|
|
41
|
+
# No per-event group column in this domain — the entity_group_pooling gate is
|
|
42
|
+
# structurally unusable (inheriting AOTY's primary_genre would misdescribe it).
|
|
43
|
+
entity_group_col: null
|
|
44
|
+
date_col: Flight_Date
|
|
45
|
+
parsed_date_col: Flight_Date_Parsed
|
|
46
|
+
year_col: Year
|
|
47
|
+
date_format: "%Y-%m-%d" # ISO, unlike AOTY's "April 10, 2018"
|
|
48
|
+
|
|
49
|
+
# --- targets ----------------------------------------------------------------
|
|
50
|
+
target_col: Perf_Score
|
|
51
|
+
target_bounds: [0.0, 10.0]
|
|
52
|
+
model_prefix: perf
|
|
53
|
+
n_obs_col: Sensor_Samples
|
|
54
|
+
# Sensor samples count telemetry points, not independent raters whose mean is the
|
|
55
|
+
# score, so the beta_binomial likelihood is not meaningful here.
|
|
56
|
+
n_obs_is_aggregation_count: false
|
|
57
|
+
secondary_target_col: null
|
|
58
|
+
secondary_prefix: null
|
|
59
|
+
secondary_n_obs_col: null
|
|
60
|
+
|
|
61
|
+
# --- cleaning semantics ----------------------------------------------------
|
|
62
|
+
multi_entity_col: Test_Crew
|
|
63
|
+
multi_entity_separator: " + "
|
|
64
|
+
unknown_entity_sentinel: null
|
|
65
|
+
min_year: 2015
|
|
66
|
+
|
|
67
|
+
# --- dataset preparation -----------------------------------------------------
|
|
68
|
+
min_obs_thresholds: [5, 10, 25]
|
|
69
|
+
primary_min_obs: 5
|
|
70
|
+
processed_name_template: "perf_minobs_{min_ratings}"
|
|
71
|
+
|
|
72
|
+
# --- features -----------------------------------------------------------------
|
|
73
|
+
feature_packs: []
|
|
74
|
+
feature_blocks:
|
|
75
|
+
- name: temporal
|
|
76
|
+
- name: entity_history
|
|
77
|
+
- name: core_numeric
|
|
78
|
+
params:
|
|
79
|
+
columns: [Thrust_Margin, Payload_Fraction]
|
|
80
|
+
ablation_groups:
|
|
81
|
+
temporal: [temporal]
|
|
82
|
+
artist: [entity_history]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Airframe,Flight ID,Flight Date,Campaign Year,Perf Score,Sensor Samples,Test Crew,Thrust Margin,Payload Fraction
|
|
2
|
+
Falcon-X1,Falcon-X1-F01,2021-04-16,2021,4.42,116,Falcon-X1 + Chase-3,-1.951,0.883
|
|
3
|
+
Falcon-X1,Falcon-X1-F02,2021-05-10,2021,5.05,102,Falcon-X1 + Chase-2,0.879,0.849
|
|
4
|
+
Falcon-X1,Falcon-X1-F03,2021-05-30,2021,4.27,156,Falcon-X1 + Chase-2,-0.959,0.779
|
|
5
|
+
Falcon-X1,Falcon-X1-F04,2021-07-15,2021,4.72,113,Falcon-X1,-0.155,0.745
|
|
6
|
+
Condor-7,Condor-7-F01,2021-04-28,2021,6.54,176,Condor-7,-0.406,0.428
|
|
7
|
+
Condor-7,Condor-7-F02,2021-05-09,2021,7.0,42,Condor-7,-0.84,0.359
|
|
8
|
+
Condor-7,Condor-7-F03,2021-07-20,2021,6.74,198,Condor-7,0.543,0.783
|
|
9
|
+
Condor-7,Condor-7-F04,2021-07-08,2021,7.02,148,Condor-7 + Chase-3,0.224,0.34
|
|
10
|
+
Raptor-M2,Raptor-M2-F01,2021-04-20,2021,5.24,128,Raptor-M2,-0.275,0.28
|
|
11
|
+
Raptor-M2,Raptor-M2-F02,2021-04-30,2021,5.43,170,Raptor-M2,0.163,0.588
|
|
12
|
+
Raptor-M2,Raptor-M2-F03,2021-06-11,2021,4.81,100,Raptor-M2,0.858,0.486
|
|
13
|
+
Raptor-M2,Raptor-M2-F04,2021-08-30,2021,4.62,219,Raptor-M2 + Chase-1,0.142,0.663
|
|
14
|
+
Raptor-M2,Raptor-M2-F05,2021-09-15,2021,4.83,171,Raptor-M2,0.457,0.317
|
|
15
|
+
Albatross-3,Albatross-3-F01,2021-04-13,2021,6.81,58,Albatross-3,0.481,0.687
|
|
16
|
+
Albatross-3,Albatross-3-F02,2021-05-13,2021,5.55,200,Albatross-3 + Chase-2,-1.687,0.261
|
|
17
|
+
Albatross-3,Albatross-3-F03,2021-06-21,2021,6.81,64,Albatross-3,1.299,0.745
|
|
18
|
+
Albatross-3,Albatross-3-F04,2021-06-12,2021,5.39,28,Albatross-3,-0.339,0.519
|
|
19
|
+
Albatross-3,Albatross-3-F05,2021-09-01,2021,5.49,45,Albatross-3,-1.446,0.731
|
|
20
|
+
Albatross-3,Albatross-3-F06,2021-08-05,2021,6.38,131,Albatross-3,-0.239,0.259
|
|
21
|
+
Kestrel-V,Kestrel-V-F01,2021-04-05,2021,6.29,29,Kestrel-V,-1.189,0.319
|
|
22
|
+
Kestrel-V,Kestrel-V-F02,2021-05-09,2021,5.92,21,Kestrel-V + Chase-2,-0.222,0.871
|
|
23
|
+
Kestrel-V,Kestrel-V-F03,2021-05-05,2021,7.38,179,Kestrel-V,2.914,0.856
|
|
24
|
+
Kestrel-V,Kestrel-V-F04,2021-06-12,2021,6.69,197,Kestrel-V + Chase-1,-0.415,0.507
|
|
25
|
+
Harrier-9,Harrier-9-F01,2021-03-04,2021,4.48,150,Harrier-9,-0.054,0.709
|
|
26
|
+
Harrier-9,Harrier-9-F02,2021-04-25,2021,4.94,105,Harrier-9 + Chase-1,-0.965,0.588
|
|
27
|
+
Harrier-9,Harrier-9-F03,2021-05-27,2021,4.46,218,Harrier-9,0.932,0.404
|
|
28
|
+
Harrier-9,Harrier-9-F04,2021-07-18,2021,3.66,166,Harrier-9 + Chase-1,-0.455,0.505
|
|
29
|
+
Harrier-9,Harrier-9-F05,2021-06-01,2021,4.56,197,Harrier-9,0.286,0.421
|
|
30
|
+
Harrier-9,Harrier-9-F06,2021-10-06,2021,4.65,28,Harrier-9,1.536,0.384
|
|
31
|
+
Osprey-T4,Osprey-T4-F01,2021-03-05,2021,8.52,46,Osprey-T4,1.461,0.812
|
|
32
|
+
Osprey-T4,Osprey-T4-F02,2021-03-23,2021,8.07,214,Osprey-T4,-0.005,0.301
|
|
33
|
+
Osprey-T4,Osprey-T4-F03,2021-03-27,2021,6.88,151,Osprey-T4,-2.05,0.554
|
|
34
|
+
Osprey-T4,Osprey-T4-F04,2021-07-09,2021,7.82,178,Osprey-T4,0.916,0.717
|
|
35
|
+
Swift-E2,Swift-E2-F01,2021-05-01,2021,5.35,113,Swift-E2 + Chase-2,0.538,0.869
|
|
36
|
+
Swift-E2,Swift-E2-F02,2021-05-18,2021,5.7,9,Swift-E2,0.177,0.274
|
|
37
|
+
Swift-E2,Swift-E2-F03,2021-08-18,2021,4.99,11,Swift-E2 + Chase-3,-0.853,0.763
|
|
38
|
+
Swift-E2,Swift-E2-F04,2021-07-25,2021,6.07,183,Swift-E2,-0.654,0.363
|
|
39
|
+
Swift-E2,Swift-E2-F05,2021-07-27,2021,5.69,87,Swift-E2,1.124,0.656
|
|
40
|
+
Swift-E2,Swift-E2-F06,2021-09-11,2021,7.36,58,Swift-E2,-1.097,0.772
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Command-line interface for the panelcast prediction pipeline.
|
|
2
|
+
|
|
3
|
+
This module provides CLI entry points for running the full pipeline or
|
|
4
|
+
individual stages. The primary entry point is `panelcast run`, which
|
|
5
|
+
executes all stages in dependency order with progress tracking.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
panelcast run --seed 42
|
|
9
|
+
panelcast run --dry-run --verbose
|
|
10
|
+
panelcast stage data --verbose
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import typer
|
|
16
|
+
|
|
17
|
+
app = typer.Typer(
|
|
18
|
+
add_completion=True,
|
|
19
|
+
help="panelcast - hierarchical Bayesian prediction for bounded scores over entity histories.",
|
|
20
|
+
invoke_without_command=True,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
# Stage subcommand group
|
|
24
|
+
stage_app = typer.Typer(help="Run individual pipeline stages")
|
|
25
|
+
app.add_typer(stage_app, name="stage")
|
|
26
|
+
|
|
27
|
+
# Runs subcommand group
|
|
28
|
+
runs_app = typer.Typer(help="Inspect pipeline run directories")
|
|
29
|
+
app.add_typer(runs_app, name="runs")
|
|
30
|
+
|
|
31
|
+
# Import the command submodules for their decorator side effects: importing each
|
|
32
|
+
# one runs the @app.command / @stage_app.command decorators that register the
|
|
33
|
+
# subcommands onto the shared app / stage_app created above. Order matches the
|
|
34
|
+
# original definition order so ``--help`` lists the commands unchanged.
|
|
35
|
+
# isort: off
|
|
36
|
+
from panelcast.cli import main as _main # noqa: E402
|
|
37
|
+
from panelcast.cli import run as _run # noqa: E402, F401
|
|
38
|
+
from panelcast.cli import stages as _stages # noqa: E402, F401
|
|
39
|
+
from panelcast.cli import commands as _commands # noqa: E402, F401
|
|
40
|
+
from panelcast.cli import runs_cmd as _runs_cmd # noqa: E402, F401
|
|
41
|
+
from panelcast.cli import doctor_cmd as _doctor_cmd # noqa: E402, F401
|
|
42
|
+
from panelcast.cli import preflight_cmd as _preflight_cmd # noqa: E402, F401
|
|
43
|
+
from panelcast.cli import select_cmd as _select_cmd # noqa: E402, F401
|
|
44
|
+
from panelcast.cli import stack_cmd as _stack_cmd # noqa: E402, F401
|
|
45
|
+
from panelcast.cli import backtest_cmd as _backtest_cmd # noqa: E402, F401
|
|
46
|
+
# isort: on
|
|
47
|
+
|
|
48
|
+
__version__ = _main.__version__
|
|
49
|
+
main = _main.main
|
|
50
|
+
|
|
51
|
+
__all__ = ["__version__", "app", "main", "runs_app", "stage_app"]
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""The `panelcast backtest` command (#179).
|
|
2
|
+
|
|
3
|
+
Rolling-origin backtest: runs the full leakage-safe stage chain once per
|
|
4
|
+
origin and reports every headline metric as mean ± SE across origins. A
|
|
5
|
+
killed backtest resumes at the next unfinished origin via the JSON ledger.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import typer
|
|
13
|
+
|
|
14
|
+
from panelcast.cli import app
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@app.command("backtest")
|
|
18
|
+
def backtest(
|
|
19
|
+
origins: int = typer.Option(
|
|
20
|
+
3,
|
|
21
|
+
"--origins",
|
|
22
|
+
min=1,
|
|
23
|
+
help="Number of rolling origins K: origin k holds out each entity's (last-k)-th event.",
|
|
24
|
+
),
|
|
25
|
+
backtest_id: str = typer.Option(
|
|
26
|
+
"default",
|
|
27
|
+
"--backtest-id",
|
|
28
|
+
help="Ledger/report directory name under outputs/backtest/ (reuse to resume).",
|
|
29
|
+
),
|
|
30
|
+
dataset: str | None = typer.Option(
|
|
31
|
+
None,
|
|
32
|
+
"--dataset",
|
|
33
|
+
help="Dataset descriptor (bare name or YAML path; omit for AOTY defaults).",
|
|
34
|
+
),
|
|
35
|
+
num_chains: int | None = typer.Option(
|
|
36
|
+
None, "--num-chains", min=1, help="Chains per origin fit (default: pipeline default)."
|
|
37
|
+
),
|
|
38
|
+
num_samples: int | None = typer.Option(
|
|
39
|
+
None, "--num-samples", min=1, help="Draws per origin fit (default: pipeline default)."
|
|
40
|
+
),
|
|
41
|
+
num_warmup: int | None = typer.Option(
|
|
42
|
+
None, "--num-warmup", min=1, help="Warmup per origin fit (default: pipeline default)."
|
|
43
|
+
),
|
|
44
|
+
origin_timeout: float | None = typer.Option(
|
|
45
|
+
None,
|
|
46
|
+
"--origin-timeout",
|
|
47
|
+
min=1.0,
|
|
48
|
+
help="Per-origin wall-clock timeout in seconds (default: none).",
|
|
49
|
+
),
|
|
50
|
+
output_root: str = typer.Option(
|
|
51
|
+
"outputs/backtest", "--output-root", help="Root directory for backtest ledgers/reports."
|
|
52
|
+
),
|
|
53
|
+
) -> None:
|
|
54
|
+
"""Run (or resume) a rolling-origin backtest and print the aggregate table.
|
|
55
|
+
|
|
56
|
+
Each origin regenerates splits/features with fresh stamps, so the leakage
|
|
57
|
+
controls hold unchanged; every origin's split content hash is recorded in
|
|
58
|
+
the ledger. Deeper origins shrink the eligible entity set — the aggregate
|
|
59
|
+
table reports n_test and n_entities per origin so cross-origin variation
|
|
60
|
+
is framed honestly.
|
|
61
|
+
|
|
62
|
+
Examples:
|
|
63
|
+
panelcast backtest --origins 3
|
|
64
|
+
panelcast backtest --origins 5 --num-chains 2 --num-samples 500
|
|
65
|
+
panelcast backtest --backtest-id nightly # rerun to resume
|
|
66
|
+
"""
|
|
67
|
+
from panelcast.pipelines.backtest import BacktestConfig, run_backtest
|
|
68
|
+
|
|
69
|
+
cfg = BacktestConfig(
|
|
70
|
+
origins=origins,
|
|
71
|
+
backtest_id=backtest_id,
|
|
72
|
+
output_root=Path(output_root),
|
|
73
|
+
dataset=dataset,
|
|
74
|
+
num_chains=num_chains,
|
|
75
|
+
num_samples=num_samples,
|
|
76
|
+
num_warmup=num_warmup,
|
|
77
|
+
origin_timeout_seconds=origin_timeout,
|
|
78
|
+
)
|
|
79
|
+
aggregate = run_backtest(cfg)
|
|
80
|
+
|
|
81
|
+
typer.echo(
|
|
82
|
+
f"\nBacktest '{backtest_id}': {aggregate['n_origins_completed']}"
|
|
83
|
+
f"/{aggregate['n_origins_requested']} origins completed."
|
|
84
|
+
)
|
|
85
|
+
for name, block in aggregate["metrics"].items():
|
|
86
|
+
if block is None:
|
|
87
|
+
continue
|
|
88
|
+
se = f" ± {block['se']:.4f}" if block["se"] is not None else ""
|
|
89
|
+
typer.echo(f" {name}: {block['mean']:.4f}{se} [{block['min']:.4f}, {block['max']:.4f}]")
|
|
90
|
+
typer.echo(f"\n wrote {cfg.backtest_dir / 'backtest_metrics.json'}")
|
|
91
|
+
typer.echo(f" wrote {cfg.backtest_dir / 'backtest_report.md'}")
|
|
92
|
+
if aggregate["n_origins_completed"] < aggregate["n_origins_requested"]:
|
|
93
|
+
typer.echo(" incomplete origins remain — rerun the same command to resume.")
|
|
94
|
+
raise typer.Exit(code=1)
|