taylorbell.com

The Stats We Need

Similar to Sabermetrics in baseball, basketball offers many advanced statistics to play with.

For now though, we'll stick with some basics.

Here is a mini-glossary of the stats we'll use for estimating the score of the game:

  • FGA: Field goal attempts (aka "shots")
  • FGM: Field goals made
  • threePA: Three point shots attempted
  • threePM: Three pointers made
  • twoPA: Two point shots attempted
  • twoPM: Two pointers made
  • FTA: Free throw attempts
  • FTM: Free throws made
  • ORB: Offensive rebounds (the team shoots & misses but gets the ball back for another try)
  • DRB: Defensive rebounds (the team takes the ball from their opponent)
  • TOV: Turnovers (The team with the ball loses it without taking a shot. e.g. the ball is stolen, the shot clock runs out, ball goes out of bounds, fouls, etc.)

We get the number of two point field goals attempted and made by subtracting 3 point shots from fieldGoals. This number will be used shortly.

Shooting percentages will be calculated by dividing made / attempts.

Each team will have their own Possession estimate, calculated with some of their opponent's stats.

Where to get the stats?

For now we'll be using season averages, which can be gathered from the Basketball-reference.com team pages.

Later on as we make our model more robust, we'll write a scraper capable of averaging these stats over date ranges we supply.

Continuing on with our example Spurs @ Pelicans game, let's build the stats for the Spurs as they were leading up to January 22, 2020.

const awayTeamBaseStats = {
  name: 'Spurs',
  FGA: 90,
  FGM: 41.33,
  threePA: 31,
  threePM: 12.33,
  FTA: 23,
  FTM: 20.67,
  ORB: 9.67,
  TOV: 11.33
}

With these stats in place, we'll create a new object and use the spread operator in order to bring over all of our base stats and calculate some new ones:

const awayTeamStats = {
  ...awayTeamBaseStats,
  threePct: awayTeamBaseStats.threePM / awayTeamBaseStats.threePA,
  twoPA: awayTeamBaseStats.FGA - awayTeamBaseStats.threePA,
  twoPM: awayTeamBaseStats.FGM - awayTeamBaseStats.threePM,
  twoPct: (awayTeamBaseStats.FGM - awayTeamBaseStats.threePM) / awayTeamBaseStats.FGA - awayTeamBaseStats.threePA
  ftPct: awayTeamBaseStats.FTM / awayTeamBaseStats.FTA
}

Our resulting awayTeamStats object gives us the values we need in order to calculate possessions and a score:

awayTeamStats = {
  name: 'Spurs',
  FGA: 80.26,
  FGM: 37.43,
  threePA: 18.37,
  threePM: 6.88,
  threePct: 0.37,
  twoPA: 61.89,
  twoPM: 30.55,
  twoPct: 49.3,
  FTA: 23.87,
  FTM: 17.81,
  ftPct: 0.74,
  ORB: 10.52,
  DRB: 32.63,
  TOV: 13.34
}

We'll follow the same process to build stats for the home team Pelicans, resulting in:

homeTeamStats = {
  name: 'Pelicans',
  FGA: 81.56,
  FGM: 36.89,
  threePA: 18.04,
  threePM: 6.5,
  threePct: 0.36,
  twoPA: 63.52,
  twoPM: 30.39,
  twoPct: 0.47,
  FTA: 23.54,
  FTM: 17.94,
  ftPct: 0.76,
  ORB: 11.21,
  DRB: 31.26,
  TOV: 13.49
}

Now we can use our stats to start predicting each team's scores.