← Back to Outliers

PhiladelphiaRatings toolMethodology recipe

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

  1. Filter philly_school_year_metrics by metric_key + year + subgroup=ALL + population_cut.

  2. Order by `comparison_group_percentile DESC` for top, `ASC` for bottom.

  3. 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.