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.
Table of Contents
Related Topics
Quick Actions