Game-by-game offensive and defensive ratings are sourced from NBA.com via the nba_api library. Raw ratings are smoothed using a 5-game rolling average to reveal underlying trends while filtering out single-game noise.
Consistency is measured using rugosity—a metric borrowed from ecology and geography that quantifies how "jagged" or volatile a time series is. Rugosity is calculated as the arc-to-chord ratio: the total path length of the rating curve divided by the straight-line distance from start to end.
Interpretation:
Rugosity = 1.0 — Perfectly straight line (maximum consistency)Rugosity < 1.15 — Highly consistent performanceRugosity 1.15 - 1.35 — Moderate variationRugosity > 1.35 — Volatile, unpredictable performanceTeams are grouped into tiers based on net rating (offensive rating minus defensive rating). Thresholds:
Contenders — Net Rating > +6.0Legit Threats — Net Rating > +3.5Dangerous — Net Rating > +1.5Play-In — Net Rating > -1.5Up-and-Coming — Net Rating > -4.0Rebuild — Net Rating > -7.0Tank — Net Rating ≤ -7.0Teams are classified using a 4-dimensional matrix based on their position relative to league medians:
This creates 16 possible matrix positions (24), each with a unique label.
Team labels can be modified based on significant trends:
(↑O) or (↓D)