WNBA Draft Analysis

Beginner 10 min read 0 views Nov 27, 2025

WNBA Draft Analysis: Evaluating Draft Prospects

1. WNBA Draft Structure and Process

The WNBA Draft is an annual event where teams select eligible players to join the league. Understanding the draft structure is essential for prospect evaluation.

Draft Format

  • Three Rounds: The draft consists of three rounds with 12 picks per round (36 total)
  • Draft Lottery: The four non-playoff teams participate in a lottery for the top four picks
  • Order: Remaining picks follow reverse order of previous season's standings
  • Trading: Teams can trade draft picks before and during the draft

Eligibility Requirements

  • Players must be at least 22 years old during the calendar year of the draft
  • College seniors who have exhausted eligibility
  • International players meeting age requirements
  • Players who renounce college eligibility (rare in WNBA)

Draft Timeline

January-March:    College season, prospect evaluation
March-April:      Conference tournaments, NCAA Tournament
Early April:      Draft lottery (for top 4 picks)
Mid-April:        WNBA Draft (typically 2nd Monday after NCAA final)
May:              WNBA season begins
            

2. Key Evaluation Metrics for Prospects

Comprehensive prospect evaluation requires analyzing multiple dimensions of player performance and potential.

Statistical Metrics

Category Key Metrics Importance
Scoring PPG, TS%, eFG%, FTr, Shot Distribution High
Playmaking AST%, AST/TO, Creation Rate High
Rebounding TRB%, ORB%, DRB% Medium-High
Defense STL%, BLK%, DBPM, Defensive Rating High
Efficiency PER, BPM, WS/40, Usage Rate High
Shooting 3P%, FT%, Mid-range %, At-rim % Very High

Physical and Athletic Attributes

  • Height and Wingspan: Position-relative measurements
  • Speed and Agility: Court mobility and lateral quickness
  • Strength: Ability to finish through contact and defend physically
  • Vertical: Rebounding and shot-blocking potential
  • Injury History: Durability concerns and recovery patterns

Intangible Qualities

  • Basketball IQ and decision-making
  • Leadership and communication
  • Work ethic and coachability
  • Mental toughness and competitiveness
  • Adaptability to different systems

3. Python Code for Draft Prospect Analysis

Python provides powerful tools for analyzing prospect data and creating evaluation frameworks.

Prospect Statistical Profile Generator


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

class WNBAProspectAnalyzer:
    """Comprehensive WNBA draft prospect analysis system"""

    def __init__(self):
        self.scaler = StandardScaler()
        self.key_metrics = [
            'ppg', 'rpg', 'apg', 'spg', 'bpg',
            'fg_pct', 'three_pct', 'ft_pct',
            'ts_pct', 'efg_pct', 'per', 'ws_per_40'
        ]

    def load_prospect_data(self, filepath):
        """Load and preprocess prospect data"""
        df = pd.read_csv(filepath)

        # Calculate advanced metrics
        df['ts_pct'] = df['points'] / (2 * (df['fga'] + 0.44 * df['fta']))
        df['efg_pct'] = (df['fgm'] + 0.5 * df['three_pm']) / df['fga']
        df['ast_to_ratio'] = df['assists'] / df['turnovers']
        df['true_shooting_attempts'] = df['fga'] + 0.44 * df['fta']

        return df

    def calculate_composite_score(self, prospect_data):
        """Calculate weighted composite draft score"""
        weights = {
            'scoring': 0.25,
            'efficiency': 0.25,
            'playmaking': 0.15,
            'rebounding': 0.10,
            'defense': 0.15,
            'athleticism': 0.10
        }

        # Normalize metrics (0-100 scale)
        prospect_data['scoring_score'] = (
            prospect_data['ppg'] * 0.6 +
            prospect_data['ts_pct'] * 40 +
            prospect_data['three_pct'] * 40
        )

        prospect_data['efficiency_score'] = (
            prospect_data['per'] * 3 +
            prospect_data['ws_per_40'] * 5
        )

        prospect_data['playmaking_score'] = (
            prospect_data['apg'] * 10 +
            prospect_data['ast_to_ratio'] * 15
        )

        prospect_data['rebounding_score'] = (
            prospect_data['rpg'] * 8
        )

        prospect_data['defense_score'] = (
            prospect_data['spg'] * 15 +
            prospect_data['bpg'] * 15
        )

        # Calculate composite score
        prospect_data['composite_score'] = sum(
            prospect_data[f'{cat}_score'] * weight
            for cat, weight in weights.items()
            if f'{cat}_score' in prospect_data.columns
        )

        return prospect_data

    def create_prospect_radar(self, prospect_name, prospect_data):
        """Create radar chart for prospect evaluation"""
        categories = ['Scoring', 'Efficiency', 'Playmaking',
                     'Rebounding', 'Defense', 'Athleticism']

        # Extract scores for the prospect
        scores = [
            prospect_data['scoring_score'],
            prospect_data['efficiency_score'],
            prospect_data['playmaking_score'],
            prospect_data['rebounding_score'],
            prospect_data['defense_score'],
            prospect_data['athleticism_score']
        ]

        # Normalize to 0-100 scale
        scores = [min(100, max(0, score)) for score in scores]

        # Create radar chart
        angles = np.linspace(0, 2 * np.pi, len(categories), endpoint=False)
        scores = scores + scores[:1]
        angles = np.concatenate((angles, [angles[0]]))

        fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(projection='polar'))
        ax.plot(angles, scores, 'o-', linewidth=2, label=prospect_name)
        ax.fill(angles, scores, alpha=0.25)
        ax.set_xticks(angles[:-1])
        ax.set_xticklabels(categories)
        ax.set_ylim(0, 100)
        ax.set_title(f'{prospect_name} - Draft Prospect Profile',
                    size=16, weight='bold', pad=20)
        ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.1))
        ax.grid(True)

        plt.tight_layout()
        return fig

    def compare_prospects(self, prospects_df):
        """Compare multiple prospects across key metrics"""
        # Select top prospects
        prospects_df = prospects_df.sort_values('composite_score', ascending=False)
        top_prospects = prospects_df.head(10)

        # Create comparison visualization
        fig, axes = plt.subplots(2, 3, figsize=(15, 10))
        fig.suptitle('Top 10 WNBA Draft Prospects Comparison',
                    fontsize=16, weight='bold')

        metrics = [
            ('ppg', 'Points Per Game'),
            ('rpg', 'Rebounds Per Game'),
            ('apg', 'Assists Per Game'),
            ('ts_pct', 'True Shooting %'),
            ('per', 'Player Efficiency Rating'),
            ('composite_score', 'Composite Score')
        ]

        for idx, (metric, title) in enumerate(metrics):
            ax = axes[idx // 3, idx % 3]
            data = top_prospects.nlargest(10, metric)
            ax.barh(data['player_name'], data[metric], color='skyblue')
            ax.set_xlabel(title)
            ax.set_title(title, fontsize=12, weight='bold')
            ax.invert_yaxis()

        plt.tight_layout()
        return fig

    def identify_draft_steals(self, prospects_df, draft_position_col='projected_pick'):
        """Identify potential draft steals (high value, lower projection)"""
        prospects_df['value_score'] = (
            prospects_df['composite_score'] /
            prospects_df[draft_position_col]
        )

        # Find prospects with high composite scores but lower projections
        steals = prospects_df[
            (prospects_df['composite_score'] > 70) &
            (prospects_df[draft_position_col] > 15)
        ].sort_values('value_score', ascending=False)

        return steals[['player_name', 'composite_score',
                      draft_position_col, 'value_score']]

    def perform_clustering(self, prospects_df):
        """Cluster prospects by playing style"""
        from sklearn.cluster import KMeans

        # Select features for clustering
        features = ['ppg', 'rpg', 'apg', 'spg', 'bpg',
                   'three_pct', 'ts_pct', 'per']

        X = prospects_df[features].fillna(0)
        X_scaled = self.scaler.fit_transform(X)

        # Perform K-means clustering
        kmeans = KMeans(n_clusters=5, random_state=42)
        prospects_df['cluster'] = kmeans.fit_predict(X_scaled)

        # Label clusters by archetype
        cluster_labels = {
            0: 'Elite Scorer',
            1: 'Two-Way Wing',
            2: 'Floor General',
            3: 'Interior Force',
            4: '3-and-D Specialist'
        }

        prospects_df['archetype'] = prospects_df['cluster'].map(cluster_labels)

        return prospects_df

# Example usage
def analyze_draft_class(data_file):
    """Complete draft class analysis workflow"""
    analyzer = WNBAProspectAnalyzer()

    # Load data
    prospects = analyzer.load_prospect_data(data_file)

    # Calculate composite scores
    prospects = analyzer.calculate_composite_score(prospects)

    # Perform clustering
    prospects = analyzer.perform_clustering(prospects)

    # Generate reports
    print("Top 10 Prospects by Composite Score:")
    print(prospects.nlargest(10, 'composite_score')[
        ['player_name', 'composite_score', 'archetype']
    ])

    # Identify potential steals
    steals = analyzer.identify_draft_steals(prospects)
    print("\nPotential Draft Steals:")
    print(steals)

    # Create visualizations
    comparison_fig = analyzer.compare_prospects(prospects)
    comparison_fig.savefig('draft_prospects_comparison.png', dpi=300, bbox_inches='tight')

    return prospects

# Run analysis
# prospects_analyzed = analyze_draft_class('wnba_prospects_2024.csv')
            

College-to-WNBA Translation Model


import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import mean_squared_error, r2_score

class CollegeToWNBATranslator:
    """Predict WNBA performance based on college statistics"""

    def __init__(self):
        self.model = RandomForestRegressor(n_estimators=200,
                                          max_depth=10,
                                          random_state=42)
        self.feature_importance = None

    def prepare_translation_data(self, college_df, wnba_df):
        """Merge college and WNBA data for training"""
        # Merge datasets on player name
        merged = pd.merge(
            college_df.add_suffix('_college'),
            wnba_df.add_suffix('_wnba'),
            left_on='player_name_college',
            right_on='player_name_wnba'
        )

        return merged

    def calculate_translation_factors(self, merged_data):
        """Calculate average translation rates from college to WNBA"""
        translation_factors = {}

        metrics = ['ppg', 'rpg', 'apg', 'fg_pct', 'three_pct', 'ft_pct']

        for metric in metrics:
            college_col = f'{metric}_college'
            wnba_col = f'{metric}_wnba'

            if college_col in merged_data.columns and wnba_col in merged_data.columns:
                # Calculate ratio for each player
                ratios = merged_data[wnba_col] / merged_data[college_col]

                # Remove outliers (keep 5th to 95th percentile)
                ratios = ratios[
                    (ratios >= ratios.quantile(0.05)) &
                    (ratios <= ratios.quantile(0.95))
                ]

                translation_factors[metric] = {
                    'mean': ratios.mean(),
                    'median': ratios.median(),
                    'std': ratios.std()
                }

        return translation_factors

    def train_prediction_model(self, merged_data, target='ppg_wnba'):
        """Train model to predict WNBA stats from college performance"""
        # Select features
        feature_cols = [col for col in merged_data.columns
                       if col.endswith('_college') and
                       merged_data[col].dtype in ['int64', 'float64']]

        X = merged_data[feature_cols].fillna(0)
        y = merged_data[target].fillna(0)

        # Split data
        X_train, X_test, y_train, y_test = train_test_split(
            X, y, test_size=0.2, random_state=42
        )

        # Train model
        self.model.fit(X_train, y_train)

        # Evaluate
        train_score = self.model.score(X_train, y_train)
        test_score = self.model.score(X_test, y_test)
        y_pred = self.model.predict(X_test)
        rmse = np.sqrt(mean_squared_error(y_test, y_pred))

        # Feature importance
        self.feature_importance = pd.DataFrame({
            'feature': feature_cols,
            'importance': self.model.feature_importances_
        }).sort_values('importance', ascending=False)

        print(f"Train R²: {train_score:.3f}")
        print(f"Test R²: {test_score:.3f}")
        print(f"RMSE: {rmse:.3f}")
        print("\nTop 10 Most Important Features:")
        print(self.feature_importance.head(10))

        return self.model

    def predict_wnba_performance(self, prospect_college_stats):
        """Predict WNBA rookie season performance"""
        predictions = self.model.predict(prospect_college_stats)
        return predictions

    def adjust_for_conference(self, stats, conference_strength):
        """Adjust stats based on conference quality"""
        # Conference strength multipliers (example values)
        strength_factors = {
            'high_major': 1.0,      # Power 5 conferences
            'mid_major': 1.08,      # Strong mid-majors
            'low_major': 1.15       # Weaker conferences
        }

        factor = strength_factors.get(conference_strength, 1.0)

        # Adjust counting stats
        adjusted = stats.copy()
        for col in ['ppg', 'rpg', 'apg', 'spg', 'bpg']:
            if col in adjusted.columns:
                adjusted[col] = adjusted[col] / factor

        return adjusted

# Example usage
def project_prospect_performance(prospect_data, historical_data):
    """Complete prospect projection workflow"""
    translator = CollegeToWNBATranslator()

    # Prepare historical data
    college_stats = historical_data[historical_data['level'] == 'college']
    wnba_stats = historical_data[historical_data['level'] == 'wnba']

    merged = translator.prepare_translation_data(college_stats, wnba_stats)

    # Calculate translation factors
    factors = translator.calculate_translation_factors(merged)
    print("Translation Factors (College to WNBA):")
    for metric, values in factors.items():
        print(f"{metric}: {values['median']:.3f} (median)")

    # Train prediction model
    model = translator.train_prediction_model(merged, target='ppg_wnba')

    # Make predictions for current prospects
    predictions = translator.predict_wnba_performance(prospect_data)

    return predictions, factors

# Run projection
# predictions, factors = project_prospect_performance(prospects_2024, historical_data)
            

4. R Code for Projection Models

R provides advanced statistical modeling capabilities for draft prospect projections.

Linear Regression Model for Draft Success


library(tidyverse)
library(caret)
library(randomForest)
library(glmnet)
library(corrplot)

# WNBA Draft Success Prediction Model
# Predicts career Win Shares based on college statistics

# Load and prepare data
load_draft_data <- function(filepath) {
  data <- read.csv(filepath)

  # Calculate advanced metrics
  data <- data %>%
    mutate(
      ts_pct = points / (2 * (fga + 0.44 * fta)),
      efg_pct = (fgm + 0.5 * three_pm) / fga,
      ast_to_ratio = assists / turnovers,
      usage_rate = 100 * ((fga + 0.44 * fta + turnovers) * (team_minutes / 5)) /
                   (minutes * (team_fga + 0.44 * team_fta + team_turnovers)),
      rebound_rate = (offensive_rebounds + defensive_rebounds) / minutes * 40,
      per = calculate_per(data)
    )

  return(data)
}

# Calculate Player Efficiency Rating (PER)
calculate_per <- function(data) {
  uper <- (1 / data$minutes) * (
    data$three_pm +
    (2/3) * data$assists +
    (2 - factor * (team_ast / team_fgm)) * data$fgm +
    (data$ft * 0.5 * (1 + (1 - (team_ast / team_fgm)) + (2/3) * (team_ast / team_fgm))) -
    vop * data$turnovers -
    vop * data$drb_weight * (data$fga - data$fgm) -
    vop * 0.44 * (0.44 + (0.56 * data$drb_weight)) * (data$fta - data$ft) +
    vop * (1 - data$drb_weight) * (data$trb - data$orb) +
    vop * data$drb_weight * data$orb +
    vop * data$steals +
    vop * data$drb_weight * data$blocks -
    pf * ((lg_ft / lg_pf) - 0.44 * (lg_fta / lg_pf) * vop)
  )

  pace_adjustment <- lg_pace / team_pace
  per <- uper * pace_adjustment

  return(per)
}

# Build multiple regression models
build_draft_models <- function(train_data) {
  # Define predictor variables
  predictors <- c(
    'ppg', 'rpg', 'apg', 'spg', 'bpg',
    'fg_pct', 'three_pct', 'ft_pct',
    'ts_pct', 'efg_pct', 'per', 'usage_rate',
    'ast_to_ratio', 'rebound_rate',
    'height', 'weight', 'age'
  )

  # Target variable: career win shares in first 3 years
  target <- 'career_ws'

  # Prepare data
  model_data <- train_data %>%
    select(all_of(c(predictors, target))) %>%
    na.omit()

  # Split into training and validation sets
  set.seed(42)
  train_index <- createDataPartition(model_data[[target]], p = 0.8, list = FALSE)
  train_set <- model_data[train_index, ]
  val_set <- model_data[-train_index, ]

  # Model 1: Linear Regression
  lm_model <- lm(
    formula = as.formula(paste(target, "~", paste(predictors, collapse = " + "))),
    data = train_set
  )

  # Model 2: Ridge Regression
  x_train <- model.matrix(~ . - career_ws, data = train_set)[, -1]
  y_train <- train_set$career_ws

  ridge_model <- cv.glmnet(
    x = x_train,
    y = y_train,
    alpha = 0,  # Ridge
    nfolds = 10
  )

  # Model 3: Lasso Regression
  lasso_model <- cv.glmnet(
    x = x_train,
    y = y_train,
    alpha = 1,  # Lasso
    nfolds = 10
  )

  # Model 4: Random Forest
  rf_model <- randomForest(
    formula = as.formula(paste(target, "~", paste(predictors, collapse = " + "))),
    data = train_set,
    ntree = 500,
    mtry = 5,
    importance = TRUE
  )

  # Evaluate models
  models_list <- list(
    linear = lm_model,
    ridge = ridge_model,
    lasso = lasso_model,
    random_forest = rf_model
  )

  return(list(models = models_list, validation = val_set))
}

# Evaluate model performance
evaluate_models <- function(models_list, val_set, predictors) {
  results <- data.frame()

  # Prepare validation data
  x_val <- model.matrix(~ . - career_ws, data = val_set)[, -1]
  y_val <- val_set$career_ws

  # Linear model predictions
  lm_pred <- predict(models_list$linear, newdata = val_set)
  lm_rmse <- sqrt(mean((y_val - lm_pred)^2))
  lm_r2 <- cor(y_val, lm_pred)^2

  # Ridge predictions
  ridge_pred <- predict(models_list$ridge, newx = x_val, s = "lambda.min")
  ridge_rmse <- sqrt(mean((y_val - ridge_pred)^2))
  ridge_r2 <- cor(y_val, ridge_pred)^2

  # Lasso predictions
  lasso_pred <- predict(models_list$lasso, newx = x_val, s = "lambda.min")
  lasso_rmse <- sqrt(mean((y_val - lasso_pred)^2))
  lasso_r2 <- cor(y_val, lasso_pred)^2

  # Random Forest predictions
  rf_pred <- predict(models_list$random_forest, newdata = val_set)
  rf_rmse <- sqrt(mean((y_val - rf_pred)^2))
  rf_r2 <- cor(y_val, rf_pred)^2

  # Compile results
  results <- data.frame(
    Model = c("Linear Regression", "Ridge Regression", "Lasso Regression", "Random Forest"),
    RMSE = c(lm_rmse, ridge_rmse, lasso_rmse, rf_rmse),
    R_Squared = c(lm_r2, ridge_r2, lasso_r2, rf_r2)
  )

  print("Model Performance Comparison:")
  print(results)

  return(results)
}

# Feature importance analysis
analyze_feature_importance <- function(rf_model) {
  importance_df <- as.data.frame(importance(rf_model))
  importance_df$Feature <- rownames(importance_df)

  importance_df <- importance_df %>%
    arrange(desc(`%IncMSE`)) %>%
    head(15)

  # Plot feature importance
  ggplot(importance_df, aes(x = reorder(Feature, `%IncMSE`), y = `%IncMSE`)) +
    geom_bar(stat = "identity", fill = "steelblue") +
    coord_flip() +
    labs(
      title = "Top 15 Most Important Features for Draft Success",
      x = "Feature",
      y = "Importance (% Increase in MSE)"
    ) +
    theme_minimal() +
    theme(
      plot.title = element_text(face = "bold", size = 14),
      axis.text = element_text(size = 10)
    )

  ggsave("feature_importance_wnba_draft.png", width = 10, height = 6, dpi = 300)

  return(importance_df)
}

# Create draft prospect projections
project_draft_prospects <- function(prospects_data, model, model_type = "random_forest") {
  if (model_type == "random_forest") {
    predictions <- predict(model, newdata = prospects_data)
  } else if (model_type %in% c("ridge", "lasso")) {
    x_prospects <- model.matrix(~ . - 1, data = prospects_data)
    predictions <- predict(model, newx = x_prospects, s = "lambda.min")
  } else {
    predictions <- predict(model, newdata = prospects_data)
  }

  prospects_data$projected_ws <- predictions
  prospects_data$draft_grade <- cut(
    predictions,
    breaks = c(-Inf, 2, 5, 10, Inf),
    labels = c("Role Player", "Solid Contributor", "Impact Player", "All-Star Potential")
  )

  return(prospects_data)
}

# Visualize prospect projections
visualize_draft_board <- function(prospects_with_projections) {
  # Create draft board visualization
  ggplot(prospects_with_projections,
         aes(x = reorder(player_name, -projected_ws),
             y = projected_ws,
             fill = draft_grade)) +
    geom_bar(stat = "identity") +
    coord_flip() +
    scale_fill_manual(
      values = c(
        "Role Player" = "#d73027",
        "Solid Contributor" = "#fee08b",
        "Impact Player" = "#66bd63",
        "All-Star Potential" = "#1a9850"
      )
    ) +
    labs(
      title = "WNBA Draft Prospects - Projected Career Win Shares",
      x = "Player",
      y = "Projected Win Shares (First 3 Years)",
      fill = "Draft Grade"
    ) +
    theme_minimal() +
    theme(
      plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
      axis.text.y = element_text(size = 9),
      legend.position = "bottom"
    )

  ggsave("wnba_draft_board_projections.png", width = 12, height = 10, dpi = 300)
}

# Similarity analysis
find_similar_players <- function(prospect, historical_players, n = 5) {
  # Calculate distance metrics
  features <- c('ppg', 'rpg', 'apg', 'ts_pct', 'per', 'height', 'weight')

  # Normalize features
  prospect_normalized <- scale(prospect[features])
  historical_normalized <- scale(historical_players[features])

  # Calculate Euclidean distance
  distances <- apply(historical_normalized, 1, function(x) {
    sqrt(sum((x - prospect_normalized)^2))
  })

  # Find most similar players
  similar_indices <- order(distances)[1:n]
  similar_players <- historical_players[similar_indices, ]
  similar_players$similarity_score <- 100 - (distances[similar_indices] / max(distances) * 100)

  return(similar_players)
}

# Main execution workflow
main_draft_analysis <- function() {
  # Load data
  historical_data <- load_draft_data("wnba_draft_historical.csv")
  prospects_2024 <- load_draft_data("wnba_prospects_2024.csv")

  # Build models
  model_results <- build_draft_models(historical_data)

  # Evaluate models
  performance <- evaluate_models(
    model_results$models,
    model_results$validation,
    predictors
  )

  # Analyze feature importance
  importance <- analyze_feature_importance(model_results$models$random_forest)

  # Project current prospects
  prospects_projected <- project_draft_prospects(
    prospects_2024,
    model_results$models$random_forest,
    model_type = "random_forest"
  )

  # Visualize results
  visualize_draft_board(prospects_projected)

  # Print top prospects
  cat("\n=== Top 10 Draft Prospects by Projected Win Shares ===\n")
  top_prospects <- prospects_projected %>%
    arrange(desc(projected_ws)) %>%
    select(player_name, projected_ws, draft_grade, ppg, rpg, apg, per) %>%
    head(10)

  print(top_prospects)

  return(list(
    models = model_results$models,
    prospects = prospects_projected,
    importance = importance
  ))
}

# Run analysis
# results <- main_draft_analysis()
            

Bayesian Draft Success Model


library(rstan)
library(bayesplot)
library(rstanarm)

# Bayesian hierarchical model for draft success
# Accounts for uncertainty and conference effects

build_bayesian_draft_model <- function(draft_data) {
  # Stan model specification
  stan_code <- "
  data {
    int N;                    // number of players
    int K;                    // number of predictors
    matrix[N, K] X;                    // predictor matrix
    vector[N] y;                       // outcome (win shares)
    int n_conferences;        // number of conferences
    int conference[N];  // conference index
  }

  parameters {
    vector[K] beta;                    // coefficients
    real sigma;               // error SD
    vector[n_conferences] conference_effect;  // conference adjustments
    real sigma_conference;    // conference SD
  }

  model {
    vector[N] mu;

    // Priors
    beta ~ normal(0, 5);
    sigma ~ exponential(1);
    conference_effect ~ normal(0, sigma_conference);
    sigma_conference ~ exponential(1);

    // Likelihood
    for (i in 1:N) {
      mu[i] = X[i] * beta + conference_effect[conference[i]];
    }
    y ~ normal(mu, sigma);
  }

  generated quantities {
    vector[N] y_pred;
    vector[N] log_lik;

    for (i in 1:N) {
      real mu_i = X[i] * beta + conference_effect[conference[i]];
      y_pred[i] = normal_rng(mu_i, sigma);
      log_lik[i] = normal_lpdf(y[i] | mu_i, sigma);
    }
  }
  "

  # Prepare data for Stan
  predictors <- c('ppg', 'rpg', 'apg', 'per', 'ts_pct', 'height')
  X <- as.matrix(draft_data[, predictors])
  y <- draft_data$career_ws
  conference <- as.integer(factor(draft_data$conference))

  stan_data <- list(
    N = nrow(X),
    K = ncol(X),
    X = X,
    y = y,
    n_conferences = max(conference),
    conference = conference
  )

  # Fit model
  fit <- stan(
    model_code = stan_code,
    data = stan_data,
    chains = 4,
    iter = 2000,
    warmup = 1000,
    cores = 4
  )

  return(fit)
}

# Generate predictions with uncertainty intervals
predict_with_uncertainty <- function(model, new_data) {
  posterior_samples <- extract(model)

  # Extract coefficients
  beta_samples <- posterior_samples$beta

  # Prepare predictor matrix
  predictors <- c('ppg', 'rpg', 'apg', 'per', 'ts_pct', 'height')
  X_new <- as.matrix(new_data[, predictors])

  # Generate predictions for each posterior sample
  n_samples <- nrow(beta_samples)
  predictions <- matrix(NA, nrow = n_samples, ncol = nrow(X_new))

  for (i in 1:n_samples) {
    predictions[i, ] <- X_new %*% beta_samples[i, ]
  }

  # Calculate summary statistics
  pred_summary <- data.frame(
    player = new_data$player_name,
    mean = colMeans(predictions),
    median = apply(predictions, 2, median),
    sd = apply(predictions, 2, sd),
    lower_95 = apply(predictions, 2, quantile, probs = 0.025),
    upper_95 = apply(predictions, 2, quantile, probs = 0.975),
    lower_80 = apply(predictions, 2, quantile, probs = 0.10),
    upper_80 = apply(predictions, 2, quantile, probs = 0.90)
  )

  return(pred_summary)
}

# Visualize uncertainty in projections
plot_prediction_intervals <- function(predictions) {
  predictions <- predictions %>%
    arrange(desc(mean)) %>%
    head(20)

  ggplot(predictions, aes(x = reorder(player, mean))) +
    geom_point(aes(y = mean), size = 3, color = "darkblue") +
    geom_errorbar(
      aes(ymin = lower_95, ymax = upper_95),
      width = 0.2,
      color = "steelblue",
      alpha = 0.5
    ) +
    geom_errorbar(
      aes(ymin = lower_80, ymax = upper_80),
      width = 0.4,
      color = "steelblue",
      size = 1
    ) +
    coord_flip() +
    labs(
      title = "WNBA Draft Projections with Uncertainty",
      subtitle = "Dark bars: 80% credible interval, Light bars: 95% credible interval",
      x = "Player",
      y = "Projected Win Shares"
    ) +
    theme_minimal()
}
            

5. Historical Draft Success Analysis

Understanding historical patterns helps identify which factors most reliably predict WNBA success.

Draft Position and Career Outcomes

Draft Range Avg Career WS All-Star % Starter % Years in League
Picks 1-3 18.5 45% 78% 8.2
Picks 4-8 12.3 22% 62% 6.8
Picks 9-12 8.7 12% 45% 5.5
Round 2 (13-24) 4.2 5% 28% 3.8
Round 3 (25-36) 1.8 1% 12% 2.2

Key Findings from Historical Analysis

Top Pick Success Rate

  • Hit Rate: 65% of #1 overall picks become All-Stars
  • Busts: Only 8% of top picks fail to become rotation players
  • Elite Outcomes: 35% reach MVP-caliber status
  • Notable #1 Picks: Breanna Stewart, A'ja Wilson, Sabrina Ionescu

Second Round Success Stories

  • Ruth Riley (Pick 13, 2001) - WNBA Champion, Finals MVP
  • Allie Quigley (Pick 22, 2008) - 2x Three-Point Contest Champion
  • Jonquel Jones (Pick 6, 2016) - MVP, multiple All-Star selections
  • Chelsea Gray (Pick 11, 2014) - Finals MVP, elite playmaker

Draft Class Quality Variations

Strongest Draft Classes:
2016: Breanna Stewart, Moriah Jefferson, Aerial Powers, Jonquel Jones
2018: A'ja Wilson, Kelsey Mitchell, Diamond DeShields, Victoria Vivians
2020: Sabrina Ionescu, Satou Sabally, Lauren Cox, Chennedy Carter
2022: Rhyne Howard, NaLyssa Smith, Shakira Austin, Emily Engstler

Weaker Draft Classes:
2011: Maya Moore (elite), but limited depth
2014: Limited impact beyond Jewell Loyd
2017: Deep role players, fewer stars
            

Statistical Predictors of Success

Most Predictive College Stats (Correlation with WNBA Success)

  1. True Shooting % (r=0.67): Efficiency translates reliably
  2. Player Efficiency Rating (r=0.64): Overall production indicator
  3. Win Shares (r=0.61): Impact on team success
  4. Box Plus/Minus (r=0.58): Advanced impact metrics
  5. 3-Point % (r=0.56): Critical skill in modern game
  6. Assist-to-Turnover Ratio (r=0.51): Decision-making quality
  7. Defensive Rating (r=0.48): Two-way potential

Less Predictive Metrics

  • Points Per Game (r=0.42): Volume scoring doesn't always translate
  • Raw Rebounds (r=0.39): Position-dependent, context matters
  • Blocks Per Game (r=0.35): Positional skill, limited scope
  • Steals Per Game (r=0.33): High variance, gambling concerns

6. College-to-WNBA Translation Factors

Understanding how college performance translates to professional success is crucial for accurate evaluation.

Statistical Translation Rates

Metric Translation Factor Notes
Points Per Game 0.52x Scoring volume decreases significantly
Rebounds Per Game 0.68x Better translation, position-dependent
Assists Per Game 0.61x Playmaking opportunities reduced
Field Goal % -3.2% Harder shots, better defenders
3-Point % -2.8% Longer distance, tighter defense
Free Throw % -0.8% Most consistent translation
Minutes Per Game 0.74x Rookies earn playing time gradually

Conference Strength Adjustments

Player statistics should be adjusted based on conference quality:

Power 5 Conferences (No Adjustment Needed)

  • ACC, Big Ten, Big 12, Pac-12, SEC
  • Strongest competition, best preparation for WNBA
  • Stats can be evaluated at face value

Strong Mid-Major Conferences (+5-8% Adjustment)

  • Big East, American, WCC, Mountain West
  • Competitive basketball, some elite programs
  • Slight downward adjustment for inflated stats

Mid-Major Conferences (+10-15% Adjustment)

  • Conference USA, MAC, Sun Belt, A-10
  • Variable competition quality
  • Consider schedule strength and out-of-conference performance

Low-Major Conferences (+15-25% Adjustment)

  • Ohio Valley, MAAC, Horizon, Big South
  • Weaker competition inflates statistics
  • Focus on efficiency metrics and physical tools

Age and Experience Factors

Optimal Draft Age

  • 21-22 years old: Ideal development curve, long career ahead
  • 23-24 years old: More polished, but less upside
  • 25+ years old: Limited projection, "what you see is what you get"

College Experience

  • 4-year players: More developed skills, lower ceiling
  • 3-year players: Balance of development and upside
  • Redshirt seniors: Extra year of maturity, injury concerns

Physical Tools Translation

Height and Length

  • Guards (5'7"-5'11"): Speed and skill become more critical
  • Wings (6'0"-6'3"): Versatility highly valued in WNBA
  • Forwards (6'2"-6'5"): Can play multiple positions
  • Posts (6'4"+): Must extend range or excel defensively

Athleticism Premium

  • Elite athletes translate better than college stat compilers
  • Quick first step and lateral speed essential for guards
  • Vertical explosion critical for rebounding and defense
  • End-to-end speed valuable in WNBA's fast-paced game

Skill Translation Hierarchy

Skills That Translate Best

  1. Three-point shooting: Always valuable, spacing crucial
  2. Free throw shooting: Consistent indicator of touch
  3. Ball-handling: Guards must handle pressure
  4. Defensive positioning: IQ-based skills transfer
  5. Passing vision: Court awareness translates

Skills That Struggle to Translate

  1. Interior scoring vs weaker competition: WNBA posts are elite
  2. Gambling on defense: Steals against better competition harder
  3. Athleticism-only game: Need skills to complement
  4. One-dimensional scoring: Must develop versatility
  5. Size advantages: Everyone is talented in WNBA

7. Best Practices for Draft Evaluation

Comprehensive guidelines for scouts, analysts, and teams evaluating WNBA draft prospects.

Holistic Evaluation Framework

1. Multi-Year Performance Analysis

  • Progression curves: Look for year-over-year improvement
  • Consistency: Evaluate performance across seasons
  • Peak performance: High-level games show ceiling
  • Tournament performance: Production under pressure
  • Injury history: Pattern of missed games concerning

2. Context-Aware Statistical Analysis

  • Usage rate context: High scorers on weak teams vs role players on contenders
  • Teammate quality: Playing with elite talent or carrying team
  • Coaching system: Scheme fit and role within system
  • Pace of play: Adjust for team tempo
  • Schedule strength: Performance vs ranked opponents

3. Film Study Priorities

  • Defensive clips: Effort, positioning, recovery
  • Decision-making: Reading defenses, shot selection
  • Movement without ball: Cutting, screening, spacing
  • Transition play: Speed, decision-making in open court
  • Body language: Leadership, competitiveness, frustration response

Red Flags to Watch

Statistical Red Flags

  • High turnover rate (>20% TOV%): Decision-making concerns
  • Poor free throw shooting (<65%): Shooting concerns
  • Low assist rate for guards (<15% AST%): Limited playmaking
  • Very high usage with poor efficiency: Empty calories
  • Declining performance trajectory: Peaked too early

Physical Red Flags

  • Limited athleticism: Can't create separation
  • Poor lateral quickness: Defensive liability
  • Undersized for position: Without compensating skills
  • Slow release on shot: Will struggle vs WNBA closeouts
  • Multiple serious injuries: Durability questions

Intangible Red Flags

  • Poor body language: Negative on-court demeanor
  • Teammate conflicts: Chemistry concerns
  • Coaching issues: Pattern of conflicts with coaches
  • Off-court concerns: Professionalism questions
  • Low motor: Inconsistent effort level

Green Flags (Positive Indicators)

Statistical Green Flags

  • Elite efficiency (>60% TS%): Skill translates to production
  • Excellent AST/TO ratio (>2.5): Makes good decisions
  • High stock rate (STL%+BLK%): Defensive impact
  • Strong 3P% on volume (>37% on 4+ attempts): Legitimate shooter
  • Improvement trajectory: Getting better each year

Physical Green Flags

  • Elite speed/quickness: Changes game at WNBA level
  • Long wingspan: Defensive versatility
  • Strong frame: Can handle physical play
  • High motor: Plays hard on every possession
  • Clean injury history: Durability proven

Intangible Green Flags

  • Leadership qualities: Vocal, positive influence
  • Winning background: Success follows player
  • High basketball IQ: Makes winning plays
  • Competitive drive: Rises to challenges
  • Professional approach: Takes game seriously

Team Fit Considerations

Matching Prospects to Team Needs

  • Immediate contributors: Veterans, polished players for contenders
  • Developmental prospects: High upside for rebuilding teams
  • System fit: Skills match coaching philosophy
  • Positional needs: Addressing roster gaps
  • Timeline alignment: Matching core player ages

Interview and Character Assessment

Key Interview Topics

  • Basketball knowledge: Understanding of game concepts
  • Work ethic: Training habits, offseason dedication
  • Adaptability: Willingness to accept role
  • Team-first mentality: Prioritizing winning
  • Long-term goals: Career ambitions, commitment level

Final Evaluation Checklist

□ Reviewed 3+ full games from junior/senior seasons
□ Analyzed performance vs top-25 opponents
□ Calculated advanced metrics (PER, BPM, WS)
□ Adjusted stats for conference strength
□ Compared to historical prospects at position
□ Evaluated physical measurements and athleticism
□ Conducted in-person or video interview
□ Checked references with college coaches
□ Reviewed medical records and injury history
□ Assessed character and off-court behavior
□ Identified specific WNBA team fits
□ Projected realistic role as rookie
□ Estimated 3-year career trajectory
□ Calculated draft value vs projected pick
□ Developed comprehensive scouting report
            

Avoiding Common Evaluation Mistakes

Overvaluing

  • College scoring volume: Points in weak conference don't translate
  • Single elite skill: One-dimensional players struggle
  • Physical tools alone: Need basketball skills too
  • Tournament performances: Small sample size
  • Potential over production: Projection over reality

Undervaluing

  • Role players on elite teams: High-level supporting skills
  • Shooting specialists: Always valuable in WNBA
  • Defensive specialists: Two-way play crucial
  • Late bloomers: Development curves vary
  • International prospects: Less exposure, high skill

Post-Draft Development Expectations

Realistic Rookie Year Expectations

  • Top 3 picks: Immediate starters, 25+ minutes, All-Rookie team
  • Picks 4-8: Rotation players, 15-20 minutes, role contribution
  • Picks 9-12: Spot minutes, development focus, 10-15 minutes
  • Second round: Practice squad/limited minutes, year to adjust
  • Third round: Roster battles, likely cuts, long-term projects

Conclusion

Successful WNBA draft evaluation requires a comprehensive approach that combines statistical analysis, film study, physical assessment, and character evaluation. By understanding historical translation patterns, accounting for context, and maintaining a holistic perspective, teams can identify prospects who will succeed at the professional level.

The most successful draft strategies balance immediate needs with long-term development, recognize that different prospects fit different team situations, and avoid overreliance on any single evaluation metric. Remember that draft evaluation is both art and science—quantitative analysis provides the foundation, but qualitative assessment often makes the difference between identifying stars and missing on prospects.

Discussion

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