Effective Field Goal Percentage (eFG%)

Beginner 10 min read 1 views Nov 27, 2025
# Effective Field Goal Percentage (eFG%) ## Overview Effective Field Goal Percentage (eFG%) is an advanced basketball statistic that adjusts field goal percentage to account for the fact that three-point field goals are worth more than two-point field goals. It provides a more accurate measure of a player's shooting efficiency than traditional field goal percentage. ## The Formula ### Basic Formula ``` eFG% = (FGM + 0.5 × 3PM) / FGA ``` Where: - **FGM** = Field Goals Made (total made shots, both 2-point and 3-point) - **3PM** = Three-Point Field Goals Made - **FGA** = Field Goal Attempts (total shot attempts) ### Why 0.5? The 0.5 multiplier represents the 50% bonus value of a three-point shot compared to a two-point shot. Since a three-pointer is worth 1.5 times a two-pointer (3 points vs 2 points), we add half of the three-pointers made to account for this extra value. ### Calculation Example Player Statistics: - Field Goals Made: 400 - Three-Pointers Made: 100 - Field Goal Attempts: 900 ``` eFG% = (400 + 0.5 × 100) / 900 eFG% = (400 + 50) / 900 eFG% = 450 / 900 eFG% = 0.500 or 50.0% ``` ## Why eFG% Matters ### 1. Accurate Shooting Efficiency Traditional FG% treats all made shots equally, but eFG% recognizes that three-pointers are more valuable. This gives a truer picture of a player's scoring efficiency. ### 2. Better Player Comparison eFG% allows for fair comparisons between: - Perimeter shooters who take many three-pointers - Interior players who primarily shoot two-pointers - Players with different shot selection profiles ### 3. Predictive Value Research shows that eFG% is one of the strongest predictors of: - Team offensive efficiency - Game outcomes - Player offensive value ### 4. Shot Selection Insight A high eFG% indicates a player is taking and making high-value shots, reflecting good shot selection and execution. ## eFG% vs Traditional FG% ### Key Differences | Aspect | FG% | eFG% | |--------|-----|------| | **Calculation** | FGM / FGA | (FGM + 0.5 × 3PM) / FGA | | **Point Value** | All shots equal | Adjusts for 3-point value | | **Best For** | Interior players | All player types | | **Accuracy** | Basic efficiency | True shooting efficiency | ### Comparison Example **Player A (Perimeter Shooter):** - 6/15 FG (4/10 on 3PT, 2/5 on 2PT) - FG% = 40.0% - eFG% = (6 + 0.5 × 4) / 15 = 53.3% - Points Scored: 20 points **Player B (Interior Player):** - 8/15 FG (0/0 on 3PT, 8/15 on 2PT) - FG% = 53.3% - eFG% = (8 + 0.5 × 0) / 15 = 53.3% - Points Scored: 16 points Despite Player A having a lower FG%, both players have the same eFG% because Player A's three-pointers compensate for the lower percentage. However, Player A actually scored more points, demonstrating eFG%'s superior accuracy in measuring efficiency. ## NBA League Averages ### Historical Trends (2000-2024) | Season | League Avg eFG% | Notes | |--------|----------------|-------| | 2000-01 | 48.2% | Traditional two-point era | | 2005-06 | 49.1% | Steady improvement | | 2010-11 | 49.6% | Three-point shooting increases | | 2015-16 | 50.6% | Curry/Warriors revolution | | 2020-21 | 54.0% | Analytics-driven shot selection | | 2023-24 | 54.5% | Modern peak efficiency | ### Recent Trends The steady increase in league-wide eFG% reflects: - Greater emphasis on three-point shooting - Reduced mid-range attempts - Better shot selection through analytics - Improved spacing and offensive systems - Enhanced shooting skill development ## Position Benchmarks ### 2023-24 NBA Season Averages by Position | Position | Average eFG% | Elite (Top 10%) | Poor (Bottom 10%) | |----------|--------------|-----------------|-------------------| | **Point Guard** | 52.5% | 58%+ | <48% | | **Shooting Guard** | 53.0% | 59%+ | <49% | | **Small Forward** | 54.0% | 60%+ | <50% | | **Power Forward** | 55.5% | 62%+ | <51% | | **Center** | 59.0% | 65%+ | <54% | ### Position Analysis **Guards (PG/SG):** - Take more three-pointers - Lower eFG% due to shot difficulty - Elite guards exceed 58% through volume three-point shooting **Forwards (SF/PF):** - Balanced shot distribution - Mid-range eFG% values - Versatility in scoring locations **Centers:** - Highest eFG% due to close-range shots - Limited three-point attempts - Elite centers leverage size advantage near basket ## Historical Trends and Evolution ### Era Comparison **1980s-1990s (Pre-Analytics Era):** - League eFG%: 47-49% - Limited three-point shooting - Heavy mid-range focus - Traditional big-man dominance **2000s (Transition Era):** - League eFG%: 48-50% - Gradual increase in three-point attempts - Introduction of advanced analytics - Beginning of perimeter-oriented play **2010s (Analytics Revolution):** - League eFG%: 50-53% - Dramatic rise in three-point volume - Elimination of "inefficient" mid-range shots - Pace-and-space offense becomes standard **2020s (Modern Era):** - League eFG%: 54-55% - Peak efficiency through optimal shot selection - Nearly 40 three-point attempts per game - Position-less basketball emphasizing versatility ### Notable Historical eFG% Leaders (Single Season) 1. **Rudy Gobert (2020-21):** 73.7% eFG% 2. **DeAndre Jordan (2015-16):** 71.4% eFG% 3. **Artis Gilmore (1981-82):** 70.3% eFG% 4. **Tyson Chandler (2011-12):** 70.2% eFG% 5. **Stephen Curry (2015-16):** 63.0% eFG% (guards) ### Impact of Rule Changes - **2004 Hand-Check Rule:** Allowed better perimeter penetration, improved eFG% - **2018 Freedom of Movement:** Further reduced defensive contact, increased efficiency - **Three-Point Line Distance:** International distance adoption in 1994 temporarily lowered eFG% ## Code Examples ### Python Implementation ```python def calculate_efg(fgm, three_pm, fga): """ Calculate Effective Field Goal Percentage Parameters: ----------- fgm : int or float Field goals made three_pm : int or float Three-pointers made fga : int or float Field goal attempts Returns: -------- float Effective field goal percentage (0-1 scale) Raises: ------- ValueError If fga is zero or negative """ if fga <= 0: raise ValueError("Field goal attempts must be positive") efg = (fgm + 0.5 * three_pm) / fga return efg def efg_percentage_string(fgm, three_pm, fga, decimal_places=1): """ Calculate eFG% and return as formatted percentage string Parameters: ----------- fgm : int or float Field goals made three_pm : int or float Three-pointers made fga : int or float Field goal attempts decimal_places : int, optional Number of decimal places (default: 1) Returns: -------- str Formatted eFG% string (e.g., "54.3%") """ efg = calculate_efg(fgm, three_pm, fga) return f"{efg * 100:.{decimal_places}f}%" # Example usage if __name__ == "__main__": # Single player calculation player_fgm = 425 player_3pm = 150 player_fga = 950 efg = calculate_efg(player_fgm, player_3pm, player_fga) print(f"Player eFG%: {efg:.3f} or {efg * 100:.1f}%") print(f"Formatted: {efg_percentage_string(player_fgm, player_3pm, player_fga)}") # Comparison of two players players = { "Stephen Curry": {"fgm": 417, "3pm": 273, "fga": 919}, "Giannis Antetokounmpo": {"fgm": 608, "3pm": 17, "fga": 1035} } print("\nPlayer Comparison:") for name, stats in players.items(): efg = calculate_efg(stats["fgm"], stats["3pm"], stats["fga"]) fg_pct = stats["fgm"] / stats["fga"] print(f"{name}:") print(f" FG%: {fg_pct * 100:.1f}%") print(f" eFG%: {efg * 100:.1f}%") print(f" Difference: {(efg - fg_pct) * 100:.1f} percentage points") ``` ### Advanced Python with Pandas ```python import pandas as pd import numpy as np def calculate_team_efg(df, group_by='team'): """ Calculate eFG% for teams or groups in a DataFrame Parameters: ----------- df : pandas.DataFrame DataFrame with columns: fgm, three_pm, fga group_by : str, optional Column name to group by (default: 'team') Returns: -------- pandas.DataFrame Aggregated stats with eFG% """ grouped = df.groupby(group_by).agg({ 'fgm': 'sum', 'three_pm': 'sum', 'fga': 'sum' }).reset_index() grouped['efg_pct'] = (grouped['fgm'] + 0.5 * grouped['three_pm']) / grouped['fga'] grouped['efg_pct_formatted'] = grouped['efg_pct'].apply(lambda x: f"{x*100:.1f}%") return grouped def efg_rating(efg_pct, position='guard'): """ Rate a player's eFG% based on position benchmarks Parameters: ----------- efg_pct : float Effective field goal percentage (0-1 scale) position : str Player position (guard, forward, center) Returns: -------- str Rating description """ benchmarks = { 'guard': {'elite': 0.58, 'above_avg': 0.52, 'avg': 0.48, 'below_avg': 0.45}, 'forward': {'elite': 0.60, 'above_avg': 0.54, 'avg': 0.50, 'below_avg': 0.47}, 'center': {'elite': 0.65, 'above_avg': 0.59, 'avg': 0.54, 'below_avg': 0.50} } pos_benchmarks = benchmarks.get(position.lower(), benchmarks['guard']) if efg_pct >= pos_benchmarks['elite']: return "Elite" elif efg_pct >= pos_benchmarks['above_avg']: return "Above Average" elif efg_pct >= pos_benchmarks['avg']: return "Average" elif efg_pct >= pos_benchmarks['below_avg']: return "Below Average" else: return "Poor" # Example with sample data if __name__ == "__main__": # Create sample dataset data = { 'player': ['Player A', 'Player B', 'Player C', 'Player D', 'Player E'], 'team': ['Lakers', 'Lakers', 'Warriors', 'Warriors', 'Celtics'], 'position': ['guard', 'center', 'guard', 'forward', 'center'], 'fgm': [380, 520, 410, 450, 490], 'three_pm': [180, 5, 220, 95, 12], 'fga': [850, 780, 900, 870, 750] } df = pd.DataFrame(data) # Calculate individual eFG% df['efg_pct'] = (df['fgm'] + 0.5 * df['three_pm']) / df['fga'] df['efg_rating'] = df.apply(lambda row: efg_rating(row['efg_pct'], row['position']), axis=1) print("Individual Player Stats:") print(df[['player', 'position', 'efg_pct', 'efg_rating']]) # Calculate team eFG% team_stats = calculate_team_efg(df, group_by='team') print("\nTeam Stats:") print(team_stats) ``` ### R Implementation ```r # Calculate Effective Field Goal Percentage calculate_efg <- function(fgm, three_pm, fga) { #' Calculate Effective Field Goal Percentage #' #' @param fgm Numeric. Field goals made #' @param three_pm Numeric. Three-pointers made #' @param fga Numeric. Field goal attempts #' @return Numeric. Effective field goal percentage (0-1 scale) #' @examples #' calculate_efg(400, 100, 900) if (fga <= 0) { stop("Field goal attempts must be positive") } efg <- (fgm + 0.5 * three_pm) / fga return(efg) } efg_percentage_string <- function(fgm, three_pm, fga, decimal_places = 1) { #' Format eFG% as percentage string #' #' @param fgm Numeric. Field goals made #' @param three_pm Numeric. Three-pointers made #' @param fga Numeric. Field goal attempts #' @param decimal_places Integer. Number of decimal places (default: 1) #' @return Character. Formatted percentage string efg <- calculate_efg(fgm, three_pm, fga) formatted <- sprintf(paste0("%.", decimal_places, "f%%"), efg * 100) return(formatted) } efg_rating <- function(efg_pct, position = "guard") { #' Rate a player's eFG% based on position benchmarks #' #' @param efg_pct Numeric. Effective field goal percentage (0-1 scale) #' @param position Character. Player position (guard, forward, center) #' @return Character. Rating description benchmarks <- list( guard = list(elite = 0.58, above_avg = 0.52, avg = 0.48, below_avg = 0.45), forward = list(elite = 0.60, above_avg = 0.54, avg = 0.50, below_avg = 0.47), center = list(elite = 0.65, above_avg = 0.59, avg = 0.54, below_avg = 0.50) ) pos_key <- tolower(position) if (!pos_key %in% names(benchmarks)) { pos_key <- "guard" } pos_benchmarks <- benchmarks[[pos_key]] if (efg_pct >= pos_benchmarks$elite) { return("Elite") } else if (efg_pct >= pos_benchmarks$above_avg) { return("Above Average") } else if (efg_pct >= pos_benchmarks$avg) { return("Average") } else if (efg_pct >= pos_benchmarks$below_avg) { return("Below Average") } else { return("Poor") } } # Example usage if (interactive()) { # Single calculation player_fgm <- 425 player_3pm <- 150 player_fga <- 950 efg <- calculate_efg(player_fgm, player_3pm, player_fga) cat(sprintf("Player eFG%%: %.3f or %.1f%%\n", efg, efg * 100)) cat(sprintf("Formatted: %s\n", efg_percentage_string(player_fgm, player_3pm, player_fga))) # Player comparison cat("\nPlayer Comparison:\n") players <- data.frame( name = c("Stephen Curry", "Giannis Antetokounmpo"), fgm = c(417, 608), three_pm = c(273, 17), fga = c(919, 1035) ) for (i in 1:nrow(players)) { row <- players[i, ] efg <- calculate_efg(row$fgm, row$three_pm, row$fga) fg_pct <- row$fgm / row$fga cat(sprintf("%s:\n", row$name)) cat(sprintf(" FG%%: %.1f%%\n", fg_pct * 100)) cat(sprintf(" eFG%%: %.1f%%\n", efg * 100)) cat(sprintf(" Difference: %.1f percentage points\n", (efg - fg_pct) * 100)) } } ``` ### Advanced R with dplyr and ggplot2 ```r library(dplyr) library(ggplot2) # Create sample dataset create_sample_data <- function() { #' Create sample player statistics dataset #' #' @return data.frame with player statistics set.seed(42) data.frame( player = paste("Player", LETTERS[1:20]), team = sample(c("Lakers", "Warriors", "Celtics", "Heat", "Nets"), 20, replace = TRUE), position = sample(c("Guard", "Forward", "Center"), 20, replace = TRUE, prob = c(0.4, 0.4, 0.2)), fgm = sample(300:600, 20, replace = TRUE), three_pm = sample(10:250, 20, replace = TRUE), fga = sample(700:1100, 20, replace = TRUE) ) } calculate_team_efg <- function(df) { #' Calculate team-level eFG% statistics #' #' @param df data.frame with player statistics #' @return data.frame with team aggregates and eFG% df %>% group_by(team) %>% summarise( total_fgm = sum(fgm), total_3pm = sum(three_pm), total_fga = sum(fga), efg_pct = (total_fgm + 0.5 * total_3pm) / total_fga, .groups = 'drop' ) %>% mutate( efg_formatted = sprintf("%.1f%%", efg_pct * 100) ) %>% arrange(desc(efg_pct)) } visualize_efg_by_position <- function(df) { #' Create visualization of eFG% by position #' #' @param df data.frame with player statistics and calculated eFG% #' @return ggplot object # Calculate eFG% if not already present if (!"efg_pct" %in% names(df)) { df <- df %>% mutate(efg_pct = (fgm + 0.5 * three_pm) / fga) } # Create boxplot ggplot(df, aes(x = position, y = efg_pct * 100, fill = position)) + geom_boxplot(alpha = 0.7) + geom_jitter(width = 0.2, alpha = 0.5, size = 2) + labs( title = "Effective Field Goal Percentage by Position", x = "Position", y = "eFG%", caption = "Data: Sample NBA player statistics" ) + theme_minimal() + theme(legend.position = "none") + scale_fill_brewer(palette = "Set2") } # Example analysis if (interactive()) { # Create and analyze sample data player_data <- create_sample_data() # Calculate individual eFG% player_data <- player_data %>% mutate( efg_pct = (fgm + 0.5 * three_pm) / fga, fg_pct = fgm / fga, efg_rating = mapply(efg_rating, efg_pct, tolower(position)) ) # Display top performers cat("Top 5 Players by eFG%:\n") print(player_data %>% select(player, position, efg_pct, efg_rating) %>% arrange(desc(efg_pct)) %>% head(5)) # Team statistics cat("\nTeam eFG% Rankings:\n") team_stats <- calculate_team_efg(player_data) print(team_stats) # Create visualization plot <- visualize_efg_by_position(player_data) print(plot) } ``` ## Practical Applications ### 1. Player Evaluation eFG% helps identify: - Efficient scorers who maximize points per shot - Players with good shot selection - High-value offensive contributors ### 2. Team Building Teams use eFG% to: - Assess shooting needs - Balance roster composition - Optimize offensive spacing ### 3. Game Strategy Coaches use eFG% to: - Design offensive plays - Evaluate shot quality - Make substitution decisions ### 4. Contract Negotiations Front offices consider eFG% when: - Evaluating player value - Determining salary offers - Assessing trade targets ## Limitations While eFG% is highly useful, it has limitations: 1. **No Free Throws:** Doesn't account for foul-drawing ability 2. **No Context:** Doesn't consider shot difficulty or defense 3. **Volume Agnostic:** Treats high and low-volume shooters equally 4. **Assists Ignored:** Doesn't distinguish between assisted and unassisted shots For a more complete picture, combine eFG% with True Shooting Percentage (TS%) and other advanced metrics. ## Related Metrics - **True Shooting Percentage (TS%):** Includes free throws for complete efficiency - **Field Goal Percentage (FG%):** Traditional shooting percentage - **Three-Point Percentage (3P%):** Efficiency specifically on three-point shots - **Points Per Shot (PPS):** Direct scoring efficiency measure ## Conclusion Effective Field Goal Percentage is an essential modern basketball statistic that provides a more accurate assessment of shooting efficiency than traditional field goal percentage. By accounting for the added value of three-point shots, eFG% enables better player comparisons, team evaluation, and strategic decision-making. As the NBA continues to evolve toward analytics-driven play, eFG% remains a fundamental metric for understanding offensive performance.

Discussion

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