Photo by @markusspiske on Unsplash
Photo by @markusspiske on Unsplash

Who Scores the Most Expensive Basket in the NBA?

2020-02-11 6-minute read

Hey! Just a quick post after work. A couple weeks ago, my roommate showed me a tweet that listed soccer players with the most expensive contracts. (I think it was the Premier League?) Of course, I wanted to make something similar with NBA players. I made some quick bar graphs that night showing $ earned per made basket, which was cool, but I wanted to make it a little better.

In this post, I’m going to a good old bar graph. Let’s dive in to this!

I have three dataframes that I pulled from the nbastatR package.

library(tidyverse)

df_salary <- read_csv("salary2020.csv")
df_salary
## # A tibble: 523 x 2
##    namePlayer        amountContract
##    <chr>                      <dbl>
##  1 Otto Porter             27250576
##  2 Zach LaVine             19500000
##  3 Thaddeus Young          12900000
##  4 Tomas Satoransky        10000000
##  5 Cristiano Felicio        8156500
##  6 Kris Dunn                5348007
##  7 Coby White               5307120
##  8 Lauri Markkanen          5300400
##  9 Wendell Carter           5201400
## 10 Denzel Valentine         3377568
## # ... with 513 more rows
df_stats <- read_csv("all2020.csv") %>% 
  select(namePlayer, slugTeam, fgm) 
df_stats
## # A tibble: 505 x 3
##    namePlayer        slugTeam   fgm
##    <chr>             <chr>    <dbl>
##  1 Aaron Gordon      ORL        253
##  2 Aaron Holiday     IND        181
##  3 Abdel Nader       OKC         73
##  4 Adam Mokoka       CHI          6
##  5 Admiral Schofield WAS         30
##  6 Al Horford        PHI        241
##  7 Al-Farouq Aminu   ORL         25
##  8 Alec Burks        PHI        244
##  9 Alen Smailagic    GSW         19
## 10 Alex Caruso       LAL         90
## # ... with 495 more rows
photos <- read_csv("photos.csv") %>% 
  select(namePlayer, urlPlayerHeadshot)
photos
## # A tibble: 4,506 x 2
##    namePlayer        urlPlayerHeadshot                                          
##    <chr>             <chr>                                                      
##  1 Alaa Abdelnaby    https://ak-static.cms.nba.com/wp-content/uploads/headshots~
##  2 Zaid Abdul-Aziz   https://ak-static.cms.nba.com/wp-content/uploads/headshots~
##  3 Kareem Abdul-Jab~ https://ak-static.cms.nba.com/wp-content/uploads/headshots~
##  4 Mahmoud Abdul-Ra~ https://ak-static.cms.nba.com/wp-content/uploads/headshots~
##  5 Tariq Abdul-Wahad https://ak-static.cms.nba.com/wp-content/uploads/headshots~
##  6 Shareef Abdur-Ra~ https://ak-static.cms.nba.com/wp-content/uploads/headshots~
##  7 Tom Abernethy     https://ak-static.cms.nba.com/wp-content/uploads/headshots~
##  8 Forest Able       https://ak-static.cms.nba.com/wp-content/uploads/headshots~
##  9 John Abramovic    https://ak-static.cms.nba.com/wp-content/uploads/headshots~
## 10 Alex Abrines      https://ak-static.cms.nba.com/wp-content/uploads/headshots~
## # ... with 4,496 more rows

Now that I’ve extracted the info I’m interested in, (field goal made and player photos) Let’s join them into a single dataframe.

salaried_stats <- df_stats %>% 
  inner_join(df_salary, by = "namePlayer") %>% 
  inner_join(photos, by = "namePlayer")
salaried_stats
## # A tibble: 425 x 5
##    namePlayer    slugTeam   fgm amountContract urlPlayerHeadshot                
##    <chr>         <chr>    <dbl>          <dbl> <chr>                            
##  1 Aaron Gordon  ORL        253       19863636 https://ak-static.cms.nba.com/wp~
##  2 Aaron Holiday IND        181        2239200 https://ak-static.cms.nba.com/wp~
##  3 Abdel Nader   OKC         73        1618520 https://ak-static.cms.nba.com/wp~
##  4 Adam Mokoka   CHI          6          79568 https://ak-static.cms.nba.com/wp~
##  5 Admiral Scho~ WAS         30        1000000 https://ak-static.cms.nba.com/wp~
##  6 Al Horford    PHI        241       28000000 https://ak-static.cms.nba.com/wp~
##  7 Al-Farouq Am~ ORL         25        9258000 https://ak-static.cms.nba.com/wp~
##  8 Alec Burks    PHI        244        2320044 https://ak-static.cms.nba.com/wp~
##  9 Alen Smailag~ GSW         19         898310 https://ak-static.cms.nba.com/wp~
## 10 Alex Caruso   LAL         90        2750000 https://ak-static.cms.nba.com/wp~
## # ... with 415 more rows

Making the graphs

Since many players don’t get to play in the NBA, I’ve filtered for only players that scored at least 100 baskets. Then, I can calculate the $ made per basket.

per_bucket <- salaried_stats %>% 
  mutate(money_per_buckets = amountContract / fgm) %>% 
  filter(fgm >= 100)
per_bucket
## # A tibble: 211 x 6
##    namePlayer  slugTeam   fgm amountContract urlPlayerHeadshot  money_per_bucke~
##    <chr>       <chr>    <dbl>          <dbl> <chr>                         <dbl>
##  1 Aaron Gord~ ORL        253       19863636 https://ak-static~           78512.
##  2 Aaron Holi~ IND        181        2239200 https://ak-static~           12371.
##  3 Al Horford  PHI        241       28000000 https://ak-static~          116183.
##  4 Alec Burks  PHI        244        2320044 https://ak-static~            9508.
##  5 Alex Len    SAC        142        4160000 https://ak-static~           29296.
##  6 Andre Drum~ CLE        367       27093018 https://ak-static~           73823.
##  7 Andrew Wig~ GSW        365       27504630 https://ak-static~           75355.
##  8 Anfernee S~ POR        178        2149560 https://ak-static~           12076.
##  9 Anthony Da~ LAL        416       27093019 https://ak-static~           65127.
## 10 Aron Baynes PHX        146        5453280 https://ak-static~           37351.
## # ... with 201 more rows

I wonder what the league-wide average was?

library(scales)
avg_bucket_pay <- as.numeric(per_bucket %>% summarize(mean(money_per_buckets)))
dollar(avg_bucket_pay)
## [1] "$48,838.41"

That’s a lot of money! If you make a basket in the NBA, you’re pretty much making as much as a regular Joe will make in an entire year!

Most expensive baskets

I arranged the dataframe in a descending order of $ per basket, took top 10, and made a bar graph with geom_col. After that, I used geom_image from ggimage package to plot a player’s headshot at the end of the bar graphs.

library(ggimage)
theme_set(theme_light())

per_bucket %>% 
  arrange(desc(money_per_buckets)) %>% 
  slice(1:10) %>% 
  mutate(namePlayer = fct_reorder(namePlayer, money_per_buckets)) %>% 
  ggplot(aes(namePlayer, money_per_buckets, fill = fgm)) +
  geom_col() +
  geom_image(aes(image = urlPlayerHeadshot), size = 0.1) + 
  geom_hline(yintercept = avg_bucket_pay, linetype = "dashed") +
  geom_text(aes(3, avg_bucket_pay, label = "League Avg. $48,838")) +
  coord_flip() +
  scale_fill_gradient2(low = "blue", mid = "pink", high = "red", midpoint = 200) +
  scale_y_continuous(labels = dollar_format()) +
  labs( title = "Who scores the most expensive buckets in 2020 NBA season?",
        subtitle = "At least 100 Fg Made this season",
        x = "",
        y = "$ per field goal made",
        fill = "# made field goal") 

Don’t really see too obvious a pattern. Some of them are defense-first guys (Green, Bazemore & Biyombo), while some are legit scorers (Hayward, George & Lowry). Now, let’s look at the most economically friendly contracts.

The Cheapest baskets

This is basically the same plot as above, but I took the ascending order of $ per basket instead.

per_bucket %>% 
  arrange((money_per_buckets)) %>% 
  slice(1:10) %>% 
  mutate(namePlayer = fct_reorder(namePlayer, -money_per_buckets)) %>% 
  ggplot(aes(namePlayer, money_per_buckets, fill = fgm)) +
  geom_col() +
  geom_image(aes(image = urlPlayerHeadshot), size = 0.1) + 
  geom_hline(yintercept = avg_bucket_pay, linetype = "dashed") +
  geom_text(aes(3, 30000, label = "League Avg. $48,838")) +
  coord_flip() +
  scale_fill_gradient2(low = "blue", mid = "pink", high = "red", midpoint = 200) +
  scale_y_continuous(labels = dollar_format()) +
  labs( title = "Who scores the most economical buckets in 2020 NBA season?",
                subtitle = "At least 100 Fg Made this season",
  x = "",
  y = "$ per field goal made",
  fill = "# made field goal") 

Obvious pattern is the youth of this group of players. All of these guys are in their early-mid 20s, who are under their rookie contracts. We see Toronto’s Pascal Siakam & Terrance Davis in the mix, which is nice to see from a Raps fan. Furthermore, there are 4 Golden State Warriors (5 if you count Glenn Robinson who got traded this month). This makes sense, as Golden State’s stars have been injured all season, forcing them to play their inexperienced players.

Ky Bowman

You may have noticed Ky Bowman’s ubsurdly low $ per basket. He was on a 45-day 2-way contract, which means he can go back and forth between an NBA team and a farm team. His salary is less than $80,000, which I know some of you make more than! Unfortunately for him, he plays in the city of San Francisco, which is notorious for its expensive rent. There was a rumor that he may qualify for a low income housing, which turned out not to be true. However, due to his performance as of late, the Warrios signed him to a multi-year contract

Conclusion

I had a super fun time writing this post, and learned a couple of new tricks. One thing I could do next time, is to investigate if there is a relationship between the number of efficient contracts to team performance. Maybe I can count the number of players with below league average $ per basket, and use that as a variable to predict the number of wins.