Double-Doubles and Triple-Doubles

Beginner 10 min read 1 views Nov 27, 2025

Definitions and Fundamentals

What is a Double-Double?

A double-double occurs when a player achieves double-digit totals (10 or more) in two of the five major statistical categories in a single game:

  • Points - Scoring
  • Rebounds - Total rebounds (offensive + defensive)
  • Assists - Passes leading directly to baskets
  • Steals - Deflections resulting in possession change
  • Blocks - Shots legally deflected

The most common double-double combinations are:

  • Points-Rebounds: The standard for big men and power forwards (e.g., 20 points, 12 rebounds)
  • Points-Assists: Common for point guards and playmakers (e.g., 15 points, 10 assists)
  • Rebounds-Assists: Rare but seen with versatile players like Draymond Green

What is a Triple-Double?

A triple-double occurs when a player reaches double digits in three statistical categories in a single game. This achievement demonstrates exceptional all-around performance and versatility.

Common triple-double combinations:

  • Points-Rebounds-Assists: The classic triple-double (e.g., 25 points, 10 rebounds, 10 assists)
  • Points-Rebounds-Blocks: The defensive anchor triple-double
  • Points-Assists-Steals: The perimeter defensive triple-double
  • Rebounds-Assists-Steals: Extremely rare, requiring no scoring

Historical Context

The term "triple-double" wasn't officially recognized until the 1979-80 season when the NBA began tracking steals and blocks. However, retrospective analysis suggests legendary players like Wilt Chamberlain, Bill Russell, and Oscar Robertson achieved numerous triple-doubles before official tracking began.

All-Time Historical Leaders

Career Triple-Doubles (Top 10)

Rank Player Triple-Doubles Era Games Played TD Rate
1 Russell Westbrook 198+ 2008-Present 1,100+ 18.0%
2 Oscar Robertson 181 1960-1974 1,040 17.4%
3 Magic Johnson 138 1979-1996 906 15.2%
4 Nikola Jokic 130+ 2015-Present 700+ 18.6%
5 LeBron James 110+ 2003-Present 1,500+ 7.3%
6 Jason Kidd 107 1994-2013 1,391 7.7%
7 Luka Doncic 75+ 2018-Present 400+ 18.8%
8 Wilt Chamberlain 78* 1959-1973 1,045 7.5%
9 Larry Bird 59 1979-1992 897 6.6%
10 James Harden 75+ 2009-Present 1,100+ 6.8%

*Chamberlain's count is estimated; blocks and steals weren't officially tracked during his era

Career Double-Doubles (Top 10)

Rank Player Double-Doubles Games Played DD Rate Primary Categories
1 Wilt Chamberlain 968 1,045 92.6% Points-Rebounds
2 Tim Duncan 841 1,392 60.4% Points-Rebounds
3 Karl Malone 811 1,476 54.9% Points-Rebounds
4 Kevin Garnett 742 1,462 50.8% Points-Rebounds
5 Dwight Howard 700+ 1,200+ 58.3% Points-Rebounds
6 Kareem Abdul-Jabbar 680+ 1,560 43.6% Points-Rebounds
7 Shaquille O'Neal 619 1,207 51.3% Points-Rebounds
8 Moses Malone 600+ 1,329 45.1% Points-Rebounds
9 Nikola Jokic 500+ 700+ 71.4% Points-Rebounds
10 LeBron James 550+ 1,500+ 36.7% Points-Rebounds

Oscar Robertson: The Original Triple-Double King

Before Russell Westbrook's recent dominance, Oscar Robertson held the career triple-double record for over 40 years. Robertson's most remarkable achievement was averaging a triple-double for an entire season (1961-62): 30.8 PPG, 12.5 RPG, 11.4 APG.

Robertson nearly averaged a triple-double over his first five NBA seasons (1960-65):

  • 30.3 points per game
  • 10.4 rebounds per game
  • 10.6 assists per game

Modern Era Trends and Evolution

The Triple-Double Explosion (2015-Present)

The frequency of triple-doubles has increased dramatically in recent years:

Season Total Triple-Doubles Games Played Per Game Rate Notable
1990-91 35 1,230 2.8% Magic Johnson era
2000-01 39 1,189 3.3% Pre-analytics
2010-11 46 1,230 3.7% LeBron emergence
2016-17 117 1,230 9.5% Westbrook MVP season
2018-19 144 1,230 11.7% Analytics era peak
2020-21 99 1,080 9.2% COVID shortened
2023-24 130+ 1,230 10.6% Jokic dominance

Why the Increase?

Several factors explain the modern triple-double explosion:

1. Pace of Play

Modern NBA games feature faster tempo and more possessions per game:

  • 1990s average: 95 possessions per game
  • 2000s average: 91 possessions per game (slowest era)
  • 2020s average: 100+ possessions per game

2. Analytics and Three-Point Shooting

The three-point revolution creates more rebounding opportunities:

  • Longer rebounds from three-point misses
  • Guards positioned further from basket for spacing
  • More defensive rebounds available to ball-handlers

3. Positionless Basketball

Modern players develop more well-rounded skill sets:

  • Centers like Nikola Jokic facilitate offense
  • Guards like Luka Doncic control rebounds
  • Forwards handle point guard duties

4. Usage and Responsibility

Star players have higher usage rates and control more aspects of their team's offense, leading to more opportunities for assists and rebounds.

Modern Double-Double Leaders (2023-24 Season)

Player Double-Doubles Games Rate Avg Stats
Domantas Sabonis 77 82 93.9% 19.4 PTS, 13.7 REB
Nikola Jokic 68 79 86.1% 26.4 PTS, 12.4 REB
Anthony Davis 63 76 82.9% 24.7 PTS, 12.6 REB
Giannis Antetokounmpo 60 73 82.2% 30.4 PTS, 11.5 REB
Joel Embiid 55 39 87.3% 34.7 PTS, 11.0 REB

Russell Westbrook: The Triple-Double Revolution

Historic Achievement

Russell Westbrook has fundamentally redefined what's possible in terms of triple-doubles, becoming the all-time leader and the only player besides Oscar Robertson to average a triple-double for a full season—doing it not once, but four times.

Westbrook's Triple-Double Seasons

2016-17 Season: Breaking the Record

Category Value
Games Played 81
Triple-Doubles 42 (NBA record at the time)
Points per Game 31.6 (scoring champion)
Rebounds per Game 10.7
Assists per Game 10.4 (assist leader)
Achievement NBA MVP, broke Oscar Robertson's single-season record (41)

2017-18 Season: Back-to-Back Triple-Double Average

Category Value
Games Played 80
Triple-Doubles 25
Points per Game 25.4
Rebounds per Game 10.1
Assists per Game 10.3
Achievement Second consecutive triple-double average

2018-19 Season: The Consistency Peak

Category Value
Games Played 73
Triple-Doubles 34
Points per Game 22.9
Rebounds per Game 11.1
Assists per Game 10.7
Achievement Third consecutive triple-double average, highest rebound rate

2020-21 Season: The Fourth Time

Category Value
Games Played 65
Triple-Doubles 38 (led league)
Points per Game 22.2
Rebounds per Game 11.5
Assists per Game 11.7 (assist leader)
Achievement Fourth triple-double average, highest assist average

Career Triple-Double Milestones

  • December 2016: Passed Magic Johnson (138) for 3rd all-time
  • April 2017: Broke Oscar Robertson's single-season record (41)
  • April 2019: Passed Oscar Robertson (181) for all-time record
  • May 2021: Reached 183rd career triple-double
  • 2023: Surpassed 190+ career triple-doubles

The Debate: Context and Criticism

Westbrook's triple-double achievements have sparked debate:

Supporting Arguments:

  • Unprecedented consistency over multiple seasons
  • Carried team to playoffs as primary option
  • High usage rate reflects team necessity
  • Clutch performances in critical moments

Critical Perspectives:

  • Concerns about "stat-padding" and uncontested rebounds
  • Questions about efficiency (career TS% of 51.8%)
  • Team success not always correlating with triple-doubles
  • Defensive effort debated during regular season

Impact on the Game

Regardless of debate, Westbrook's triple-double dominance has:

  • Changed expectations for star players' statistical contributions
  • Influenced how teams utilize their primary ball-handlers
  • Inspired a generation of versatile, do-everything players
  • Made the triple-double a more common and celebrated achievement

Statistical Analysis with Python

Analyzing Triple-Double Trends

Below is Python code to analyze triple-double frequency and trends over time:


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats

# Sample data: Triple-doubles by season
triple_double_data = {
    'Season': ['1989-90', '1999-00', '2009-10', '2014-15', '2015-16',
               '2016-17', '2017-18', '2018-19', '2019-20', '2020-21',
               '2021-22', '2022-23', '2023-24'],
    'Triple_Doubles': [34, 39, 46, 45, 75, 117, 130, 144, 142, 99, 118, 113, 130],
    'Games_Played': [1230, 1189, 1230, 1230, 1230, 1230, 1230, 1230, 971, 1080, 1230, 1230, 1230]
}

df = pd.DataFrame(triple_double_data)

# Calculate triple-double rate per 100 games
df['TD_Rate'] = (df['Triple_Doubles'] / df['Games_Played']) * 100

# Calculate year-over-year growth
df['Year'] = df['Season'].str[:4].astype(int)
df['YoY_Growth'] = df['Triple_Doubles'].pct_change() * 100

print("Triple-Double Trends Analysis")
print("=" * 60)
print(df[['Season', 'Triple_Doubles', 'TD_Rate', 'YoY_Growth']])
print()

# Statistical analysis
print("Statistical Summary:")
print(f"Mean triple-doubles per season: {df['Triple_Doubles'].mean():.1f}")
print(f"Median triple-doubles per season: {df['Triple_Doubles'].median():.1f}")
print(f"Standard deviation: {df['Triple_Doubles'].std():.1f}")
print()

# Correlation analysis between year and triple-doubles
correlation = stats.pearsonr(df['Year'], df['Triple_Doubles'])
print(f"Correlation between year and triple-doubles: {correlation[0]:.3f}")
print(f"P-value: {correlation[1]:.6f}")
print()

# Visualization
fig, axes = plt.subplots(2, 2, figsize=(15, 12))

# Plot 1: Triple-doubles over time
axes[0, 0].plot(df['Season'], df['Triple_Doubles'], marker='o', linewidth=2, markersize=8)
axes[0, 0].set_title('Triple-Doubles per Season (NBA)', fontsize=14, fontweight='bold')
axes[0, 0].set_xlabel('Season')
axes[0, 0].set_ylabel('Total Triple-Doubles')
axes[0, 0].grid(True, alpha=0.3)
axes[0, 0].tick_params(axis='x', rotation=45)

# Plot 2: Triple-double rate per 100 games
axes[0, 1].bar(df['Season'], df['TD_Rate'], color='steelblue', alpha=0.7)
axes[0, 1].set_title('Triple-Double Rate per 100 Games', fontsize=14, fontweight='bold')
axes[0, 1].set_xlabel('Season')
axes[0, 1].set_ylabel('Rate (%)')
axes[0, 1].tick_params(axis='x', rotation=45)
axes[0, 1].grid(True, alpha=0.3, axis='y')

# Plot 3: Year-over-year growth
axes[1, 0].bar(df['Season'][1:], df['YoY_Growth'][1:],
               color=['green' if x > 0 else 'red' for x in df['YoY_Growth'][1:]], alpha=0.7)
axes[1, 0].set_title('Year-over-Year Growth (%)', fontsize=14, fontweight='bold')
axes[1, 0].set_xlabel('Season')
axes[1, 0].set_ylabel('Growth (%)')
axes[1, 0].axhline(y=0, color='black', linestyle='-', linewidth=0.5)
axes[1, 0].tick_params(axis='x', rotation=45)
axes[1, 0].grid(True, alpha=0.3, axis='y')

# Plot 4: Distribution histogram
axes[1, 1].hist(df['Triple_Doubles'], bins=10, color='coral', alpha=0.7, edgecolor='black')
axes[1, 1].set_title('Distribution of Triple-Doubles', fontsize=14, fontweight='bold')
axes[1, 1].set_xlabel('Triple-Doubles per Season')
axes[1, 1].set_ylabel('Frequency')
axes[1, 1].axvline(df['Triple_Doubles'].mean(), color='red', linestyle='--',
                   linewidth=2, label=f'Mean: {df["Triple_Doubles"].mean():.1f}')
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.savefig('triple_double_analysis.png', dpi=300, bbox_inches='tight')
plt.show()

print("Visualization saved as 'triple_double_analysis.png'")

Analyzing Russell Westbrook's Triple-Double Seasons


import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# Westbrook's triple-double average seasons
westbrook_seasons = {
    'Season': ['2016-17', '2017-18', '2018-19', '2020-21'],
    'Games': [81, 80, 73, 65],
    'PPG': [31.6, 25.4, 22.9, 22.2],
    'RPG': [10.7, 10.1, 11.1, 11.5],
    'APG': [10.4, 10.3, 10.7, 11.7],
    'Triple_Doubles': [42, 25, 34, 38],
    'FG_Pct': [42.5, 44.9, 42.8, 43.9],
    'Usage_Rate': [41.7, 33.1, 30.6, 28.9]
}

df_russ = pd.DataFrame(westbrook_seasons)

# Calculate triple-double rate
df_russ['TD_Rate'] = (df_russ['Triple_Doubles'] / df_russ['Games']) * 100

# Calculate efficiency score (simple metric)
df_russ['Efficiency'] = (df_russ['PPG'] + df_russ['RPG'] + df_russ['APG']) / 3

print("Russell Westbrook Triple-Double Seasons Analysis")
print("=" * 70)
print(df_russ.to_string(index=False))
print()

print("Summary Statistics:")
print(f"Average PPG across TD seasons: {df_russ['PPG'].mean():.1f}")
print(f"Average RPG across TD seasons: {df_russ['RPG'].mean():.1f}")
print(f"Average APG across TD seasons: {df_russ['APG'].mean():.1f}")
print(f"Average triple-double rate: {df_russ['TD_Rate'].mean():.1f}%")
print(f"Total triple-doubles in these seasons: {df_russ['Triple_Doubles'].sum()}")
print()

# Visualization
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# Plot 1: Points, Rebounds, Assists per game
x = np.arange(len(df_russ['Season']))
width = 0.25

axes[0, 0].bar(x - width, df_russ['PPG'], width, label='PPG', alpha=0.8)
axes[0, 0].bar(x, df_russ['RPG'], width, label='RPG', alpha=0.8)
axes[0, 0].bar(x + width, df_russ['APG'], width, label='APG', alpha=0.8)
axes[0, 0].set_title('Westbrook: Points, Rebounds, Assists by Season',
                     fontsize=12, fontweight='bold')
axes[0, 0].set_xlabel('Season')
axes[0, 0].set_ylabel('Per Game Average')
axes[0, 0].set_xticks(x)
axes[0, 0].set_xticklabels(df_russ['Season'])
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3, axis='y')

# Plot 2: Triple-doubles per season
axes[0, 1].plot(df_russ['Season'], df_russ['Triple_Doubles'],
                marker='o', markersize=10, linewidth=2, color='darkblue')
axes[0, 1].set_title('Triple-Doubles per Season', fontsize=12, fontweight='bold')
axes[0, 1].set_xlabel('Season')
axes[0, 1].set_ylabel('Triple-Doubles')
axes[0, 1].grid(True, alpha=0.3)
for i, v in enumerate(df_russ['Triple_Doubles']):
    axes[0, 1].text(i, v + 1, str(v), ha='center', fontweight='bold')

# Plot 3: Usage rate vs efficiency
axes[1, 0].scatter(df_russ['Usage_Rate'], df_russ['Efficiency'],
                   s=df_russ['Triple_Doubles']*10, alpha=0.6, c=range(len(df_russ)))
axes[1, 0].set_title('Usage Rate vs Efficiency (bubble size = triple-doubles)',
                     fontsize=12, fontweight='bold')
axes[1, 0].set_xlabel('Usage Rate (%)')
axes[1, 0].set_ylabel('Efficiency Score')
axes[1, 0].grid(True, alpha=0.3)
for i, season in enumerate(df_russ['Season']):
    axes[1, 0].annotate(season, (df_russ['Usage_Rate'][i], df_russ['Efficiency'][i]),
                        xytext=(5, 5), textcoords='offset points', fontsize=9)

# Plot 4: Triple-double rate
axes[1, 1].bar(df_russ['Season'], df_russ['TD_Rate'], color='green', alpha=0.7)
axes[1, 1].set_title('Triple-Double Rate (%)', fontsize=12, fontweight='bold')
axes[1, 1].set_xlabel('Season')
axes[1, 1].set_ylabel('TD Rate (%)')
axes[1, 1].grid(True, alpha=0.3, axis='y')
for i, v in enumerate(df_russ['TD_Rate']):
    axes[1, 1].text(i, v + 1, f'{v:.1f}%', ha='center', fontweight='bold')

plt.tight_layout()
plt.savefig('westbrook_triple_double_analysis.png', dpi=300, bbox_inches='tight')
plt.show()

print("Westbrook visualization saved as 'westbrook_triple_double_analysis.png'")

Comparing All-Time Triple-Double Leaders


import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# All-time triple-double leaders
leaders_data = {
    'Player': ['Russell Westbrook', 'Oscar Robertson', 'Magic Johnson',
               'Nikola Jokic', 'LeBron James', 'Jason Kidd', 'Luka Doncic',
               'Wilt Chamberlain', 'Larry Bird', 'James Harden'],
    'Career_TDs': [198, 181, 138, 130, 110, 107, 75, 78, 59, 75],
    'Games_Played': [1100, 1040, 906, 700, 1500, 1391, 400, 1045, 897, 1100],
    'Era_Start': [2008, 1960, 1979, 2015, 2003, 1994, 2018, 1959, 1979, 2009]
}

df_leaders = pd.DataFrame(leaders_data)

# Calculate TD rate
df_leaders['TD_Rate'] = (df_leaders['Career_TDs'] / df_leaders['Games_Played']) * 100

# Sort by career triple-doubles
df_leaders = df_leaders.sort_values('Career_TDs', ascending=False)

print("All-Time Triple-Double Leaders")
print("=" * 70)
print(df_leaders.to_string(index=False))
print()

# Statistical comparisons
print("Era Comparison:")
modern_players = df_leaders[df_leaders['Era_Start'] >= 2000]
historic_players = df_leaders[df_leaders['Era_Start'] < 2000]

print(f"Modern era (2000+) average TD rate: {modern_players['TD_Rate'].mean():.2f}%")
print(f"Historic era (pre-2000) average TD rate: {historic_players['TD_Rate'].mean():.2f}%")
print()

# Visualization
fig, axes = plt.subplots(2, 2, figsize=(16, 12))

# Plot 1: Career triple-doubles
axes[0, 0].barh(df_leaders['Player'], df_leaders['Career_TDs'], color='steelblue', alpha=0.7)
axes[0, 0].set_title('Career Triple-Doubles - All-Time Leaders',
                     fontsize=14, fontweight='bold')
axes[0, 0].set_xlabel('Career Triple-Doubles')
axes[0, 0].grid(True, alpha=0.3, axis='x')
axes[0, 0].invert_yaxis()

# Plot 2: Triple-double rate
colors = ['red' if rate > 15 else 'orange' if rate > 10 else 'blue'
          for rate in df_leaders['TD_Rate']]
axes[0, 1].barh(df_leaders['Player'], df_leaders['TD_Rate'], color=colors, alpha=0.7)
axes[0, 1].set_title('Triple-Double Rate (% of games)', fontsize=14, fontweight='bold')
axes[0, 1].set_xlabel('TD Rate (%)')
axes[0, 1].grid(True, alpha=0.3, axis='x')
axes[0, 1].invert_yaxis()

# Plot 3: Triple-doubles vs Games Played (scatter)
axes[1, 0].scatter(df_leaders['Games_Played'], df_leaders['Career_TDs'],
                   s=200, alpha=0.6, c=df_leaders['Era_Start'], cmap='viridis')
axes[1, 0].set_title('Career TDs vs Games Played', fontsize=14, fontweight='bold')
axes[1, 0].set_xlabel('Games Played')
axes[1, 0].set_ylabel('Career Triple-Doubles')
axes[1, 0].grid(True, alpha=0.3)

# Add player labels
for idx, row in df_leaders.iterrows():
    axes[1, 0].annotate(row['Player'].split()[1] if len(row['Player'].split()) > 1
                        else row['Player'],
                        (row['Games_Played'], row['Career_TDs']),
                        xytext=(5, 5), textcoords='offset points', fontsize=8)

# Plot 4: Era distribution
era_bins = [1950, 1980, 2000, 2020, 2030]
era_labels = ['1960s-70s', '1980s-90s', '2000s-10s', '2015+']
df_leaders['Era_Category'] = pd.cut(df_leaders['Era_Start'], bins=era_bins, labels=era_labels)

era_counts = df_leaders.groupby('Era_Category', observed=True)['Player'].count()
axes[1, 1].bar(era_counts.index.astype(str), era_counts.values, color='coral', alpha=0.7)
axes[1, 1].set_title('Top 10 TD Leaders by Era', fontsize=14, fontweight='bold')
axes[1, 1].set_xlabel('Era')
axes[1, 1].set_ylabel('Number of Players in Top 10')
axes[1, 1].grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.savefig('triple_double_leaders_analysis.png', dpi=300, bbox_inches='tight')
plt.show()

print("Leaders visualization saved as 'triple_double_leaders_analysis.png'")

Statistical Analysis with R

Triple-Double Trends Analysis in R


# Load required libraries
library(tidyverse)
library(ggplot2)
library(scales)
library(gridExtra)

# Triple-double data by season
triple_double_data <- data.frame(
  Season = c('1989-90', '1999-00', '2009-10', '2014-15', '2015-16',
             '2016-17', '2017-18', '2018-19', '2019-20', '2020-21',
             '2021-22', '2022-23', '2023-24'),
  Triple_Doubles = c(34, 39, 46, 45, 75, 117, 130, 144, 142, 99, 118, 113, 130),
  Games_Played = c(1230, 1189, 1230, 1230, 1230, 1230, 1230, 1230, 971, 1080, 1230, 1230, 1230),
  stringsAsFactors = FALSE
)

# Calculate metrics
triple_double_data <- triple_double_data %>%
  mutate(
    TD_Rate = (Triple_Doubles / Games_Played) * 100,
    Year = as.numeric(substr(Season, 1, 4)),
    YoY_Growth = (Triple_Doubles / lag(Triple_Doubles) - 1) * 100
  )

# Statistical summary
cat("Triple-Double Trends Analysis
")
cat(rep("=", 60), "
", sep="")
print(triple_double_data)
cat("
")

cat("Statistical Summary:
")
cat(sprintf("Mean triple-doubles per season: %.1f
", mean(triple_double_data)))
cat(sprintf("Median triple-doubles per season: %.1f
", median(triple_double_data)))
cat(sprintf("Standard deviation: %.1f
", sd(triple_double_data)))
cat(sprintf("Range: %d - %d
", min(triple_double_data),
    max(triple_double_data)))
cat("
")

# Correlation analysis
correlation_test <- cor.test(triple_double_data, triple_double_data)
cat(sprintf("Correlation between year and triple-doubles: %.3f
",
    correlation_test))
cat(sprintf("P-value: %.6f
", correlation_test.value))
cat("
")

# Linear regression
model <- lm(Triple_Doubles ~ Year, data = triple_double_data)
cat("Linear Regression Results:
")
print(summary(model))
cat("
")

# Predictions for next season
next_year <- data.frame(Year = 2024)
prediction <- predict(model, newdata = next_year, interval = "confidence")
cat(sprintf("Predicted triple-doubles for 2024-25: %.0f (95%% CI: %.0f - %.0f)
",
    prediction[1], prediction[2], prediction[3]))

# Visualization
# Plot 1: Triple-doubles over time
p1 <- ggplot(triple_double_data, aes(x = Season, y = Triple_Doubles)) +
  geom_line(group = 1, color = "steelblue", size = 1.2) +
  geom_point(size = 3, color = "darkblue") +
  geom_smooth(aes(x = Year, y = Triple_Doubles), method = "lm",
              se = TRUE, color = "red", linetype = "dashed") +
  labs(title = "Triple-Doubles per Season (NBA)",
       x = "Season", y = "Total Triple-Doubles") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(face = "bold", size = 14))

# Plot 2: Triple-double rate
p2 <- ggplot(triple_double_data, aes(x = Season, y = TD_Rate)) +
  geom_bar(stat = "identity", fill = "steelblue", alpha = 0.7) +
  labs(title = "Triple-Double Rate per 100 Games",
       x = "Season", y = "Rate (%)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(face = "bold", size = 14))

# Plot 3: Distribution
p3 <- ggplot(triple_double_data, aes(x = Triple_Doubles)) +
  geom_histogram(bins = 8, fill = "coral", color = "black", alpha = 0.7) +
  geom_vline(aes(xintercept = mean(Triple_Doubles)),
             color = "red", linetype = "dashed", size = 1) +
  annotate("text", x = mean(triple_double_data) + 10,
           y = 3, label = sprintf("Mean: %.1f", mean(triple_double_data)),
           color = "red", fontface = "bold") +
  labs(title = "Distribution of Triple-Doubles per Season",
       x = "Triple-Doubles", y = "Frequency") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 14))

# Plot 4: Year-over-year growth
p4 <- ggplot(triple_double_data[-1,], aes(x = Season, y = YoY_Growth, fill = YoY_Growth > 0)) +
  geom_bar(stat = "identity", alpha = 0.7) +
  scale_fill_manual(values = c("red", "green"), guide = "none") +
  geom_hline(yintercept = 0, color = "black", size = 0.5) +
  labs(title = "Year-over-Year Growth (%)",
       x = "Season", y = "Growth (%)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(face = "bold", size = 14))

# Combine plots
grid.arrange(p1, p2, p3, p4, ncol = 2)

# Save plot
ggsave("triple_double_analysis_r.png",
       arrangeGrob(p1, p2, p3, p4, ncol = 2),
       width = 14, height = 10, dpi = 300)

cat("Visualization saved as 'triple_double_analysis_r.png'
")

Russell Westbrook Analysis in R


library(tidyverse)
library(ggplot2)
library(gridExtra)

# Westbrook's triple-double seasons
westbrook_data <- data.frame(
  Season = c('2016-17', '2017-18', '2018-19', '2020-21'),
  Games = c(81, 80, 73, 65),
  PPG = c(31.6, 25.4, 22.9, 22.2),
  RPG = c(10.7, 10.1, 11.1, 11.5),
  APG = c(10.4, 10.3, 10.7, 11.7),
  Triple_Doubles = c(42, 25, 34, 38),
  FG_Pct = c(42.5, 44.9, 42.8, 43.9),
  Usage_Rate = c(41.7, 33.1, 30.6, 28.9),
  stringsAsFactors = FALSE
)

# Calculate additional metrics
westbrook_data <- westbrook_data %>%
  mutate(
    TD_Rate = (Triple_Doubles / Games) * 100,
    Efficiency = (PPG + RPG + APG) / 3,
    Total_Stats = PPG + RPG + APG
  )

cat("Russell Westbrook Triple-Double Seasons Analysis
")
cat(rep("=", 70), "
", sep="")
print(westbrook_data)
cat("
")

# Summary statistics
cat("Summary Statistics:
")
cat(sprintf("Average PPG: %.1f
", mean(westbrook_data)))
cat(sprintf("Average RPG: %.1f
", mean(westbrook_data)))
cat(sprintf("Average APG: %.1f
", mean(westbrook_data)))
cat(sprintf("Average TD Rate: %.1f%%
", mean(westbrook_data)))
cat(sprintf("Total TDs in these seasons: %d
", sum(westbrook_data)))
cat("
")

# Correlation analysis
cat("Correlation Matrix:
")
cor_matrix <- cor(westbrook_data[, c("PPG", "RPG", "APG", "Triple_Doubles", "Usage_Rate")])
print(round(cor_matrix, 3))
cat("
")

# Visualizations
# Plot 1: Stats comparison
stats_long <- westbrook_data %>%
  select(Season, PPG, RPG, APG) %>%
  pivot_longer(cols = c(PPG, RPG, APG), names_to = "Stat", values_to = "Value")

p1 <- ggplot(stats_long, aes(x = Season, y = Value, fill = Stat)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.8) +
  labs(title = "Westbrook: Points, Rebounds, Assists by Season",
       x = "Season", y = "Per Game Average") +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 12),
        legend.position = "bottom")

# Plot 2: Triple-doubles per season
p2 <- ggplot(westbrook_data, aes(x = Season, y = Triple_Doubles)) +
  geom_line(group = 1, color = "darkblue", size = 1.5) +
  geom_point(size = 4, color = "darkblue") +
  geom_text(aes(label = Triple_Doubles), vjust = -1, fontface = "bold") +
  labs(title = "Triple-Doubles per Season",
       x = "Season", y = "Triple-Doubles") +
  ylim(0, max(westbrook_data) + 5) +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 12))

# Plot 3: Usage vs Efficiency
p3 <- ggplot(westbrook_data, aes(x = Usage_Rate, y = Efficiency,
                                  size = Triple_Doubles, label = Season)) +
  geom_point(alpha = 0.6, color = "steelblue") +
  geom_text(vjust = -1.5, size = 3, fontface = "bold") +
  labs(title = "Usage Rate vs Efficiency",
       subtitle = "Bubble size = triple-doubles",
       x = "Usage Rate (%)", y = "Efficiency Score") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 12))

# Plot 4: TD Rate
p4 <- ggplot(westbrook_data, aes(x = Season, y = TD_Rate)) +
  geom_bar(stat = "identity", fill = "green", alpha = 0.7) +
  geom_text(aes(label = sprintf("%.1f%%", TD_Rate)), vjust = -0.5, fontface = "bold") +
  labs(title = "Triple-Double Rate (%)",
       x = "Season", y = "TD Rate (%)") +
  ylim(0, max(westbrook_data) + 5) +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 12))

# Combine plots
grid.arrange(p1, p2, p3, p4, ncol = 2)

# Save visualization
ggsave("westbrook_analysis_r.png",
       arrangeGrob(p1, p2, p3, p4, ncol = 2),
       width = 14, height = 10, dpi = 300)

cat("Westbrook visualization saved as 'westbrook_analysis_r.png'
")

Advanced Statistical Modeling in R


library(tidyverse)
library(broom)

# All-time leaders data
leaders_data <- data.frame(
  Player = c('Russell Westbrook', 'Oscar Robertson', 'Magic Johnson',
             'Nikola Jokic', 'LeBron James', 'Jason Kidd', 'Luka Doncic',
             'Wilt Chamberlain', 'Larry Bird', 'James Harden'),
  Career_TDs = c(198, 181, 138, 130, 110, 107, 75, 78, 59, 75),
  Games_Played = c(1100, 1040, 906, 700, 1500, 1391, 400, 1045, 897, 1100),
  Era_Start = c(2008, 1960, 1979, 2015, 2003, 1994, 2018, 1959, 1979, 2009),
  stringsAsFactors = FALSE
)

# Calculate TD rate
leaders_data <- leaders_data %>%
  mutate(
    TD_Rate = (Career_TDs / Games_Played) * 100,
    Era = case_when(
      Era_Start < 1980 ~ "Classic Era (1960s-70s)",
      Era_Start < 2000 ~ "Modern Era (1980s-90s)",
      Era_Start < 2015 ~ "2000s-2010s",
      TRUE ~ "Current Era (2015+)"
    )
  )

cat("All-Time Triple-Double Leaders Analysis
")
cat(rep("=", 70), "
", sep="")
print(leaders_data)
cat("
")

# Era-based analysis
era_summary <- leaders_data %>%
  group_by(Era) %>%
  summarise(
    Players = n(),
    Avg_TDs = mean(Career_TDs),
    Avg_TD_Rate = mean(TD_Rate),
    Total_TDs = sum(Career_TDs)
  )

cat("Era-based Summary:
")
print(era_summary)
cat("
")

# Statistical tests
modern_players <- leaders_data %>% filter(Era_Start >= 2000)
historic_players <- leaders_data %>% filter(Era_Start < 2000)

t_test_result <- t.test(modern_players, historic_players)
cat("T-test comparing modern vs historic TD rates:
")
cat(sprintf("Modern era mean: %.2f%%
", mean(modern_players)))
cat(sprintf("Historic era mean: %.2f%%
", mean(historic_players)))
cat(sprintf("P-value: %.4f
", t_test_result.value))
cat(sprintf("Significant at alpha=0.05: %s
",
    ifelse(t_test_result.value < 0.05, "Yes", "No")))
cat("
")

# Linear model: TD rate predicted by era
model <- lm(TD_Rate ~ Era_Start, data = leaders_data)
cat("Linear Regression: TD Rate ~ Era Start Year
")
print(summary(model))
cat("
")

# Visualizations
# Plot 1: Career triple-doubles
p1 <- ggplot(leaders_data, aes(x = reorder(Player, Career_TDs), y = Career_TDs, fill = Era)) +
  geom_bar(stat = "identity", alpha = 0.8) +
  coord_flip() +
  labs(title = "Career Triple-Doubles - All-Time Leaders",
       x = "Player", y = "Career Triple-Doubles") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 12),
        legend.position = "bottom")

# Plot 2: TD Rate by player
p2 <- ggplot(leaders_data, aes(x = reorder(Player, TD_Rate), y = TD_Rate,
                                fill = ifelse(TD_Rate > 15, "High", "Normal"))) +
  geom_bar(stat = "identity", alpha = 0.8) +
  coord_flip() +
  scale_fill_manual(values = c("High" = "red", "Normal" = "steelblue"), guide = "none") +
  labs(title = "Triple-Double Rate (% of Games)",
       x = "Player", y = "TD Rate (%)") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 12))

# Plot 3: TDs vs Games Played
p3 <- ggplot(leaders_data, aes(x = Games_Played, y = Career_TDs, color = Era, label = Player)) +
  geom_point(size = 4, alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, color = "black", linetype = "dashed") +
  labs(title = "Career TDs vs Games Played",
       x = "Games Played", y = "Career Triple-Doubles") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 12),
        legend.position = "bottom")

# Plot 4: Era distribution
p4 <- ggplot(leaders_data, aes(x = Era, fill = Era)) +
  geom_bar(alpha = 0.7) +
  labs(title = "Top 10 Leaders by Era",
       x = "Era", y = "Number of Players") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 12),
        axis.text.x = element_text(angle = 45, hjust = 1),
        legend.position = "none")

# Combine and save
grid.arrange(p1, p2, p3, p4, ncol = 2)

ggsave("leaders_analysis_r.png",
       arrangeGrob(p1, p2, p3, p4, ncol = 2),
       width = 16, height = 12, dpi = 300)

cat("Leaders visualization saved as 'leaders_analysis_r.png'
")

Rarity, Records, and Notable Achievements

Quadruple-Doubles: The Ultimate Rarity

A quadruple-double (double-digits in four categories) is one of basketball's rarest achievements. Only four players have officially recorded a quadruple-double in NBA history:

Player Date Stat Line Team
Nate Thurmond October 18, 1974 22 PTS, 14 REB, 13 AST, 12 BLK Chicago Bulls
Alvin Robertson February 18, 1986 20 PTS, 11 REB, 10 AST, 10 STL San Antonio Spurs
Hakeem Olajuwon March 29, 1990 18 PTS, 16 REB, 10 AST, 11 BLK Houston Rockets
David Robinson February 17, 1994 34 PTS, 10 REB, 10 AST, 10 BLK San Antonio Spurs

Unique Triple-Double Combinations

Points-Rebounds-Blocks (Defensive Triple-Double)

Players achieving this are typically elite rim protectors:

  • Hakeem Olajuwon: Multiple instances
  • Shaquille O'Neal: Rare but achieved
  • David Robinson: Several throughout career

Rebounds-Assists-Steals (No-Point Triple-Double)

Extremely rare combinations achieved by versatile defenders:

  • Draymond Green: 4 PTS, 12 REB, 10 AST, 10 STL (February 10, 2017)
  • One of the rarest triple-double types in NBA history

Single-Game Triple-Double Records

Largest Individual Stats in Triple-Doubles

  • Most Points: Wilt Chamberlain - 53 PTS, 32 REB, 14 AST (March 18, 1968)
  • Most Rebounds: Wilt Chamberlain - 22 PTS, 55 REB, 11 AST (November 24, 1960)
  • Most Assists: Scott Skiles - 30 AST, 22 PTS, 10 REB (December 30, 1990)
  • Most Blocks: Shaquille O'Neal - 24 PTS, 28 REB, 15 BLK (November 20, 1993)
  • Most Steals: Alvin Robertson - 20 PTS, 11 REB, 10 AST, 10 STL (February 18, 1986)

Consecutive Triple-Double Streaks

Rank Player Streak Season
1 Russell Westbrook 11 games 2018-19
2 Wilt Chamberlain 9 games 1967-68
3 Oscar Robertson 7 games 1960-61
4 Russell Westbrook 7 games 2016-17
5 Magic Johnson 7 games 1981-82

Team and Opponent Triple-Doubles

Most Triple-Doubles in a Single Game (Both Teams)

Occasionally, multiple players from both teams achieve triple-doubles in the same game:

  • Most common in high-pace, high-scoring games
  • Modern era has seen increase in these occurrences
  • Notable: Jokic vs Westbrook matchups have featured multiple triple-doubles

Playoff and Finals Triple-Doubles

Most Playoff Triple-Doubles (Career)

  1. Magic Johnson: 30 playoff triple-doubles
  2. LeBron James: 28+ playoff triple-doubles
  3. Russell Westbrook: 12 playoff triple-doubles
  4. Nikola Jokic: 15+ playoff triple-doubles

NBA Finals Triple-Doubles

  • LeBron James: 10 Finals triple-doubles (most all-time)
  • Magic Johnson: 8 Finals triple-doubles
  • Notable: LeBron's 2016 Finals Game 7 triple-double (27-11-11) led Cavaliers to championship

The Value Debate

Arguments For Triple-Double Emphasis

  • Demonstrates all-around excellence and versatility
  • Correlates with high basketball IQ and court awareness
  • Often reflects player's importance to team success
  • Requires sustained excellence across entire game

Arguments Against Triple-Double Obsession

  • Can incentivize "stat-padding" behavior
  • Defensive rebounds sometimes prioritized for statistics
  • Doesn't account for efficiency or winning impact
  • May not reflect true value (e.g., 10 points on poor shooting vs 28 points with 9 assists)

Conclusion: Evolution and Context

Double-doubles and triple-doubles remain important benchmarks for measuring all-around performance in basketball. While their frequency has increased in the modern era due to pace, spacing, and analytics, they still represent exceptional individual achievement.

Understanding these statistics requires context: era, team success, efficiency, and role. Russell Westbrook's triple-double dominance, Oscar Robertson's pioneering achievements, and the emergence of versatile modern stars like Nikola Jokic and Luka Doncic demonstrate the evolving nature of basketball excellence.

As the game continues to evolve, these milestones will remain central to evaluating player performance while requiring increasingly sophisticated analysis to fully appreciate their value.

Discussion

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