Introduction to ballr

Ryan Elmore

2018-03-26

Introduction

Welcome to the ballr [baw-ler], as in baller1. This is the R resource for your basketball-reference.com needs.

library(ballr)
library(magrittr)
library(ggplot2)
library(janitor)
library(scales)

Example 1

Current standings

standings <- NBAStandingsByDate() # "YEAR-MO-DY"
standings
## $East
##      eastern_conference  w  l w_lpercent   gb pw pl  ps_g  pa_g
## 1      Toronto Raptors* 54 20      0.730    — 55 19 112.4 104.3
## 2       Boston Celtics* 50 23      0.685  3.5 46 27 104.3 100.3
## 3  Cleveland Cavaliers* 44 29      0.603  9.5 38 35 111.1 110.3
## 4       Indiana Pacers* 43 31      0.581   11 41 33 105.8 104.2
## 5    Philadelphia 76ers 42 30      0.583   11 43 29 108.5 105.5
## 6    Washington Wizards 40 33      0.548 13.5 39 34 107.0 106.0
## 7       Milwaukee Bucks 39 34      0.534 14.5 36 37 106.0 106.2
## 8            Miami Heat 39 35      0.527   15 38 36 103.3 103.1
## 9       Detroit Pistons 33 40      0.452 20.5 35 38 103.0 103.7
## 10    Charlotte Hornets 33 41      0.446   21 37 37 107.4 107.4
## 11      New York Knicks 27 47      0.365   27 29 45 104.2 107.5
## 12        Chicago Bulls 24 49      0.329 29.5 21 52 103.4 110.1
## 13        Brooklyn Nets 23 51      0.311   31 27 47 106.4 110.6
## 14        Orlando Magic 22 51      0.301 31.5 25 48 104.3 109.1
## 15        Atlanta Hawks 21 53      0.284   33 24 50 103.6 109.0
## 
## $West
##        western_conference  w  l w_lpercent   gb pw pl  ps_g  pa_g
## 1        Houston Rockets* 60 14      0.811    — 56 18 113.5 104.4
## 2  Golden State Warriors* 54 19      0.740  5.5 52 21 114.4 107.2
## 3  Portland Trail Blazers 45 28      0.616 14.5 43 30 106.0 103.2
## 4   Oklahoma City Thunder 44 31      0.587 16.5 45 30 107.3 104.0
## 5    New Orleans Pelicans 43 31      0.581   17 38 36 111.4 111.0
## 6       San Antonio Spurs 43 31      0.581   17 45 29 102.4  99.2
## 7               Utah Jazz 42 32      0.568   18 45 29 103.5 100.2
## 8  Minnesota Timberwolves 42 32      0.568   18 42 32 110.0 107.7
## 9          Denver Nuggets 40 33      0.548 19.5 40 33 109.8 108.3
## 10   Los Angeles Clippers 39 34      0.534 20.5 39 34 109.6 108.7
## 11     Los Angeles Lakers 32 40      0.444   27 33 39 108.5 110.0
## 12       Sacramento Kings 24 50      0.324   36 20 54  99.4 106.8
## 13       Dallas Mavericks 22 51      0.301 37.5 30 43 102.7 105.3
## 14      Memphis Grizzlies 19 54      0.260 40.5 22 51  98.7 104.8
## 15           Phoenix Suns 19 55      0.257   41 16 58 104.0 113.9

Standings on an arbitrary date

standings <- NBAStandingsByDate("2015-12-31")
standings
## $East
##      eastern_conference  w  l w_lpercent   gb pw pl  ps_g  pa_g
## 1  Cleveland Cavaliers* 21  9      0.700    — 20 10  99.7  95.1
## 2        Atlanta Hawks* 21 13      0.618    2 19 15 102.0 100.1
## 3      Toronto Raptors* 20 13      0.606  2.5 20 13  99.8  96.4
## 4         Chicago Bulls 18 12      0.600    3 16 14 101.1 100.0
## 5         Orlando Magic 19 13      0.594    3 19 13 101.0  98.4
## 6           Miami Heat* 18 13      0.581  3.5 17 14  97.0  95.5
## 7       Indiana Pacers* 18 13      0.581  3.5 20 11 102.3  98.5
## 8       Boston Celtics* 18 14      0.563    4 20 12 103.1  99.1
## 9    Charlotte Hornets* 17 14      0.548  4.5 18 13 102.5  99.7
## 10     Detroit Pistons* 17 15      0.531    5 17 15 101.0 100.2
## 11      New York Knicks 15 18      0.455  7.5 15 18  98.0  99.5
## 12   Washington Wizards 14 16      0.467    7 12 18 101.5 104.4
## 13      Milwaukee Bucks 12 21      0.364 10.5 10 23  97.1 103.2
## 14        Brooklyn Nets  9 23      0.281   13  9 23  97.1 103.4
## 15   Philadelphia 76ers  3 31      0.088   20  5 29  92.5 104.4
## 
## $West
##         western_conference  w  l w_lpercent   gb pw pl  ps_g  pa_g
## 1   Golden State Warriors* 29  2      0.935    — 26  5 114.1 101.8
## 2       San Antonio Spurs* 28  6      0.824  2.5 30  4 102.0  88.6
## 3   Oklahoma City Thunder* 22 10      0.688  7.5 24  8 108.6 100.4
## 4    Los Angeles Clippers* 20 13      0.606   10 19 14 103.1 100.9
## 5        Dallas Mavericks* 19 13      0.594 10.5 18 14 102.3 100.8
## 6       Memphis Grizzlies* 18 16      0.529 12.5 13 21  96.4  99.4
## 7         Houston Rockets* 16 17      0.485   14 15 18 104.1 105.5
## 8  Portland Trail Blazers* 14 20      0.412 16.5 16 18 101.3 102.0
## 9                Utah Jazz 13 17      0.433 15.5 14 16  96.6  97.3
## 10  Minnesota Timberwolves 12 20      0.375 17.5 14 18 100.4 102.6
## 11        Sacramento Kings 12 20      0.375 17.5 13 19 104.2 107.3
## 12          Denver Nuggets 12 21      0.364   18 11 22  98.9 103.8
## 13            Phoenix Suns 12 22      0.353 18.5 14 20 102.7 105.4
## 14    New Orleans Pelicans 10 21      0.323   19 11 20 102.1 107.0
## 15      Los Angeles Lakers  6 27      0.182   24  6 27  96.8 107.2

Example 2

players <- NBAPerGameStatistics()
players
## # A tibble: 640 x 31
##       rk player pos     age tm        g    gs    mp    fg    fga fgpercent
##    <dbl> <chr>  <chr> <dbl> <chr> <dbl> <dbl> <dbl> <dbl>  <dbl>     <dbl>
##  1    1. Alex … SG      24. OKC     69.    8. 14.9  1.60   3.90      0.399
##  2    2. Quinc… PF      27. BRK     63.    8. 19.5  1.70   5.10      0.341
##  3    3. Steve… C       24. OKC     69.   69. 32.6  6.00   9.50      0.634
##  4    4. Bam A… C       20. MIA     64.   19. 20.2  2.60   5.00      0.514
##  5    5. Arron… SG      32. ORL     50.    3. 12.9  1.20   3.00      0.395
##  6    6. Cole … C       29. MIN     19.    0.  2.40 0.300  0.800     0.333
##  7    7. LaMar… C       32. SAS     67.   67. 33.5  9.20  18.0       0.508
##  8    8. Jarre… C       19. BRK     64.   23. 19.4  3.20   5.40      0.582
##  9    9. Kadee… PG      25. BOS     10.    0.  3.10 0.100  0.600     0.167
## 10   10. Tony … SF      36. NOP     22.    0. 12.4  2.00   4.10      0.484
## # ... with 630 more rows, and 20 more variables: x3p <dbl>, x3pa <dbl>,
## #   x3ppercent <dbl>, x2p <dbl>, x2pa <dbl>, x2ppercent <dbl>,
## #   efgpercent <dbl>, ft <dbl>, fta <dbl>, ftpercent <dbl>, orb <dbl>,
## #   drb <dbl>, trb <dbl>, ast <dbl>, stl <dbl>, blk <dbl>, tov <dbl>,
## #   pf <dbl>, ps_g <dbl>, link <chr>

Example 3

players <- NBAPerGameStatistics(season = 2017)
players %>%
  dplyr::filter(mp > 20, pos %in% c("SF")) %>%
  dplyr::select(player, link) %>%
  dplyr::distinct()
## # A tibble: 51 x 2
##    player                link                     
##    <chr>                 <chr>                    
##  1 Justin Anderson       /players/a/anderju01.html
##  2 Giannis Antetokounmpo /players/a/antetgi01.html
##  3 Carmelo Anthony       /players/a/anthoca01.html
##  4 Trevor Ariza          /players/a/arizatr01.html
##  5 Matt Barnes           /players/b/barnema02.html
##  6 Kent Bazemore         /players/b/bazemke01.html
##  7 Bojan Bogdanovic      /players/b/bogdabo02.html
##  8 Jimmy Butler          /players/b/butleji01.html
##  9 DeMarre Carroll       /players/c/carrode01.html
## 10 Vince Carter          /players/c/cartevi01.html
## # ... with 41 more rows

Example 4

players <- NBAPerGameStatisticsPer36Min(season = 2017)
players
## # A tibble: 595 x 30
##       rk player  pos     age tm        g    gs    mp    fg   fga fgpercent
##    <dbl> <chr>   <chr> <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>     <dbl>
##  1    1. Alex A… SG      23. OKC     68.    6. 1055.  4.60 11.6      0.393
##  2    2. Quincy… PF      26. TOT     38.    1.  558.  4.50 11.0      0.412
##  3    2. Quincy… PF      26. DAL      6.    0.   48.  3.70 12.7      0.294
##  4    2. Quincy… PF      26. BRK     32.    1.  510.  4.60 10.8      0.425
##  5    3. Steven… C       23. OKC     80.   80. 2389.  5.60  9.90     0.571
##  6    4. Arron … SG      31. SAC     61.   45. 1580.  4.20  9.60     0.440
##  7    5. Alexis… C       28. NOP     39.   15.  584.  5.50 11.0      0.500
##  8    6. Cole A… C       28. MIN     62.    0.  531.  3.10  5.80     0.523
##  9    7. LaMarc… PF      31. SAS     72.   72. 2335.  7.70 16.2      0.477
## 10    8. Lavoy … PF      27. IND     61.    5.  871.  3.20  6.90     0.458
## # ... with 585 more rows, and 19 more variables: x3p <dbl>, x3pa <dbl>,
## #   x3ppercent <dbl>, x2p <dbl>, x2pa <dbl>, x2ppercent <dbl>, ft <dbl>,
## #   fta <dbl>, ftpercent <dbl>, orb <dbl>, drb <dbl>, trb <dbl>,
## #   ast <dbl>, stl <dbl>, blk <dbl>, tov <dbl>, pf <dbl>, pts <dbl>,
## #   link <chr>

Example - Look at Centers and Power Forwards averaging more than 10 MPG

players <- NBAPerGameStatisticsPer36Min(season = 2017) %>%
  dplyr::filter(pos %in% c("C", "PF")) %>%
  dplyr::top_n(n = 10, pts) %>% 
  dplyr::select(player, link) %>%
  dplyr::distinct()
players
## # A tibble: 8 x 2
##   player             link                     
##   <chr>              <chr>                    
## 1 DeMarcus Cousins   /players/c/couside01.html
## 2 Anthony Davis      /players/d/davisan02.html
## 3 Kevin Durant       /players/d/duranke01.html
## 4 Joel Embiid        /players/e/embiijo01.html
## 5 Enes Kanter        /players/k/kanteen01.html
## 6 Brook Lopez        /players/l/lopezbr01.html
## 7 Boban Marjanovic   /players/m/marjabo01.html
## 8 Karl-Anthony Towns /players/t/townska01.html

Query each player in the list

player_stats <- NBAPlayerPerGameStats(players[1, 2]) %>%
  dplyr::filter(!is.na(age)) %>%
  dplyr::mutate(player = as.character(players[1, 1]))

Append the stats from each player into a df

for(i in 2:dim(players)[1]){
  tmp <- NBAPlayerPerGameStats(players[i, 2]) %>%
    dplyr::filter(!is.na(age)) %>%
    dplyr::mutate(player = as.character(players[i, 1]))
  player_stats <- dplyr::bind_rows(player_stats, tmp)
}

Plot everything

p <- ggplot2::ggplot(data = player_stats,
            aes(x = age, y = efgpercent, group = player))
p + ggplot2::geom_line(alpha = .25) +
  ggplot2::geom_point(alpha = .25) +
  ggplot2::scale_y_continuous("effective field goal %age", limit = c(0, 1),
                     labels = percent) +
  ggplot2::geom_line(data = dplyr::filter(player_stats, player == "Anthony Davis"),
            aes(x = age, y = efgpercent), size = 1, col = "#1f78b4") +
  ggplot2::geom_point(data = dplyr::filter(player_stats, player == "Anthony Davis"),
            aes(x = age, y = efgpercent), size = 1, col = "#1f78b4") +
  ggplot2::geom_line(data = dplyr::filter(player_stats, player == "DeMarcus Cousins"),
            aes(x = age, y = efgpercent), size = 1, col = "#33a02c") +
  ggplot2::geom_point(data = dplyr::filter(player_stats, player == "DeMarcus Cousins"),
             aes(x = age, y = efgpercent), size = 1, col = "#33a02c") +
  ggplot2::theme_bw()

Advanced Statistics

per_100 <- NBAPerGameStatisticsPer100Poss(season = 2018)
utils::head(per_100)
##   rk        player pos age  tm  g gs   mp  fg  fga fgpercent x3p x3pa
## 1  1  Alex Abrines  SG  24 OKC 69  8 1029 5.2 13.0     0.399 3.8  9.7
## 2  2    Quincy Acy  PF  27 BRK 63  8 1229 4.4 12.8     0.341 3.4 10.2
## 3  3  Steven Adams   C  24 OKC 69 69 2249 9.2 14.4     0.634 0.0  0.0
## 4  4   Bam Adebayo   C  20 MIA 64 19 1293 6.4 12.5     0.514 0.0  0.3
## 5  5 Arron Afflalo  SG  32 ORL 50  3  647 4.5 11.5     0.395 1.9  4.8
## 6  6  Cole Aldrich   C  29 MIN 19  0   46 5.4 16.3     0.333 0.0  0.0
##   x3ppercent x2p x2pa x2ppercent  ft fta ftpercent orb  drb  trb ast stl
## 1      0.390 1.4  3.3      0.426 1.6 1.9     0.872 1.2  4.0  5.1 1.3 1.7
## 2      0.335 0.9  2.6      0.364 1.8 2.2     0.821 1.5  7.9  9.4 2.1 1.1
## 3      0.000 9.2 14.4      0.636 3.3 5.7     0.572 7.8  5.9 13.7 1.7 1.9
## 4      0.000 6.4 12.2      0.525 4.7 6.6     0.710 4.4  9.6 14.0 3.8 1.1
## 5      0.391 2.6  6.6      0.398 1.7 2.0     0.846 0.3  4.7  5.0 2.2 0.3
## 6         NA 5.4 16.3      0.333 2.2 6.5     0.333 3.3 10.9 14.1 2.2 2.2
##   blk tov   pf  pts  x ortg drtg                      link
## 1 0.4 1.2  5.5 15.8 NA  116  110 /players/a/abrinal01.html
## 2 1.0 2.3  5.3 13.9 NA   96  111   /players/a/acyqu01.html
## 3 1.7 2.5  4.4 21.6 NA  127  107 /players/a/adamsst01.html
## 4 1.5 2.4  5.2 17.5 NA  117  106 /players/a/adebaba01.html
## 5 0.6 1.6  4.1 12.6 NA   98  115 /players/a/afflaar01.html
## 6 1.1 1.1 12.0 13.0 NA   83  108 /players/a/aldrico01.html

Advanced Statistics

adv_stats <- NBAPerGameAdvStatistics(season = 2018)
utils::head(adv_stats)
##   rk        player pos age  tm  g   mp  per tspercent x3par   ftr
## 1  1  Alex Abrines  SG  24 OKC 69 1029  9.3     0.572 0.746 0.146
## 2  2    Quincy Acy  PF  27 BRK 63 1229  7.4     0.506 0.796 0.173
## 3  3  Steven Adams   C  24 OKC 69 2249 21.3     0.636 0.003 0.394
## 4  4   Bam Adebayo   C  20 MIA 64 1293 15.7     0.569 0.022 0.526
## 5  5 Arron Afflalo  SG  32 ORL 50  647  5.6     0.511 0.421 0.171
## 6  6  Cole Aldrich   C  29 MIN 19   46  5.2     0.340 0.000 0.400
##   orbpercent drbpercent trbpercent astpercent stlpercent blkpercent
## 1        2.5        9.2        5.7        3.6        1.7        0.7
## 2        3.2       17.4       10.2        6.1        1.1        1.5
## 3       17.0       13.7       15.4        5.2        1.9        3.1
## 4        9.8       21.7       15.7       11.3        1.1        2.6
## 5        0.7       10.7        5.7        6.2        0.3        1.0
## 6        7.5       25.3       16.3        5.8        2.2        1.9
##   tovpercent usgpercent  x  ows dws  ws  ws_48 x_2 obpm dbpm  bpm vorp
## 1        8.1       13.0 NA  1.2 0.9 2.1  0.097  NA -0.5 -1.7 -2.2 -0.1
## 2       14.3       14.3 NA -0.4 1.0 0.6  0.023  NA -2.5 -0.2 -2.8 -0.2
## 3       12.7       16.8 NA  6.4 2.8 9.3  0.198  NA  2.5  1.2  3.7  3.2
## 4       13.4       15.9 NA  2.2 1.8 4.0  0.147  NA -1.5  1.8  0.2  0.7
## 5       11.4       12.5 NA -0.1 0.2 0.0  0.004  NA -4.2 -1.8 -6.0 -0.6
## 6        5.4       17.9 NA -0.1 0.1 0.0 -0.031  NA -7.4 -0.6 -8.0 -0.1
##                        link
## 1 /players/a/abrinal01.html
## 2   /players/a/acyqu01.html
## 3 /players/a/adamsst01.html
## 4 /players/a/adebaba01.html
## 5 /players/a/afflaar01.html
## 6 /players/a/aldrico01.html

Example

Look at selector gadget for a team’s website, e.g. Denver Nuggets. Suppose you want to find everybody who played for the Nuggets last year, and then their stats. Remember to use Chrome (ugh).

library(rvest)
## Loading required package: xml2
url <- "http://www.basketball-reference.com/teams/DEN/2017.html"
links <- xml2::read_html(url) %>%
    rvest::html_nodes(".center+ .left a") %>%
    rvest::html_attr('href')
links 
##  [1] "/players/a/arthuda01.html" "/players/b/bartowi01.html"
##  [3] "/players/b/beaslma01.html" "/players/c/chandwi01.html"
##  [5] "/players/f/farieke01.html" "/players/g/gallida01.html"
##  [7] "/players/g/geeal01.html"   "/players/h/harriga01.html"
##  [9] "/players/h/hernaju01.html" "/players/h/hibbero01.html"
## [11] "/players/j/jokicni01.html" "/players/m/millemi01.html"
## [13] "/players/m/mudiaem01.html" "/players/m/murraja01.html"
## [15] "/players/n/nelsoja01.html" "/players/n/nurkiju01.html"
## [17] "/players/o/obryajo01.html" "/players/p/plumlma01.html"
## [19] "/players/s/stokeja01.html"

  1. https://www.urbandictionary.com/define.php?term=baller