The “80 Point Club”

Whenever we talk about scoring in the NBA, typically the the conversation points towards heroic scoring feats such as Wilt Chamberlain’s 100 point game or Kobe Bryant’s 81 point game. Or Wilt Chamberlain’s 78 point game… Or Wilt Chamberlain’s pair of 73 point games… or Wilt Chamberlain’s 72 point game. Of those other spurious 70+ point games from the likes of David Thompson (73), David Robinson (71), Elgin Baylor (71), or Devin Booker (70). In the end, it’s almost always about scoring. In these games, each of these players put up a significant amount of their team’s points.

Screen Shot 2019-04-21 at 9.44.52 AM

All players that have scored 70 or more points in an NBA game.

 

However, for the uninitiated, scoring is not just simply putting the ball in the basket. It’s about getting your team to convert as many points per possession as possible. It’s a reason Steve Nash was a consecutive year MVP. It’s a reason why many people remember Magic Johnson as an elite scorer; he really wasn’t as only sub-20-PPG player for most of his career. And if you’ve been paying attention this year, it’s also why Ben Simmons and Giannis Antetokounmpo are such scoring threats despite rarely (or never) making a three point attempt during the season.

Simmons

Distribution of Ben Simmons’ scoring chart. Assisted baskets are green; made baskets are blue.

 

Screen Shot 2019-02-27 at 8.52.09 AM

Giannis Antetokounmpo’s scoring chart. Assisted field goals are red; Made field goals are blue.

 

Once we plot their spatial scoring distributions, we immediately see the scoring value of a player by looking beyond “where they make their shots.” From here, we look into how many points a player contributes to their team within a game. At a cursory look, we take a step back from “deeper” such as credit sharing techniques that Dean Oliver or I have shared in the past and simply look at the accumulated points from points and assists within a game.

Note: By looking at points + assisted points we will “score” more points than a team does in a game. In this, we try to take a step back from point splitting.

Points Responsible For: PTS + A-PTS

In something I have called points responsible for (PRF) since the mid-80’s, we simply add the points scored and assisted points scored. The reason for such a term is from my days as a kid watching the Showtime Lakers with Chick Hearn and Stu Lantz on the television commentating the game. During one game, Magic Johnson had contributed to a series of baskets, causing Chick Hearn to say (as I most likely faulty remember) “Another basket by Magic. He’s contributed to [x-amount] points over their last [y-points scored].” And it was his points scored and assisted points. Ever since then I, in a nuanced fashion and to confused response, would tell people in games how many points they contributed.

By counting the contribution of a player through PRF, we start to understand how many points a player is really scoring. Consider a simpler, poor-man’s version of offensive rating. And in keeping with traditional statistics, such as points, we can start to look at the same question we introduced at the beginning of this article: who are the greatest single game scorers?

Not All Assists are Equal: Counting PRF

Recall that since the introduction of the three point line nearly 40 years ago, not all assists are created equal. To this end, we cannot simply count how many assists a player has and multiply it by a constant. Pre-1980 this is easy! Post 1979 this is much more difficult.

Using Play-By-Play

Using play-by-play, this is rather simple. We can look at every basket made and look at the assist tag. Using Python, we can simply plow through each action in play-by-play and hold results in dictionary.

for index,row in df.iterrows():
	if row['event_type'] == 'shot':
		player = row['player']+','+row['team']
		if player not in playersTemp:
			playersTemp[player] = [0.,0.,0.,0.,0.]
			if np.sum(playersTemp[player]) > 0.:
				print 'MASSIVE ERROR: PLAYERS TEMP FILE CAME INTO THE GAME NONEMPTY!!!', player, playersTemp[player]
		if row['points'] > 2.:
			# Three Point FG Made
			assistMan = str(row['assist'])+','+row['team']
			if assistMan not in playersTemp:
				playersTemp[assistMan] = [0.,0.,0.,0.,0.]
			if assistMan in playersTemp:
				playersTemp[assistMan] = [x+y for x,y in zip(playersTemp[assistMan],[0.,0.,0.,0.,3.])]
				playersTemp[player] = [x+y for x,y in zip(playersTemp[player],[0.,3.,0.,0.,0.])]
				if assistMan not in playerPTS:
					playerPTS[assistMan] = row['points']
				else:
					playerPTS[assistMan] += row['points']
				if player not in playerPTS:
					playerPTS[player] = row['points']
					teamPTS = buildTeam(row['team'],row['points'],teamPTS)
				else:
					playerPTS[player] += row['points']
					teamPTS = buildTeam(row['team'],row['points'],teamPTS)
			else:
				playersTemp[player] = [x+y for x,y in zip(playersTemp[player],[0.,3.,0.,0.,0.])]
				if player not in playerPTS:
					playerPTS[player] = row['points']
					teamPTS = buildTeam(row['team'],row['points'],teamPTS)
				else:
					playerPTS[player] += row['points']
					teamPTS = buildTeam(row['team'],row['points'],teamPTS)
		elif row['points'] > 1.:
			# Two Point FG Made
			assistMan = str(row['assist'])+','+row['team']
			if assistMan not in playersTemp:
				playersTemp[assistMan] = [0.,0.,0.,0.,0.]
			if assistMan in playersTemp:
				playersTemp[assistMan] = [x+y for x,y in zip(playersTemp[assistMan],[0.,0.,0.,2.,0.])]
				playersTemp[player] = [x+y for x,y in zip(playersTemp[player],[2.,0.,0.,0.,0.])]
				if assistMan not in playerPTS:
					playerPTS[assistMan] = row['points']
				else:
					playerPTS[assistMan] += row['points']
				if player not in playerPTS:
					playerPTS[player] = row['points']
					teamPTS = buildTeam(row['team'],row['points'],teamPTS)
				else:
					playerPTS[player] += row['points']
					teamPTS = buildTeam(row['team'],row['points'],teamPTS)
			else:
				playersTemp[player] = [x+y for x,y in zip(playersTemp[player],[2.,0.,0.,0.,0.])]
				if player not in playerPTS:
					playerPTS[player] = row['points']
					teamPTS = buildTeam(row['team'],row['points'],teamPTS)
				else:
					playerPTS[player] += row['points']
					teamPTS = buildTeam(row['team'],row['points'],teamPTS)
		elif float(row['points']) > 0.:
			# Free Throw Made
			print 'FREE THROW MADE'
			playersTemp[player] = [x+y for x,y in zip(playersTemp[player],[0.,0.,1.,0.,0.])]
			if player not in playerPTS:
				playerPTS[player] = row['points']
				teamPTS = buildTeam(row['team'],row['points'],teamPTS)
			else:
				playerPTS[player] += row['points']
				teamPTS = buildTeam(row['team'],row['points'],teamPTS)
	if row['event_type'] == 'free throw':
		player = str(row['player'])+','+str(row['team'])
		if player not in playersTemp:
			playersTemp[player] = [0.,0.,0.,0.,0.]
		if float(row['points']) > 0.:
			# Free Throw Made
			playersTemp[player] = [x+y for x,y in zip(playersTemp[player],[0.,0.,1.,0.,0.])]
			if player not in playerPTS:
				playerPTS[player] = row['points']
				teamPTS = buildTeam(row['team'],row['points'],teamPTS)
			else:
				playerPTS[player] += row['points']
				teamPTS = buildTeam(row['team'],row['points'],teamPTS)

And to this end, we can easily identify how much PRF Kobe had in his 81 point game and Devin had in his 70 point game.

  • Kobe Bryant: 86 PRF
    • 81 points
      • 42 points on 2PM
      • 21 points on 3PM
      • 18 points on FTM
    • 5 assisted points
      • 2 points on A-2PM
      • 3 points on A-3PM

 

  • Devin Booker: 83 PRF
    • 70 points
      • 34 points on 2PM
      • 12 points on 3PM
      • 24 points on FTM
    • 13 assisted points
      • 10 points on A-2PM
      • 3 points on A-3PM

And we see that both players contributed to slightly over 80 points. We also see that Kobe Bryant contributed to over seventy percent of his team’s scoring in the Toronto game. To this end, we can show Kobe’s scoring chart:

Screen Shot 2019-04-21 at 10.31.41 AM

Distribution of Kobe Bryant’s field goals (blue) and assists (red) from his 81 point game on January 22, 2006.

 

In the play-by-play era, both Kobe and Devin are the points “darlings” of the league. But who has the highest PRF? Not Russell Westbrook or LeBron James. Instead it’s…

James Harden: King of the PRF

Since 2004, James Harden has posted some of the highest PRF games. While Kobe Bryant has constructed an 86 point effort, James Harden is the only player in the play-by-play era to wrangle multiple 90-point games.

December 31, 2016: 95 points versus the Knicks

On December 31, 2016 James Harden posted one of the singly epic games in the history of the league with a 53 point, 42 assisted points game in a 129-122 win over the New York Knicks. This resulted in Harden having a hand in over 73% of the Rockets points.

Screen Shot 2019-04-21 at 10.38.00 AM

Distribution of James Harden’s points (blue) and assisted points (red) in his 95 PRF game against the New York Knicks (31-Dec-2016).

November 5, 2017: 91 points versus the Jazz

Just under a year later, Harden posted the second-best PRF total in the play-by-play era with a 91 point effort over the Utah Jazz on November 5, 2017. During this game, Harden dropped 56 points while contributing to 45 points via the assist. With a 137-110 victory over the Jazz, Harden contributed to two-thirds of the team’s points.

Screen Shot 2019-04-21 at 10.46.08 AM

Distribution of James Harden’s points (blue) and assisted points (red) in his 91 PRF game against the Utah Jazz (05-Nov-2017).

Before Play-By-Play: nbastatR

However, before play-by-play we have the added challenge of attempting to figure out how many three’s were assisted in the seasons between 1980 and the play-by-play years. To this end, we abandon Python in favor of R and a package developed by Alex Bresler, called nbastatR. Using nbastatR, we are able to leverage the NBA API to pull game logs from every season dating back to 1947.

for (season in seq(1947,1997)){
  if (season < 1980){
    multiplier <- 2.0
  }else{
    multiplier <- 3.0
    # We set this multiplier at 3 because it's maximum possible.
    # There's no play-by-play being leveraged here.
  }
  print(season)

  gamesPlayedByPlayer <- game_logs(seasons=season,league="NBA",result_types="player",season_types="Regular Season")
  print('made it here!')
  if ("ast" %in% colnames(gamesPlayedByPlayer)){
    cat("YES! ASSISTS ARE HERE!\n")
  }else{
    cat("NAH.... ASSISTS ARE MISSING!\n")
  }
  prf <- multiplier*gamesPlayedByPlayer$ast + gamesPlayedByPlayer$pts
  highPRF 79.
  highPRFindices <- which(highPRF)
  print(highPRFindices)
}

 

The above code identifies true PRF for all players pre-1980 and provides an upper bound for all players between the 1980 NBA season and the play-by-play era. One challenge we run into is that the NBA does not post assist totals for several seasons…

Screen Shot 2019-04-21 at 10.53.25 AM

Listing of all NBA seasons with and without assist totals. Even with an assist total existing, some games even miss assists.

Here we see that the NBA stats don’t have assist totals for several games. In fact, there are 14 seasons missing assists entirely; including Bob Cousy’s then record for most assists in a game (28). Similarly, for seasons that do report assists, some games have no assists included, such as Wilt Chamberlain’s December 8th, 1961 game. That’s alright, we can scan through Basketball Reference using the listing missing seasons. For these seasons, it’s straight-forward: walk through all game logs and compute PTS + 2*AST. Afterall, there’s no three point line back then.

Post-1980 Logic

Finally, we have to identify non-play-by-play assisted point totals. First we assume all assists are three point assists. By doing this, we provide an upper bound for all PRF totals. If no player hits a threshhold we like, the player game is dropped. From there, we can whittle down by looking at the box score and computing the value diff3AST and diff2AST which are created off the difference of the player scoring a three and the team scoring a three. This becomes encapsulated in the code block:

if (season > 1979){
      print(index)
      print(gamesPlayedByPlayer[index,]$namePlayer)
      print(gamesPlayedByPlayer[index,]$idGame)
      boxScores <- box_scores(gamesPlayedByPlayer[index,]$idGame,box_score_types = c("Traditional"))
      for (teamNum in seq(1,2)){
        if (boxScores$dataBoxScore[[2]][teamNum,]$slugTeam == gamesPlayedByPlayer[index,]$slugTeam){
          tot3PossAST <- boxScores$dataBoxScore[[2]][teamNum,]$fg3m - gamesPlayedByPlayer[index,]$fg3m
          diff2AST <- gamesPlayedByPlayer[index,]$ast - tot3PossAST
          print(diff2AST)
          if (diff2AST < 0.){
            diff2AST <- 0.
            diff3AST <- gamesPlayedByPlayer[index,]$ast
          }else{
            diff3AST <- gamesPlayedByPlayer[index,]$ast - diff2AST
          }
          print("Diff 3AST")
          print(diff3AST)
          print ("Diff 2AST")
          print (diff2AST)
          print(gamesPlayedByPlayer[index,]$ast)
          astPTS <- 3.*diff3AST + 2.*diff2AST
          prf <- astPTS + gamesPlayedByPlayer[index,]$pts
          print(prf)
     }
}

The idea is simple. Suppose a player has 10 assists and we are interested in an 80 point threshhold. Similarly, they made 2 3PA while their team has made 10 3PA. Then the player cannot assist more than 8 3PA! Suppose the player scored 55 points. Then their maximum possible PRF is 55 + 28 for 83 points. If this happens, then we must scan the game footage (if it exists) to see where all the three’s happened. If four are not assisted by our player, they fall off the list.

Similarly, if that player only had 51 points, their maximum PRF is 79 and they cannot be a member of the 80-Point Club.

In this case, as seen by the R-code above, we also leverage nbastatR’s boxscore function.

80 Point Club

Since 80 points is rare air when it comes to personally scoring 80 points (Wilt and Kobe), we consider 80 points for PRF as the threshhold. In this case, we obtain five questionable players when it comes to three-point differential in calculating PRF. These five players:

  • Scott Skiles
    • December 30, 1990 vs. Denver
    • 22 points scored, 30 assists, 2 possible 3P-AST
    • Guaranteed 82 PRF, maximium possible 84 PRF
  • Michael Jordan
    • March 28, 1990 vs. Cleveland
    • 69 points scored, 6 assists, 1 possible 3P-AST
    • Guaranteed 81 PRF, maximum possible 82 PRF
  • David Robinson
    • April 24, 1994 vs. LA Clippers
    • 71 points scored, 5 assists, 1 possible 3P-AST
    • Guaranteed 81 PRF, maximum possible 82 PRF
  • Tim Hardaway
    • April 25, 1993 vs. Seattle
    • 41 points scored, 18 assists, 3 possible 3P-AST
    • Guaranteed 77 PRF, maximum possible 80 PRF
  • Jason Kidd
    • February 2nd, 1996 vs. Utah
    • 20 points scored, 25 assists, 11 possible 3P-AST
    • Guaranteed 70 PRF, maximum possible 81 PRF

And that’s it. Thank you, nbastatR! We find three players immediately qualify for the 80 Point Club, but we’d like to settle their actual score. And we have two questionable players, that would barely crack the bottom of the club. To find thruth, we seek game footage.

Scott Skiles: 30 Assist Game

Skile’s 30 assist game is not only a record setter for the then-lowly Orlando Magic, it also gave Skiles’ entry into the 80 Point Club. Thanks to YouTube:

We can view every single one of Skiles’ assists. In the game, there are only two possible assists and Skiles indeed picks one of the up, to Dennis Scott, securing him with 83 PRF.

Michael Jordan: 69 Point Game

Jordan’s highest scoring game came with one possible assist for three. That would be to Charles Davis. Thanks again to YouTube, we are able to see Charles’ and Chicago’s only non-Michael Jordan three point field goal:

And we see it was assisted to him by Stacey King. Therefore Jordan remains put at 81 PRF.

Jason Kidd: 25 Assist Game

In a double-overtime affair against the Utah Jazz, Jason Kidd set a personal best early in his career with 25 assists. With Dallas hitting a then-remarkable 14 three point field goals on a television-announcer-flabberghasting 32 attempts, Kidd was on the hook for 11 possible three point attempts; as he made 3 of the 14. Thanks once again to YouTube:

We see that Jason Kidd assisted effectively all but three three point attempts: David Wood hit two three point attempts, both with Kidd on the court; but both assisted by Jim Jackson. Also, George McCloud razzle-dazzled for a step-back three in overtime to knock Kidd well below the 80 Point Club limit.

Unknowns: David Robinson and Tim Hardaway

Unfortunately, we could not find footage for both the David Robinson and Tim Hardaway games. In Robinson’s case, there’s only one missing three point field goal, taken by 80 Point Club flirting Sleepy Floyd (had several PRF > 70 games in the 1980’s).

Similarly, Tim Hardaway’s game on April 25, 1993 against the Seattle Supersonics appears to be a mystery. Despite this, there are a total of three 3PM that could have been assisted by Hardaway; all belonging to Latrell Sprewell. To this end, Hardaway sits at 77 Points and will not be included into the 80 Point Club until proper verification is provided.

Finally, onto the club:

80 Point Club

Since 1947, there have been only 31 confirmed cases of players hitting 80+ PRF in a game. Despite having thirty cases, there are only 20 players who have reached the 80 PRF mark. As indicated earlier, the king of PRF is James Harden, who has hit this threshhold 6 times!

The next frequent player on the list is Oscar Robertson and Russell Westbrook with three entries. A curious note about Westbrook is that he is the only player to hit 80 PRF in a playoff game. Only one. Ever.

If you’re keeping track, this means there are only two players remaining with two 80+ PRF games. Those two players are Wilt Chamberlain and LeBron James. That’s it.

More strikingly, Magic Johnson never reached 80 PRF despite repeatedly hitting 75 throughout the 1980’s. Larry Bird? Not close. Michael Jordan? Once. And he needed 69 points. Kobe Bryant? Same, but with 81 points.

To date, here’s the list of verified 80 Point Club Games:

Screen Shot 2019-04-21 at 11.34.42 AM

80 Point Club.

Reflections

By looking at the list, we see a couple reflections. First, we see the “high scoring”-“low scoring”-“high scoring” phenomenon of the league between the early years through the muddling 80’s and 90’s to today’s three point revolution. Second, we see the exponential increase due to the three point revolution in the league through its stars. Graphically, these reflections are viewed this way:

Screen Shot 2019-04-21 at 11.46.30 AM

Three year moving average of 80 Point Club Games.

Using the graph, we see Oscar, Wilt, and Cousy dominating the 60’s. Throughout the 70’s and early 90’s we have special cases by singular players: Jordan’s 69 point game with Skiles’ 30 assist game for the 90s’; Pistol Pete, Rick Barry, and Nate Archibald buoying the 70’s with their singular performances.

We also see the death of the 80 Point Club in the late 90’s and early 2000’s as games ground to low scoring affairs. Then, as the three point revolution has taken off over the last 4-5 years, we see the number of 80 Point Games explode; thanks primarily in part to Harden and Westbrook.

As players continue to adapt to the three point line, we will start to see this list expand and eventually have to ditch the 80 Point Club in favor of a more exclusive club. Possibly a 100 Point Club? If so… how soon will it be until we have three members?

One thought on “The “80 Point Club”

  1. Pingback: Hawks waste Trae Young’s career night, and it’s clear changes are necessary – The Athletic | trend

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.