Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
prefix = "rtichoke/_vendor/rtichoke_viz/"
required = {
f"{prefix}VENDORED_FROM",
f"{prefix}rtichoke-viz-0.18.0.tar.gz",
f"{prefix}rtichoke-viz-0.19.0.tar.gz",
f"{prefix}rtichoke-viz.js",
f"{prefix}rtichoke-viz.css",
f"{prefix}rtichoke-viz.schema.json",
Expand Down
6 changes: 3 additions & 3 deletions src/rtichoke/_report_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
def _validate_spec_schema_version(spec: Mapping[str, object]) -> None:
"""Validate that spec schemaVersion strictly matches type requirements.

summary_metrics -> "1.0"
summary_metrics -> "1.0" or "1.1"
all v2 component types -> "2.0"
"""
spec_type = spec.get("type")
Expand All @@ -46,9 +46,9 @@ def _validate_spec_schema_version(spec: Mapping[str, object]) -> None:
raise ValueError("Report component spec is missing a string schemaVersion")

if spec_type in _V10_SCHEMA_TYPES:
if schema_version != "1.0":
if schema_version not in {"1.0", "1.1"}:
raise ValueError(
f"Component type {spec_type!r} requires schemaVersion '1.0', got {schema_version!r}"
f"Component type {spec_type!r} requires schemaVersion '1.0' or '1.1', got {schema_version!r}"
)
elif spec_type in _V20_SCHEMA_TYPES:
if schema_version != "2.0":
Expand Down
95 changes: 95 additions & 0 deletions src/rtichoke/_summary_metrics_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ class _PrevalenceMetric(TypedDict):
estimate: float | None


class _EventRiskMetric(TypedDict):
metric: str
owner: _PopulationOwner
horizon: float
estimate: float | None


class _AurocMetric(TypedDict):
metric: str
owner: _EvaluationOwner
Expand Down Expand Up @@ -178,6 +185,94 @@ def _prevalence_summary_metrics_spec(
}


def _event_risk_summary_metrics_spec(
performance_data: pl.DataFrame,
evaluation_metadata: Mapping[str, _EvaluationMetadata],
fixed_time_horizons: list[float],
) -> _SummaryMetricsSpec:
"""Build canonical population-owned Event Risk SummaryMetricsSpec v1.1."""
populations_list: list[_PopulationSpec] = []
metrics_list: list[dict[str, Any]] = []

seen_populations: dict[tuple[str, str], str] = {}
pop_counter = 1

for group, metadata in evaluation_metadata.items():
pop_name = metadata.population
label = "Population" if pop_name == _SHARED_POPULATION else pop_name
pop_key = (
(group, pop_name)
if pop_name != _SHARED_POPULATION
and list(evaluation_metadata.values())[0].model is None
else (pop_name, pop_name)
)
if pop_key not in seen_populations:
pop_id = f"population-{pop_counter}"
pop_counter += 1
seen_populations[pop_key] = pop_id
populations_list.append({"id": pop_id, "label": label})

pop_horizon_estimates: dict[tuple[tuple[str, str], float], set[float]] = {}
cutoff_zero_rows = (
performance_data.filter(pl.col("chosen_cutoff") == 0)
.select(
"reference_group",
"fixed_time_horizon",
(pl.col("real_positives") / pl.col("n")).alias("event_risk"),
)
.to_dicts()
)
for row in cutoff_zero_rows:
group = str(row["reference_group"])
if group not in evaluation_metadata:
continue
metadata = evaluation_metadata[group]
pop_name = metadata.population
pop_key = (
(group, pop_name)
if pop_name != _SHARED_POPULATION and metadata.model is None
else (pop_name, pop_name)
)
horizon = float(row["fixed_time_horizon"])
risk_val = row["event_risk"]
if risk_val is not None and math.isfinite(float(risk_val)):
pop_horizon_estimates.setdefault((pop_key, horizon), set()).add(
float(risk_val)
)

for horizon in fixed_time_horizons:
norm_horizon = float(horizon)
for pop_spec in populations_list:
pop_id = pop_spec["id"]
pop_key = next(
key for key, pid in seen_populations.items() if pid == pop_id
)
estimates = pop_horizon_estimates.get((pop_key, norm_horizon), set())
estimate: float | None = (
next(iter(estimates)) if len(estimates) == 1 else None
)

metric_item: _EventRiskMetric = {
"metric": "event_risk",
"owner": {
"type": "population",
"populationId": pop_id,
},
"horizon": norm_horizon,
"estimate": estimate,
}
metrics_list.append(cast(dict[str, Any], metric_item))

return {
"schemaVersion": "1.1",
"type": "summary_metrics",
"title": "Event Risk",
"evaluations": [],
"populations": populations_list,
"metrics": metrics_list,
}


def _auroc_summary_metrics_spec(
probs: dict[str, np.ndarray],
reals: np.ndarray | dict[str, np.ndarray],
Expand Down
8 changes: 4 additions & 4 deletions src/rtichoke/_vendor/rtichoke_viz/VENDORED_FROM
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
repository=https://github.com/uriahf/rtichoke_viz
release=v0.18.0
source_commit=dbabedb495ab70062ee635cd9d59eefcafe55a43
archive=rtichoke-viz-0.18.0.tar.gz
sha256=1cd3af962be8357d0fd4c2f2ecf5e5953774683de8854ead2facbac807b6bc84
release=v0.19.0
source_commit=26f22617bb34664ad65d6591ce7b20ecc080e739
archive=rtichoke-viz-0.19.0.tar.gz
sha256=bdeb1dd3041f700341730904492c7ab271bcdb9fa3637c7a9fd0a21f183bec70
Binary file not shown.
Binary file not shown.
Loading
Loading