Introduction to ballr

Ryan Elmore

2017-11-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       Boston Celtics 18  3      0.857    — 16  5 103.6  95.8
## 2      Detroit Pistons 12  6      0.667  4.5 10  8 103.7 101.8
## 3  Cleveland Cavaliers 12  7      0.632    5 10  9 110.8 110.1
## 4      Toronto Raptors 12  7      0.632    5 14  5 109.6 102.6
## 5   Philadelphia 76ers 11  7      0.611  5.5 10  8 109.6 107.4
## 6       Indiana Pacers 11  9      0.550  6.5 11  9 108.3 107.2
## 7      New York Knicks 10  9      0.526    7  9 10 104.7 104.7
## 8   Washington Wizards 10  9      0.526    7 12  7 108.3 104.5
## 9      Milwaukee Bucks  9  9      0.500  7.5  7 11 102.4 105.6
## 10          Miami Heat  9  9      0.500  7.5  8 10 100.9 102.5
## 11   Charlotte Hornets  8 11      0.421    9  9 10 105.4 106.1
## 12       Orlando Magic  8 12      0.400  9.5  8 12 107.3 110.5
## 13       Brooklyn Nets  6 12      0.333 10.5  7 11 111.3 114.9
## 14       Atlanta Hawks  4 16      0.200 13.5  6 14 102.2 108.2
## 15       Chicago Bulls  3 14      0.176   13  2 15  94.4 107.3
## 
## $West
##        western_conference  w  l w_lpercent   gb pw pl  ps_g  pa_g
## 1         Houston Rockets 15  4      0.789    — 15  4 113.5 103.4
## 2   Golden State Warriors 15  5      0.750  0.5 16  4 117.4 106.2
## 3       San Antonio Spurs 12  7      0.632    3 11  8 100.9  98.1
## 4  Portland Trail Blazers 12  8      0.600  3.5 13  7 103.2  99.2
## 5          Denver Nuggets 11  8      0.579    4 10  9 107.8 106.5
## 6  Minnesota Timberwolves 11  8      0.579    4  9 10 107.5 108.3
## 7    New Orleans Pelicans 11  9      0.550  4.5 10 10 108.3 108.4
## 8               Utah Jazz  9 11      0.450  6.5 11  9 101.3 100.4
## 9   Oklahoma City Thunder  8 11      0.421    7 12  7 102.0  98.1
## 10     Los Angeles Lakers  8 11      0.421    7  8 11 105.3 107.1
## 11   Los Angeles Clippers  7 11      0.389  7.5  9  9 105.1 105.7
## 12      Memphis Grizzlies  7 11      0.389  7.5  8 10  99.4 101.1
## 13           Phoenix Suns  7 13      0.350  8.5  5 15 107.0 115.8
## 14       Sacramento Kings  5 14      0.263   10  3 16  94.3 105.1
## 15       Dallas Mavericks  5 15      0.250 10.5  7 13  98.8 104.0

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: 456 x 31
##       rk            player   pos   age    tm     g    gs    mp    fg   fga
##    <dbl>             <chr> <chr> <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     1      Alex Abrines    SG    24   OKC    19     0  15.2   1.4   3.7
##  2     2        Quincy Acy    PF    27   BRK    14     0  18.1   1.6   4.8
##  3     3      Steven Adams     C    24   OKC    16    16  31.3   5.3   8.3
##  4     4       Bam Adebayo     C    20   MIA    10     3  12.3   1.3   2.6
##  5     5     Arron Afflalo    SG    32   ORL    15     0  11.0   0.7   2.1
##  6     6      Cole Aldrich     C    29   MIN     5     0   2.0   0.0   0.4
##  7     7 LaMarcus Aldridge    PF    32   SAS    19    19  32.9   8.4  16.8
##  8     8     Jarrett Allen     C    19   BRK    10     0  15.4   1.9   4.1
##  9     9        Tony Allen    SG    36   NOP    16     0  13.4   2.3   4.5
## 10    10   Al-Farouq Aminu    PF    27   POR     8     8  30.1   3.3   7.5
## # ... with 446 more rows, and 21 more variables: fgpercent <dbl>,
## #   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: 55 x 2
##                   player                      link
##                    <chr>                     <chr>
##  1       Al-Farouq Aminu /players/a/aminual01.html
##  2       Justin Anderson /players/a/anderju01.html
##  3 Giannis Antetokounmpo /players/a/antetgi01.html
##  4       Carmelo Anthony /players/a/anthoca01.html
##  5          Trevor Ariza /players/a/arizatr01.html
##  6           Matt Barnes /players/b/barnema02.html
##  7         Kent Bazemore /players/b/bazemke01.html
##  8      Bojan Bogdanovic /players/b/bogdabo02.html
##  9          Jimmy Butler /players/b/butleji01.html
## 10       DeMarre Carroll /players/c/carrode01.html
## # ... with 45 more rows

Example 4

players <- NBAPerGameStatisticsPer36Min(season = 2017)
players
## # A tibble: 595 x 30
##       rk            player   pos   age    tm     g    gs    mp    fg   fga
##    <dbl>             <chr> <chr> <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     1      Alex Abrines    SG    23   OKC    68     6  1055   4.6  11.6
##  2     2        Quincy Acy    PF    26   TOT    38     1   558   4.5  11.0
##  3     2        Quincy Acy    PF    26   DAL     6     0    48   3.7  12.7
##  4     2        Quincy Acy    PF    26   BRK    32     1   510   4.6  10.8
##  5     3      Steven Adams     C    23   OKC    80    80  2389   5.6   9.9
##  6     4     Arron Afflalo    SG    31   SAC    61    45  1580   4.2   9.6
##  7     5     Alexis Ajinca     C    28   NOP    39    15   584   5.5  11.0
##  8     6      Cole Aldrich     C    28   MIN    62     0   531   3.1   5.8
##  9     7 LaMarcus Aldridge    PF    31   SAS    72    72  2335   7.7  16.2
## 10     8       Lavoy Allen    PF    27   IND    61     5   871   3.2   6.9
## # ... with 585 more rows, and 20 more variables: fgpercent <dbl>,
## #   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        Joel Embiid /players/e/embiijo01.html
## 4        Enes Kanter /players/k/kanteen01.html
## 5        Brook Lopez /players/l/lopezbr01.html
## 6   Boban Marjanovic /players/m/marjabo01.html
## 7       JaVale McGee /players/m/mcgeeja01.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

#player_stats <- clean_names(player_stats)
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 19  0 289 4.5 12.0     0.371 2.6  8.1
## 2  2    Quincy Acy  PF  27 BRK 14  0 254 4.0 12.2     0.328 3.4  9.8
## 3  3  Steven Adams   C  24 OKC 16 16 500 8.3 13.1     0.636 0.0  0.0
## 4  4   Bam Adebayo   C  20 MIA 10  3 123 5.3 10.5     0.500 0.0  0.0
## 5  5 Arron Afflalo  SG  32 ORL 15  0 165 2.9  9.0     0.323 1.4  4.6
## 6  6  Cole Aldrich   C  29 MIN  5  0  10 0.0  9.8     0.000 0.0  0.0
##   x3ppercent x2p x2pa x2ppercent  ft fta ftpercent orb drb  trb ast stl
## 1      0.319 1.9  3.9      0.478 1.5 1.9     0.818 1.2 3.4  4.6 1.2 1.7
## 2      0.352 0.5  2.4      0.231 2.5 3.1     0.824 1.5 8.9 10.3 2.0 0.9
## 3         NA 8.3 13.1      0.636 3.0 4.2     0.714 6.6 6.3 12.9 1.4 2.2
## 4         NA 5.3 10.5      0.500 3.6 5.3     0.692 5.7 8.9 14.6 0.0 1.6
## 5      0.313 1.4  4.3      0.333 1.4 2.3     0.625 0.3 6.6  6.9 2.6 0.3
## 6         NA 0.0  9.8      0.000 4.9 9.8     0.500 0.0 4.9  4.9 4.9 4.9
##   blk tov  pf  pts  x ortg drtg                      link
## 1 0.2 1.2 5.7 13.0 NA  103  106 /players/a/abrinal01.html
## 2 0.5 2.9 6.2 14.0 NA   94  111   /players/a/acyqu01.html
## 3 1.9 3.0 4.1 19.6 NA  122  101 /players/a/adamsst01.html
## 4 1.6 2.0 5.3 14.1 NA  112  104 /players/a/adebaba01.html
## 5 0.6 1.4 4.0  8.7 NA   88  113 /players/a/afflaar01.html
## 6 0.0 0.0 9.8  4.9 NA   59  105 /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 19 289  6.8     0.508 0.671 0.157
## 2  2    Quincy Acy  PF  27 BRK 14 254  6.7     0.517 0.806 0.254
## 3  3  Steven Adams   C  24 OKC 16 500 20.1     0.658 0.000 0.318
## 4  4   Bam Adebayo   C  20 MIA 10 123 13.5     0.552 0.000 0.500
## 5  5 Arron Afflalo  SG  32 ORL 15 165  3.8     0.435 0.516 0.258
## 6  6  Cole Aldrich   C  29 MIN  5  10  0.8     0.174 0.000 1.000
##   orbpercent drbpercent trbpercent astpercent stlpercent blkpercent
## 1        2.7        8.0        5.2        3.5        1.7        0.3
## 2        3.1       20.7       11.6        5.8        0.9        0.9
## 3       14.7       14.5       14.6        4.5        2.2        3.6
## 4       12.8       19.3       16.1        0.0        1.6        2.6
## 5        0.7       14.7        7.8        7.1        0.3        0.9
## 6        0.0       11.7        5.7       12.3        4.9        0.0
##   tovpercent usgpercent  x  ows dws   ws  ws_48 x_2 obpm dbpm  bpm vorp
## 1        8.6       12.3 NA  0.1 0.3  0.4  0.071  NA -2.4 -1.1 -3.5 -0.1
## 2       17.7       14.6 NA -0.1 0.1  0.0  0.009  NA -2.7 -1.0 -3.6 -0.1
## 3       16.6       15.7 NA  1.2 0.9  2.1  0.200  NA  0.9  2.2  3.1  0.6
## 4       13.6       13.3 NA  0.1 0.2  0.3  0.123  NA -4.4 -1.6 -6.0 -0.1
## 5       12.7       10.4 NA -0.1 0.0 -0.1 -0.019  NA -4.5 -1.1 -5.6 -0.2
## 6        0.0       12.5 NA  0.0 0.0  0.0 -0.078  NA -7.4  1.3 -6.1  0.0
##                        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