Outliers
Data sources, queries, caveats, and steps for the Outliers ranking.
Summary
Ranks Philly schools by direction-adjusted peer percentile on the chosen metric/year/population-cut. Peers = KNN-40 derived from school level + admission bucket + sector + demographic Euclidean. Direction-adjusted: a high percentile always means good outcome regardless of the underlying metric direction.
Data sources
- Database tablephilly_schools
One row per Philly school. PK is ulcs_code (SDP canonical, = id_eos in PSSA, = SRC_School_ID × 10). Carries aun_code + pa_code for PDE-side joins.
- Database tablephilly_school_year_metrics
Long-format facts. PK (school_ulcs, year, metric_key, subgroup, population_cut). Carries comparison_group_percentile + citywide_percentile (direction-adjusted).
- Database tablephilly_comparison_groups
K-nearest-neighbor peer groups (k=20/30/40 derived; k=40 default). Hard filters: school level + admission bucket + sector. Demographic Euclidean across 7 features.
Steps
Filter philly_school_year_metrics by metric_key + year + subgroup=ALL + population_cut.
Order by `comparison_group_percentile DESC` for top, `ASC` for bottom.
Apply optional school_type filter (district / charter / etc.).
Caveats
Peer-percentile sensitivity to k is small in Philly (~3% of schools change top-10 peers between k=20 and k=40 — see peer-group-stability story). 43 schools are dropped from the peer-percentile space because their matching universe has <5 candidates; they appear in citywide percentile only.
Reproduce
The Outliers route reads philly_school_year_metrics directly via `lib/queries/philly-schools.ts:getPhillyOutliers`. To regenerate the underlying percentiles, run `compute_percentiles.ts` after any data refresh.
Recipe lives at data/cities/philly/stories/recipes.ts.