fix(compare): census-sourced FSM/EAL benchmarks; never fall back across measure definitions
The FSM chip anchored against disadvantaged_pct (a different measure, FSM6+CLA) whenever fsm_pct was null — which it always was, since the performance df has no fsm_pct. New fact_census_benchmarks mart supplies pupil-weighted FSM/EAL means per phase; the KS2-column medians that produced a bogus 50% 'secondary disadvantaged' anchor are gone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0146VHeLAWjDVE2B5uU67jCB
This commit is contained in:
+17
-14
@@ -525,13 +525,20 @@ def get_data_info(db: Session = None) -> dict:
|
||||
# SUPPLEMENTARY DATA — per-school detail page
|
||||
# =============================================================================
|
||||
|
||||
def compute_benchmarks(df: pd.DataFrame) -> dict:
|
||||
def compute_benchmarks(df: pd.DataFrame, census_benchmarks: dict | None = None) -> dict:
|
||||
"""State-school benchmarks computed from our dataset (spec §5/§8.6).
|
||||
|
||||
NOT official DfE figures — consumers must label them
|
||||
"state-school average (computed from our dataset)". The disadvantaged
|
||||
attainment average is weighted by cohort size (eligible_pupils) so
|
||||
small schools don't dominate; context measures are medians.
|
||||
small schools don't dominate.
|
||||
|
||||
Context measures (FSM/EAL/pupil counts) come from `census_benchmarks`
|
||||
(the fact_census_benchmarks mart, pupil-weighted, keyed by phase): the
|
||||
performance df has no fsm_pct at all, and its eal/disadvantaged columns
|
||||
are KS2-only — medianing them for "secondary" produced junk anchors
|
||||
from the handful of all-through schools. When the mart is unavailable
|
||||
these are None; never fall back across measure definitions.
|
||||
"""
|
||||
if df.empty or "year" not in df.columns:
|
||||
return {}
|
||||
@@ -567,18 +574,14 @@ def compute_benchmarks(df: pd.DataFrame) -> dict:
|
||||
)
|
||||
return round(float(w), 1)
|
||||
|
||||
def _block(sub, with_disadvantaged):
|
||||
median_pupils = None
|
||||
if "total_pupils" in sub.columns:
|
||||
mp = sub["total_pupils"].median()
|
||||
if pd.notna(mp):
|
||||
median_pupils = int(mp)
|
||||
def _block(sub, phase, with_disadvantaged):
|
||||
census = (census_benchmarks or {}).get(phase) or {}
|
||||
block = {
|
||||
"eal_pct": _median(sub, "eal_pct"),
|
||||
"eal_pct": census.get("eal_pct"),
|
||||
"sen_support_pct": _median(sub, "sen_support_pct"),
|
||||
"disadvantaged_pct": _median(sub, "disadvantaged_pct"),
|
||||
"fsm_pct": _median(sub, "fsm_pct"),
|
||||
"median_pupils": median_pupils,
|
||||
"disadvantaged_pct": _median(sub, "disadvantaged_pct") if with_disadvantaged else None,
|
||||
"fsm_pct": census.get("fsm_pct"),
|
||||
"median_pupils": census.get("median_pupils"),
|
||||
}
|
||||
if with_disadvantaged:
|
||||
block["disadvantaged_rwm_expected_pct"] = _weighted_disadvantaged(sub)
|
||||
@@ -587,8 +590,8 @@ def compute_benchmarks(df: pd.DataFrame) -> dict:
|
||||
return {
|
||||
"source": "state-school average (computed from our dataset)",
|
||||
"year": int(latest_year),
|
||||
"primary": _block(prim, with_disadvantaged=True),
|
||||
"secondary": _block(sec, with_disadvantaged=False),
|
||||
"primary": _block(prim, "primary", with_disadvantaged=True),
|
||||
"secondary": _block(sec, "secondary", with_disadvantaged=False),
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user