Introduction to ballr

Ryan Elmore

2017-11-12

Introduction

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

Install the package

library(devtools)
devtools::install_github("rtelmore/ballr")
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 11  2      0.846   — 10  3 102.8  94.0
## 2      Detroit Pistons  9  3      0.750 1.5  8  4 106.1 101.1
## 3        Orlando Magic  8  5      0.615   3  8  5 110.5 107.6
## 4      Toronto Raptors  7  4      0.636   3  7  4 110.1 105.2
## 5      New York Knicks  7  5      0.583 3.5  7  5 106.4 105.0
## 6   Washington Wizards  7  5      0.583 3.5  8  4 111.5 107.1
## 7      Milwaukee Bucks  6  6      0.500 4.5  5  7 103.8 105.3
## 8   Philadelphia 76ers  6  6      0.500 4.5  5  7 107.9 109.8
## 9           Miami Heat  6  6      0.500 4.5  6  6 101.8 102.3
## 10 Cleveland Cavaliers  6  7      0.462   5  5  8 110.2 113.4
## 11      Indiana Pacers  6  7      0.462   5  7  6 109.0 108.4
## 12   Charlotte Hornets  5  7      0.417 5.5  5  7 103.4 104.9
## 13       Brooklyn Nets  5  8      0.385   6  5  8 110.6 114.5
## 14       Chicago Bulls  2  9      0.182   8  2  9  93.6 103.9
## 15       Atlanta Hawks  2 11      0.154   9  3 10 102.5 110.8
## 
## $West
##        western_conference  w  l w_lpercent  gb pw pl  ps_g  pa_g
## 1         Houston Rockets 10  3      0.769   —  9  4 110.5 103.5
## 2   Golden State Warriors 10  3      0.769   — 11  2 120.3 108.3
## 3       San Antonio Spurs  8  5      0.615   2  8  5 103.0  99.6
## 4          Denver Nuggets  8  5      0.615   2  8  5 107.6 105.2
## 5       Memphis Grizzlies  7  5      0.583 2.5  7  5 101.0  99.1
## 6  Minnesota Timberwolves  7  5      0.583 2.5  5  7 108.8 111.8
## 7    New Orleans Pelicans  7  6      0.538   3  7  6 107.5 107.2
## 8  Portland Trail Blazers  6  6      0.500 3.5  8  4 105.5 100.7
## 9               Utah Jazz  6  7      0.462   4  6  7  98.3  99.6
## 10   Los Angeles Clippers  5  7      0.417 4.5  7  5 107.4 105.8
## 11  Oklahoma City Thunder  5  7      0.417 4.5  8  4 103.3  98.4
## 12     Los Angeles Lakers  5  8      0.385   5  5  8 103.5 106.8
## 13           Phoenix Suns  5  9      0.357 5.5  3 11 107.0 116.2
## 14       Sacramento Kings  3  9      0.250 6.5  2 10  94.8 105.3
## 15       Dallas Mavericks  2 11      0.154   8  3 10  99.5 107.4

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: 437 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    12     0  16.7   1.5   3.8
##  2     2        Quincy Acy    PF    27   BRK    10     0  17.6   1.7   4.8
##  3     3      Steven Adams     C    24   OKC    11    11  30.7   5.3   8.1
##  4     4       Bam Adebayo     C    20   MIA     8     3  14.0   1.4   2.9
##  5     5     Arron Afflalo    SG    32   ORL     9     0   9.4   0.4   1.7
##  6     6      Cole Aldrich     C    29   MIN     4     0   2.3   0.0   0.5
##  7     7 LaMarcus Aldridge    PF    32   SAS    13    13  32.8   8.5  16.9
##  8     8     Jarrett Allen     C    19   BRK     6     0  15.0   1.5   3.7
##  9     9        Tony Allen    SG    36   NOP    12     0  13.5   2.3   4.5
## 10    10   Al-Farouq Aminu    PF    27   POR     8     8  30.1   3.3   7.5
## # ... with 427 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: 56 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 46 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 12  0 200 4.5 11.1     0.400 2.7  7.4
## 2  2    Quincy Acy  PF  27 BRK 10  0 176 4.4 12.4     0.354 3.9 10.9
## 3  3  Steven Adams   C  24 OKC 11 11 338 8.5 13.0     0.652 0.0  0.0
## 4  4   Bam Adebayo   C  20 MIA  8  3 112 4.8 10.0     0.478 0.0  0.0
## 5  5 Arron Afflalo  SG  32 ORL  9  0  85 2.2  8.3     0.267 0.6  3.3
## 6  6  Cole Aldrich   C  29 MIN  4  0   9 0.0 10.7     0.000 0.0  0.0
##   x3ppercent x2p x2pa x2ppercent  ft  fta ftpercent orb drb  trb ast stl
## 1      0.367 1.7  3.7      0.467 1.5  1.7     0.857 1.2 3.2  4.5 1.2 1.7
## 2      0.357 0.5  1.6      0.333 2.1  2.6     0.800 1.0 9.8 10.9 2.1 1.3
## 3         NA 8.5 13.0      0.652 2.8  3.7     0.760 6.4 7.0 13.5 1.9 2.5
## 4         NA 4.8 10.0      0.478 3.5  4.8     0.727 6.1 9.2 15.3 0.0 1.7
## 5      0.167 1.7  5.0      0.333 2.2  2.8     0.800 0.0 6.1  6.1 2.8 0.6
## 6         NA 0.0 10.7      0.000 5.4 10.7     0.500 0.0 5.4  5.4 5.4 5.4
##   blk tov   pf  pts  x ortg drtg                      link
## 1 0.2 1.2  6.4 13.1 NA  110  106 /players/a/abrinal01.html
## 2 0.0 2.9  6.5 14.8 NA   97  109   /players/a/acyqu01.html
## 3 2.0 2.8  3.5 19.8 NA  127  100 /players/a/adamsst01.html
## 4 1.7 1.3  5.2 13.1 NA  117  101 /players/a/adebaba01.html
## 5 0.6 1.7  2.8  7.2 NA   79  109 /players/a/afflaar01.html
## 6 0.0 0.0 10.7  5.4 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 12 200  7.5     0.551 0.667 0.156
## 2  2    Quincy Acy  PF  27 BRK 10 176  7.5     0.544 0.875 0.208
## 3  3  Steven Adams   C  24 OKC 11 338 21.9     0.675 0.000 0.281
## 4  4   Bam Adebayo   C  20 MIA  8 112 14.4     0.539 0.000 0.478
## 5  5 Arron Afflalo  SG  32 ORL  9  85  2.8     0.378 0.400 0.333
## 6  6  Cole Aldrich   C  29 MIN  4   9  0.9     0.174 0.000 1.000
##   orbpercent drbpercent trbpercent astpercent stlpercent blkpercent
## 1        2.7        7.5        5.1        3.5        1.7        0.4
## 2        2.2       22.7       12.1        6.3        1.3        0.0
## 3       14.3       16.3       15.3        6.1        2.5        3.7
## 4       14.2       20.0       17.2        0.0        1.7        2.8
## 5        0.0       13.7        7.1        7.3        0.6        0.9
## 6        0.0       13.1        6.4       13.5        5.4        0.0
##   tovpercent usgpercent  x  ows dws  ws  ws_48 x_2 obpm dbpm  bpm vorp
## 1        9.4       11.5 NA  0.2 0.2 0.4  0.091  NA -1.4 -0.7 -2.1  0.0
## 2       17.4       14.6 NA  0.0 0.1 0.1  0.031  NA -2.3 -1.0 -3.3 -0.1
## 3       16.0       15.3 NA  1.0 0.6 1.6  0.225  NA  1.8  3.1  4.9  0.6
## 4        9.7       12.1 NA  0.2 0.2 0.4  0.153  NA -3.7 -1.1 -4.8 -0.1
## 5       14.9       10.2 NA -0.1 0.1 0.0 -0.025  NA -5.5 -0.2 -5.7 -0.1
## 6        0.0       13.6 NA  0.0 0.0 0.0 -0.088  NA -7.2  1.7 -5.5  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