Double-Doubles and Triple-Doubles
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)
- Magic Johnson: 30 playoff triple-doubles
- LeBron James: 28+ playoff triple-doubles
- Russell Westbrook: 12 playoff triple-doubles
- 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.