Skip to content

Instantly share code, notes, and snippets.

@andrewstellman
Last active April 15, 2019 12:07
Show Gist options
  • Save andrewstellman/4872dbb9dc7593e56abddbe8b998b509 to your computer and use it in GitHub Desktop.
Save andrewstellman/4872dbb9dc7593e56abddbe8b998b509 to your computer and use it in GitHub Desktop.
3-point shot percentage after other team makes or misses (NBA 2017-2018 season)

Analysis: 3-point shot percentage after other team makes or misses

This analysis shows how pbprdf was used to analyze NBA players' 3-point shot percentage after a player on the other team either made or missed a shot over the 2017-2018 regular season.

Overview

We're interested in finding 3-point shots that were made immediately after a 3-point shot taken by the other team. The way we do this is by running a SPARQL query that calculates each player's season 3-point shot percentage, the 3P% after a player on the other team misses, and the 3P% after a player on the other team makes. We want to calculate the percentage of 3-point shots that they make or miss when we include only shots that they took immediately after a player on the other team took a 3-pointer (within two lines on the play-by-play).

Here's the data that we're using to do this analysis. Each play has a set of triples that include:

games:2018-01-18_76ers_at_Celtics/21
        pbprdf:shotPoints "3"^^xsd:int ;
        a pbprdf:Shot ;
        pbprdf:shotMade "false"^^xsd:boolean ;
        pbprdf:shotBy players:Joel_Embiid ;
        pbprdf:forTeam teams:76ers ;
        pbprdf:period "1"^^xsd:int ;
        rdfs:label "76ers: Joel Embiid misses 25-foot three point jumper" ;
        pbprdf:previousEvent games:2018-01-18_76ers_at_Celtics/20 .

Our goal is to find 3-point shots that were made after a previous 3-point shot by a player on the other team. We'll look at all 3-point shots after a 3-pointer by a player on the other team, ones that were made after a make, and ones that were made after a miss.

To find them, we'll use a query with subqueries that look like this:

  # Find the number of 3-point shots missed after a player on the other team makes a 3
  {
    SELECT ?player (COUNT(?shot) AS ?shotsMadeAfterMake)
    {
      ?shot pbprdf:shotBy ?player .
      ?shot pbprdf:shotPoints "3"^^xsd:int .
      ?shot pbprdf:shotMade "false"^^xsd:boolean .
      ?shot pbprdf:forTeam ?shotTeam .
      {
        ?shot pbprdf:previousEvent ?previous .
      } UNION {
        ?shot pbprdf:previousEvent / pbprdf:previousEvent ?previous .
      }
      ?previous pbprdf:shotPoints "3"^^xsd:int .
      ?previous pbprdf:shotMade "true"^^xsd:boolean .
      ?previous pbprdf:forTeam ?previousShotTeam .
      FILTER (?shotTeam != ?previousShotTeam)
    }
    GROUP BY ?player 
  }

This subquery takes advantage of the pbprdf:previousEvent triple, which links each event in the play-by-play to the previous one. It looks for any missed 3-point shot that was preceded by a made 3-point shot taken by a player on the other team. It aggregates and combines these, just like in the clutch shot query.

We'll need a pair of subqueries for the overall 3-point field goal percentage (# made / # taken), a pair for made after miss, and a pair for made after make.

Analysis

The results of this query were pasted into a spreadsheet, with a summary row added withthe average and standard deviation calculation. The spreadsheet was sorted to make it easy to find the players with the highest 3P% after a player on the other team makes a shot.

The average 3P% after the other team makes or misses is pretty much in line with player's overall 3P% average. But here's the REALLY interesting part: the standard deviation for 3P% after a player on the other team makes a shot is more than twice as high (!!!) as standard 3P% standard deviation. This means this metric is extremely player-specific: some players have a HUGE "anything you can do, I can do better" motivation, and it shows up in their stats. So if a player on the other team just made a 3, you definitely want the ball in the hands of Karl-Anthony Towns or Kevin Durant.

What does it mean that Steph Curry actually has a lower 3-point percentage after a player on the other team makes a 3? I can think of some reasons that this is not necessarily a bad thing. Steph is, in many ways, the ultimate team player. Maybe he knows that his team gets especially fired up when a 3 is answered with a 3, or that there's a chance that the momentum can shift a 3 goes unanswered, so it's worth taking the shot.

Top results

This table show the top ten players with the highest 3-point shot percentage taken after another player makes a 3-point shot, along with the average and standard deviation over all players.

PlayerName ThreePointShotPercentage ShotPercentageAfterMiss ShotPercentageAfterMake
"Karl-Anthony Towns" 41.99 45.16 62.50
"Aaron Gordon" 33.86 33.33 56.67
"Kevin Durant" 42.07 42.00 54.29
"Anthony Tolliver" 44.66 39.58 51.28
"Tobias Harris" 41.57 43.64 51.11
"Paul George" 39.64 47.27 50.79
"CJ McCollum" 39.76 46.88 50.00
"Nikola Jokic" 38.75 22.22 50.00
"Robert Covington" 36.99 33.33 50.00
"Allen Crabbe" 38.27 36.36 48.39
AVERAGE 37.28 37.29 36.95
STDEV 3.42 7.74 8.70

Additional Files

The following additional files are attached:

  • SPARQL query.txt – the full query that generated the data
  • Full data.md – complete results of the query run against the 2017-2018 NBA Season (note that I'm missing a few play-by-play files from the season, so the 3PFG% may be slightly different than official NBA stats, but that shouldn't affect this analysis at all because it's based on complete games)
PlayerName ThreePointShotsTaken ThreePointShotsMade ThreePointShotPercentage ShotsTakenAfterMiss ShotsMadeAfterMiss ShotPercentageAfterMiss ShotsTakenAfterMake ShotsMadeAfterMake ShotPercentageAfterMake
3-point percentage After a player on the other team misses a 3-pointer After a player on the other team makes a 3-pointer
AVERAGE 355.78 133.44 37.28 39.82 14.99 37.29 31.74 11.87 36.95
STDEV 3.42 7.74 8.70
PlayerName ThreePointShotsTaken ThreePointShotsMade ThreePointShotPercentage ShotsTakenAfterMiss ShotsMadeAfterMiss ShotPercentageAfterMiss ShotsTakenAfterMake ShotsMadeAfterMake ShotPercentageAfterMake
"Karl-Anthony Towns" 281 118 41.99 31 14 45.16 32 20 62.5
"Aaron Gordon" 316 107 33.86 30 10 33.33 30 17 56.67
"Kevin Durant" 397 167 42.07 50 21 42 35 19 54.29
"Anthony Tolliver" 356 159 44.66 48 19 39.58 39 20 51.28
"Tobias Harris" 433 180 41.57 55 24 43.64 45 23 51.11
"Paul George" 555 220 39.64 55 26 47.27 63 32 50.79
"CJ McCollum" 425 169 39.76 32 15 46.88 32 16 50
"Nikola Jokic" 271 105 38.75 27 6 22.22 22 11 50
"Robert Covington" 519 192 36.99 48 16 33.33 32 16 50
"Allen Crabbe" 520 199 38.27 55 20 36.36 31 15 48.39
"Wilson Chandler" 235 87 37.02 25 8 32 27 13 48.15
"Joe Ingles" 439 194 44.19 48 23 47.92 38 18 47.37
"Marvin Williams" 305 126 41.31 39 19 48.72 32 15 46.88
"Dario Saric" 391 155 39.64 50 16 32 28 13 46.43
"JJ Redick" 443 188 42.44 46 13 28.26 28 13 46.43
"Jrue Holiday" 307 109 35.5 34 12 35.29 28 13 46.43
"Nikola Mirotic" 337 129 38.28 49 15 30.61 28 13 46.43
"LeBron James" 350 126 36 44 18 40.91 52 24 46.15
"Brook Lopez" 321 111 34.58 44 15 34.09 22 10 45.45
"Klay Thompson" 499 220 44.09 68 33 48.53 44 20 45.45
"Eric Bledsoe" 343 119 34.69 35 9 25.71 27 12 44.44
"Kyle Kuzma" 409 147 35.94 47 12 25.53 34 15 44.12
"Devin Booker" 330 130 39.39 29 12 41.38 28 12 42.86
"Kelly Oubre Jr." 361 124 34.35 43 14 32.56 28 12 42.86
"Tyreke Evans" 255 101 39.61 22 6 27.27 21 9 42.86
"Tim Hardaway Jr." 394 127 32.23 44 13 29.55 40 17 42.5
"Carmelo Anthony" 445 156 35.06 64 23 35.94 33 14 42.42
"Marc Gasol" 305 104 34.1 34 8 23.53 26 11 42.31
"Darius Miller" 345 143 41.45 37 18 48.65 31 13 41.94
"Kyle Lowry" 524 210 40.08 54 24 44.44 36 15 41.67
"Will Barton" 388 144 37.11 57 21 36.84 24 10 41.67
"Terry Rozier" 375 142 37.87 49 21 42.86 29 12 41.38
"Kyle Korver" 366 164 44.81 38 17 44.74 32 13 40.63
"CJ Miles" 436 160 36.7 36 13 36.11 35 14 40
"Justin Holiday" 430 152 35.35 35 10 28.57 45 18 40
"Lauri Markkanen" 391 142 36.32 50 19 38 45 18 40
"Troy Daniels" 426 171 40.14 38 14 36.84 35 14 40
"Wayne Ellington" 570 223 39.12 59 20 33.9 45 18 40
"Taurean Prince" 439 171 38.95 53 21 39.62 51 20 39.22
"Otto Porter Jr." 303 135 44.55 31 13 41.94 23 9 39.13
"Denzel Valentine" 358 140 39.11 55 22 40 26 10 38.46
"Josh Richardson" 331 126 38.07 38 17 44.74 26 10 38.46
"Nicolas Batum" 265 88 33.21 22 5 22.73 26 10 38.46
"Ryan Anderson" 329 126 38.3 39 14 35.9 26 10 38.46
"Jaylen Brown" 304 121 39.8 39 14 35.9 21 8 38.1
"PJ Tucker" 306 114 37.25 39 14 35.9 21 8 38.1
"Bogdan Bogdanovic" 313 124 39.62 37 9 24.32 29 11 37.93
"Lonzo Ball" 272 77 28.31 29 7 24.14 29 11 37.93
"Ricky Rubio" 271 96 35.42 26 14 53.85 29 11 37.93
"Tony Snell" 266 107 40.23 28 13 46.43 29 11 37.93
"DeMarcus Cousins" 278 96 34.53 31 4 12.9 37 14 37.84
"Marco Belinelli" 365 137 37.53 39 12 30.77 37 14 37.84
"Buddy Hield" 371 162 43.67 52 23 44.23 32 12 37.5
"Mario Hezonja" 264 89 33.71 29 12 41.38 24 9 37.5
"Kemba Walker" 567 220 38.8 55 23 41.82 62 23 37.1
"Chris Paul" 338 133 39.35 36 17 47.22 27 10 37.04
"Dragan Bender" 319 117 36.68 33 14 42.42 27 10 37.04
"JR Smith" 365 135 36.99 37 12 32.43 41 15 36.59
"Kelly Olynyk" 273 102 37.36 33 13 39.39 22 8 36.36
"Jordan Clarkson" 301 104 34.55 31 10 32.26 25 9 36
"Nikola Vucevic" 200 63 31.5 21 7 33.33 25 9 36
"Russell Westbrook" 294 86 29.25 38 13 34.21 31 11 35.48
"Bradley Beal" 484 183 37.81 56 24 42.86 48 17 35.42
"Jamal Murray" 390 147 37.69 40 14 35 34 12 35.29
"Gerald Green" 288 106 36.81 37 12 32.43 23 8 34.78
"Blake Griffin" 301 104 34.55 40 13 32.5 26 9 34.62
"Bobby Portis" 221 79 35.75 25 7 28 26 9 34.62
"Jamal Crawford" 309 102 33.01 37 12 32.43 29 10 34.48
"Andrew Wiggins" 332 110 33.13 36 13 36.11 42 14 33.33
"J.J. Barea" 301 107 35.55 39 10 25.64 33 11 33.33
"Nick Young" 304 113 37.17 34 16 47.06 21 7 33.33
"Quincy Acy" 285 101 35.44 34 12 35.29 30 10 33.33
"Serge Ibaka" 290 105 36.21 34 14 41.18 21 7 33.33
"Victor Oladipo" 393 149 37.91 55 22 40 43 14 32.56
"Lou Williams" 484 179 36.98 69 25 36.23 40 13 32.5
"Patty Mills" 396 146 36.87 40 17 42.5 37 12 32.43
"Trevor Ariza" 451 164 36.36 44 15 34.09 25 8 32
"Jae Crowder" 325 107 32.92 27 9 33.33 22 7 31.82
"Rodney Hood" 323 121 37.46 28 9 32.14 22 7 31.82
"Kyrie Irving" 387 159 41.09 42 14 33.33 41 13 31.71
"Donovan Mitchell" 509 173 33.99 42 19 45.24 51 16 31.37
"Austin Rivers" 317 119 37.54 32 15 46.88 32 10 31.25
"Draymond Green" 251 76 30.28 26 12 46.15 29 9 31.03
"Gary Harris" 377 150 39.79 29 11 37.93 36 11 30.56
"Bojan Bogdanovic" 365 149 40.82 47 19 40.43 33 10 30.3
"Dennis Smith Jr." 304 94 30.92 38 17 44.74 30 9 30
"Mike Muscala" 165 61 36.97 22 9 40.91 24 7 29.17
"Dirk Nowitzki" 332 137 41.27 34 14 41.18 35 10 28.57
"Marcus Smart" 242 72 29.75 22 5 22.73 21 6 28.57
"Stephen Curry" 458 185 40.39 58 22 37.93 42 12 28.57
"Eric Gordon" 584 209 35.79 58 19 32.76 50 14 28
"Kevin Love" 322 136 42.24 47 21 44.68 26 7 26.92
"Spencer Dinwiddie" 379 119 31.4 33 10 30.3 26 7 26.92
"Damian Lillard" 576 214 37.15 52 16 30.77 45 12 26.67
"Dillon Brooks" 251 90 35.86 26 15 57.69 23 6 26.09
"Harrison Barnes" 319 113 35.42 37 11 29.73 27 7 25.93
"DeMarre Carroll" 377 138 36.6 47 17 36.17 31 8 25.81
"James Harden" 533 184 34.52 78 32 41.03 29 7 24.14
"Caris LeVert" 226 77 34.07 26 11 42.31 21 5 23.81
"Jonathon Simmons" 196 67 34.18 24 10 41.67 21 5 23.81
"Wesley Matthews" 378 139 36.77 42 15 35.71 32 7 21.88
"Jeremy Lamb" 246 91 36.99 23 8 34.78 34 7 20.59
"Al-Farouq Aminu" 331 124 37.46 37 18 48.65 22 4 18.18
"Khris Middleton" 396 143 36.11 47 24 51.06 22 4 18.18
"Courtney Lee" 273 112 41.03 31 13 41.94 28 5 17.86
"Kent Bazemore" 257 102 39.69 26 8 30.77 23 4 17.39
BASE <http://stellman-greene.com/pbprdf>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX pbprdf: <#>
SELECT ?playerName
?threePointShotsTaken ?threePointShotsMade ?threePointShotPercentage
?shotsTakenAfterMiss ?shotsMadeAfterMiss ?shotPercentageAfterMiss
?shotsTakenAfterMake ?shotsMadeAfterMake ?shotPercentageAfterMake
{
# Find the number of shots taken
{
SELECT ?player (COUNT(?shot) AS ?threePointShotsTaken)
{
?shot pbprdf:shotBy ?player .
?shot pbprdf:shotPoints "3"^^xsd:int .
}
GROUP BY ?player
}
# Find the number of shots made
{
SELECT ?player (COUNT(?shot) AS ?threePointShotsMade)
{
?shot pbprdf:shotBy ?player .
?shot pbprdf:shotPoints "3"^^xsd:int .
?shot pbprdf:shotMade "true"^^xsd:boolean .
}
GROUP BY ?player
}
# Calculate the shot percentage
BIND ( (round((?threePointShotsMade / ?threePointShotsTaken) * 10000)) / 100 AS ?threePointShotPercentage ) .
# Find the number of 3-point shots taken after a player on the other team misses a 3
{
SELECT ?player (COUNT(?shot) AS ?shotsTakenAfterMiss)
{
?shot pbprdf:shotBy ?player .
?shot pbprdf:shotPoints "3"^^xsd:int .
?shot pbprdf:forTeam ?shotTeam .
{
?shot pbprdf:previousEvent ?previous .
} UNION {
?shot pbprdf:previousEvent / pbprdf:previousEvent ?previous .
}
?previous pbprdf:shotPoints "3"^^xsd:int .
?previous pbprdf:shotMade "false"^^xsd:boolean .
?previous pbprdf:forTeam ?previousShotTeam .
FILTER (?shotTeam != ?previousShotTeam)
}
GROUP BY ?player
}
# Find the number of 3-point shots made after a player on the other team misses a 3
{
SELECT ?player (COUNT(?shot) AS ?shotsMadeAfterMiss)
{
?shot pbprdf:shotBy ?player .
?shot pbprdf:shotPoints "3"^^xsd:int .
?shot pbprdf:shotMade "true"^^xsd:boolean .
?shot pbprdf:forTeam ?shotTeam .
{
?shot pbprdf:previousEvent ?previous .
} UNION {
?shot pbprdf:previousEvent / pbprdf:previousEvent ?previous .
}
?previous pbprdf:shotPoints "3"^^xsd:int .
?previous pbprdf:shotMade "false"^^xsd:boolean .
?previous pbprdf:forTeam ?previousShotTeam .
FILTER (?shotTeam != ?previousShotTeam)
}
GROUP BY ?player
}
# Calculate the shot percentage
BIND ( (round((?shotsMadeAfterMiss / ?shotsTakenAfterMiss) * 10000)) / 100 AS ?shotPercentageAfterMiss ) .
# Find the number of 3-point shots taken after a player on the other team makes a 3
{
SELECT ?player (COUNT(?shot) AS ?shotsTakenAfterMake)
{
?shot pbprdf:shotBy ?player .
?shot pbprdf:shotPoints "3"^^xsd:int .
?shot pbprdf:forTeam ?shotTeam .
{
?shot pbprdf:previousEvent ?previous .
} UNION {
?shot pbprdf:previousEvent / pbprdf:previousEvent ?previous .
}
?previous pbprdf:shotPoints "3"^^xsd:int .
?previous pbprdf:shotMade "true"^^xsd:boolean .
?previous pbprdf:forTeam ?previousShotTeam .
FILTER (?shotTeam != ?previousShotTeam)
}
GROUP BY ?player
}
# Find the number of 3-point shots made after a player on the other team makes a 3
{
SELECT ?player (COUNT(?shot) AS ?shotsMadeAfterMake)
WHERE
{
?shot pbprdf:shotBy ?player .
?shot pbprdf:shotPoints "3"^^xsd:int .
?shot pbprdf:shotMade "true"^^xsd:boolean .
?shot pbprdf:forTeam ?shotTeam .
{
?shot pbprdf:previousEvent ?previous .
} UNION {
?shot pbprdf:previousEvent / pbprdf:previousEvent ?previous .
}
?previous pbprdf:shotPoints "3"^^xsd:int .
?previous pbprdf:shotMade "true"^^xsd:boolean .
?previous pbprdf:forTeam ?previousShotTeam .
FILTER (?shotTeam != ?previousShotTeam)
}
GROUP BY ?player
}
# Calculate the shot percentage and delta
BIND ( (round((?shotsMadeAfterMake / ?shotsTakenAfterMake) * 10000)) / 100 AS ?shotPercentageAfterMake ) .
# Only include players that take enough 3-pointers after missed and made 3-pointers
FILTER (?shotsTakenAfterMiss > 20)
FILTER (?shotsTakenAfterMake > 20)
?player rdfs:label ?playerName
}
ORDER BY DESC(?shotPercentage)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment