Traditional Stats Foundation
Beginner
10 min read
1 views
Nov 27, 2025
# Traditional Stats Foundation
## Introduction
Box score statistics are the fundamental building blocks of basketball analysis. This guide covers traditional stats, their calculation, and interpretation.
## Core Box Score Metrics
### Counting Stats
- **Points (PTS)** - Total points scored
- **Rebounds (REB)** - Total rebounds (offensive + defensive)
- **Assists (AST)** - Passes leading to made field goals
- **Steals (STL)** - Defensive deflections resulting in possession
- **Blocks (BLK)** - Shots blocked
- **Turnovers (TOV)** - Lost possessions
## Python Implementation
```python
import pandas as pd
import numpy as np
class BoxScoreAnalyzer:
def __init__(self, box_score_data):
"""Initialize with box score DataFrame"""
self.data = box_score_data
def calculate_advanced_metrics(self):
"""Calculate advanced metrics from traditional box score"""
df = self.data.copy()
# True Shooting Percentage
df['TS%'] = (df['PTS'] / (2 * (df['FGA'] + 0.44 * df['FTA']))) * 100
# Effective Field Goal Percentage
df['eFG%'] = ((df['FGM'] + 0.5 * df['3PM']) / df['FGA']) * 100
# Usage Rate (simplified version)
if 'MIN' in df.columns and 'TEAM_MIN' in df.columns:
df['USG%'] = ((df['FGA'] + 0.44 * df['FTA'] + df['TOV']) *
(df['TEAM_MIN'] / 5) /
(df['MIN'] * (df['TEAM_FGA'] + 0.44 * df['TEAM_FTA'] + df['TEAM_TOV']))) * 100
# Assist Ratio
df['AST_RATIO'] = (df['AST'] / df['FGA']) * 100
# Rebound Percentage (simplified)
df['REB%'] = (df['REB'] / df['MIN']) * 48
return df
def calculate_four_factors(self, team_stats):
"""Calculate Dean Oliver's Four Factors"""
factors = {}
# 1. Shooting (eFG%)
factors['eFG%'] = ((team_stats['FGM'] + 0.5 * team_stats['3PM']) /
team_stats['FGA']) * 100
# 2. Turnovers (TOV%)
factors['TOV%'] = (team_stats['TOV'] /
(team_stats['FGA'] + 0.44 * team_stats['FTA'] + team_stats['TOV'])) * 100
# 3. Rebounding (ORB%)
if 'OPP_DRB' in team_stats:
factors['ORB%'] = (team_stats['ORB'] /
(team_stats['ORB'] + team_stats['OPP_DRB'])) * 100
# 4. Free Throws (FT Rate)
factors['FT_RATE'] = team_stats['FTA'] / team_stats['FGA']
return factors
def calculate_player_efficiency_rating(self, player_stats, team_stats, league_stats):
"""Calculate Player Efficiency Rating (PER)"""
# Simplified PER calculation
factor = (2/3) - (0.5 * (league_stats['AST'] / league_stats['FGM'])) / \
(2 * (league_stats['FGM'] / league_stats['FTM']))
VOP = league_stats['PTS'] / (league_stats['FGA'] - league_stats['ORB'] +
league_stats['TOV'] + 0.44 * league_stats['FTA'])
DRB_pct = (league_stats['TRB'] - league_stats['ORB']) / league_stats['TRB']
uPER = (1 / player_stats['MIN']) * (
player_stats['3PM'] +
(2/3) * player_stats['AST'] +
(2 - factor * (team_stats['AST'] / team_stats['FGM'])) * player_stats['FGM'] +
(player_stats['FTM'] * 0.5 * (1 + (1 - (team_stats['AST'] / team_stats['FGM'])) +
(2/3) * (team_stats['AST'] / team_stats['FGM']))) -
VOP * player_stats['TOV'] -
VOP * DRB_pct * (player_stats['FGA'] - player_stats['FGM']) -
VOP * 0.44 * (0.44 + (0.56 * DRB_pct)) * (player_stats['FTA'] - player_stats['FTM']) +
VOP * (1 - DRB_pct) * (player_stats['TRB'] - player_stats['ORB']) +
VOP * DRB_pct * player_stats['ORB'] +
VOP * player_stats['STL'] +
VOP * DRB_pct * player_stats['BLK'] -
player_stats['PF'] * ((league_stats['FTM'] / league_stats['PF']) -
0.44 * (league_stats['FTA'] / league_stats['PF']) * VOP)
)
return uPER
def summarize_game_performance(self, player_id):
"""Generate performance summary for a player"""
player = self.data[self.data['PLAYER_ID'] == player_id].iloc[0]
summary = {
'player_name': player['PLAYER_NAME'],
'minutes': player['MIN'],
'points': player['PTS'],
'rebounds': player['REB'],
'assists': player['AST'],
'fg_pct': (player['FGM'] / player['FGA'] * 100) if player['FGA'] > 0 else 0,
'plus_minus': player['+/-'] if '+/-' in player else None
}
return summary
# Usage
# analyzer = BoxScoreAnalyzer(box_score_df)
# advanced_stats = analyzer.calculate_advanced_metrics()
# print(advanced_stats[['PLAYER_NAME', 'PTS', 'TS%', 'eFG%']].head())
```
## R Implementation
```r
library(dplyr)
library(tidyr)
calculate_advanced_metrics <- function(box_score_data) {
box_score_data %>%
mutate(
# True Shooting Percentage
TS_PCT = (PTS / (2 * (FGA + 0.44 * FTA))) * 100,
# Effective Field Goal Percentage
eFG_PCT = ((FGM + 0.5 * three_PM) / FGA) * 100,
# Assist Ratio
AST_RATIO = (AST / FGA) * 100,
# Rebound Rate per 48 minutes
REB_RATE = (REB / MIN) * 48,
# Points per shot attempt
PPS = PTS / (FGA + 0.44 * FTA)
)
}
calculate_four_factors <- function(team_stats) {
list(
# Shooting
eFG_PCT = ((team_stats$FGM + 0.5 * team_stats$three_PM) / team_stats$FGA) * 100,
# Turnovers
TOV_PCT = (team_stats$TOV /
(team_stats$FGA + 0.44 * team_stats$FTA + team_stats$TOV)) * 100,
# Rebounding
ORB_PCT = if("OPP_DRB" %in% names(team_stats)) {
(team_stats$ORB / (team_stats$ORB + team_stats$OPP_DRB)) * 100
} else {
NA
},
# Free Throws
FT_RATE = team_stats$FTA / team_stats$FGA
)
}
summarize_player_performance <- function(box_score_data, player_id) {
player <- box_score_data %>%
filter(PLAYER_ID == player_id)
if (nrow(player) == 0) {
return(NULL)
}
player <- player[1, ]
list(
player_name = player$PLAYER_NAME,
minutes = player$MIN,
points = player$PTS,
rebounds = player$REB,
assists = player$AST,
fg_pct = if(player$FGA > 0) (player$FGM / player$FGA * 100) else 0,
plus_minus = if("PLUS_MINUS" %in% names(player)) player$PLUS_MINUS else NA
)
}
# Usage
# advanced_stats <- calculate_advanced_metrics(box_score_df)
# four_factors <- calculate_four_factors(team_stats_df)
```
## Key Efficiency Metrics
### Shooting Efficiency
- **FG%** - Field Goal Percentage
- **3P%** - Three Point Percentage
- **FT%** - Free Throw Percentage
- **eFG%** - Effective Field Goal Percentage (accounts for 3PT value)
- **TS%** - True Shooting Percentage (accounts for FTs)
### Dean Oliver's Four Factors
1. **Shooting (40%)** - eFG%
2. **Turnovers (25%)** - TOV%
3. **Rebounding (20%)** - ORB%, DRB%
4. **Free Throws (15%)** - FT/FGA
## Per-Minute and Per-Possession Metrics
- **Per 36 Minutes** - Standardize counting stats
- **Per 100 Possessions** - Pace-adjusted metrics
- **Usage Rate** - Percentage of team plays used
- **Player Efficiency Rating (PER)** - All-in-one efficiency metric
## Best Practices
1. Always consider pace and minutes played
2. Use rate stats over counting stats for comparisons
3. Context matters (opponent strength, home/away)
4. Combine traditional and advanced metrics
5. Account for position and role
Discussion
Have questions or feedback? Join our community discussion on
Discord or
GitHub Discussions.
Table of Contents
Related Topics
Quick Actions