Hockey Prospect Evaluation

Beginner 10 min read 0 views Nov 27, 2025

Evaluating Junior and College Prospects

Scouting hockey prospects requires comparing players across different leagues with varying levels of competition. Statistical methods can help normalize performance and identify the most promising players regardless of where they play.

Major Development Leagues

  • CHL (OHL, WHL, QMJHL): Primary Canadian junior leagues
  • NCAA: U.S. college hockey
  • USHL: U.S. junior league
  • European Leagues: SHL, Liiga, etc.

Python: Adjusted Points Per Game Analysis

import pandas as pd
import numpy as np
from scipy import stats

# Load prospect data from multiple leagues
chl_prospects = pd.read_csv('chl_player_stats.csv')
ncaa_prospects = pd.read_csv('ncaa_player_stats.csv')

def calculate_adjusted_ppg(row):
    """Adjust points per game for league quality and age"""
    base_ppg = row['points'] / row['games_played']

    # League quality adjustments
    league_factors = {
        'OHL': 1.0,
        'WHL': 0.98,
        'QMJHL': 0.95,
        'NCAA': 1.1,
        'USHL': 0.85
    }

    league_adj = league_factors.get(row['league'], 1.0)

    # Age adjustment (younger players get bonus)
    age_factor = 1 + (20 - row['age']) * 0.05

    return base_ppg * league_adj * age_factor

# Apply adjustments
chl_prospects['adj_ppg'] = chl_prospects.apply(calculate_adjusted_ppg, axis=1)
ncaa_prospects['adj_ppg'] = ncaa_prospects.apply(calculate_adjusted_ppg, axis=1)

# Combine all prospects
all_prospects = pd.concat([chl_prospects, ncaa_prospects])

# Calculate prospect rankings
all_prospects['percentile_rank'] = all_prospects['adj_ppg'].rank(pct=True)

# Identify top prospects (95th percentile or higher)
top_prospects = all_prospects[
    all_prospects['percentile_rank'] >= 0.95
].sort_values('adj_ppg', ascending=False)

print("Top Ranked Prospects:")
print(top_prospects[['name', 'league', 'age', 'points',
                     'games_played', 'adj_ppg', 'percentile_rank']])

# Statistical profile analysis
def prospect_profile(player_data):
    """Generate comprehensive prospect profile"""
    profile = {
        'offensive_rating': (player_data['goals'] * 1.5 +
                           player_data['assists']) / player_data['games_played'],
        'production_consistency': player_data['points_last_10'].std(),
        'even_strength_ratio': player_data['es_points'] / player_data['points'],
        'shooting_efficiency': player_data['goals'] / player_data['shots']
    }
    return profile

# Generate profiles for top 10 prospects
for idx, prospect in top_prospects.head(10).iterrows():
    print(f"\n{prospect['name']} ({prospect['league']}):")
    profile = prospect_profile(prospect)
    for metric, value in profile.items():
        print(f"  {metric}: {value:.3f}")

R: Prospect Landscape Visualization

library(tidyverse)
library(scales)

# Load prospect data
chl_prospects <- read_csv("chl_player_stats.csv")
ncaa_prospects <- read_csv("ncaa_player_stats.csv")

# Function to calculate adjusted PPG
calculate_adjusted_ppg <- function(points, games, league, age) {
  base_ppg <- points / games

  # League quality factors
  league_factors <- c(
    "OHL" = 1.0, "WHL" = 0.98, "QMJHL" = 0.95,
    "NCAA" = 1.1, "USHL" = 0.85
  )

  league_adj <- ifelse(league %in% names(league_factors),
                       league_factors[league], 1.0)

  # Age adjustment
  age_factor <- 1 + (20 - age) * 0.05

  base_ppg * league_adj * age_factor
}

# Apply adjustments to all prospects
all_prospects <- bind_rows(chl_prospects, ncaa_prospects) %>%
  mutate(
    adj_ppg = calculate_adjusted_ppg(points, games_played, league, age),
    percentile_rank = percent_rank(adj_ppg)
  )

# Identify top prospects
top_prospects <- all_prospects %>%
  filter(percentile_rank >= 0.95) %>%
  arrange(desc(adj_ppg))

cat("Top Ranked Prospects:\n")
print(top_prospects %>%
  select(name, league, age, points, games_played, adj_ppg, percentile_rank))

# Create prospect evaluation matrix
prospect_matrix <- all_prospects %>%
  mutate(
    offensive_rating = (goals * 1.5 + assists) / games_played,
    es_ratio = es_points / points,
    shooting_pct = goals / shots * 100
  )

# Visualize prospect landscape
ggplot(prospect_matrix,
       aes(x = age, y = adj_ppg, color = league, size = games_played)) +
  geom_point(alpha = 0.6) +
  geom_hline(yintercept = quantile(prospect_matrix$adj_ppg, 0.95),
             linetype = "dashed", color = "red") +
  scale_y_continuous(labels = number_format(accuracy = 0.1)) +
  labs(title = "Hockey Prospect Evaluation Map",
       subtitle = "Red line indicates 95th percentile threshold",
       x = "Age", y = "Adjusted Points Per Game") +
  theme_minimal() +
  facet_wrap(~league)

# Top prospect summary statistics
top_stats <- top_prospects %>%
  group_by(league) %>%
  summarise(
    count = n(),
    avg_age = mean(age),
    avg_ppg = mean(adj_ppg),
    max_ppg = max(adj_ppg)
  )

print(top_stats)

Beyond Traditional Stats

Modern prospect evaluation goes beyond points and goals. Consider even-strength vs power-play production, shooting efficiency, physical development trajectory, and consistency across different competition levels.

Common Evaluation Pitfalls

  • Over-weighting power-play points in junior leagues
  • Ignoring age-for-league adjustments
  • Not accounting for team quality and linemates
  • Focusing solely on offensive production

Discussion

Have questions or feedback? Join our community discussion on Discord or GitHub Discussions.