# All-NBA Predict #7 – Exploration of Historical NBA Team Defenses

So it took me about 5 posts to realize I was looking at basketball the wrong way, then I finally found some at least interesting observations last post when I looked at the top and bottom 10 offensive teams in history.

I’m going to do the same for defense.

Let’s John Nash this shit. You already know.

In [120]:
%load_ext rpy2.ipython

The rpy2.ipython extension is already loaded. To reload it, use:

In [121]:
%%R
# Load libraries & initial config
library(ggplot2)
library(gridExtra)
library(scales)

In [122]:
# Load libraries & initial config
%matplotlib nbagg
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import boto3
from StringIO import StringIO

In [123]:
# Retrieve team stats from S3
teamAggDfToAnalyze = pd.read_csv('https://s3.ca-central-1.amazonaws.com/2017edmfasatb/fas_boto/data/teamAggDfToAnalyze.csv', index_col = 0)

pd.set_option('display.max_rows', len(teamAggDfToAnalyze.dtypes))
print teamAggDfToAnalyze.dtypes
pd.reset_option('display.max_rows')

baseStats_Season                object
perGameStats_Tm                 object
baseStats_W                      int64
baseStats_L                      int64
baseStats_WLPerc               float64
baseStats_SRS                  float64
baseStats_Pace                 float64
baseStats_Rel_Pace             float64
baseStats_ORtg                 float64
baseStats_Rel_ORtg             float64
baseStats_DRtg                 float64
baseStats_Rel_DRtg             float64
perGameStats_Age               float64
perGameStats_MP                float64
perGameStats_FG                float64
perGameStats_FGA               float64
perGameStats_FGPerc            float64
perGameStats_2P                float64
perGameStats_2PA               float64
perGameStats_2PPerc            float64
perGameStats_3P                float64
perGameStats_3PA               float64
perGameStats_3PPerc            float64
perGameStats_FT                float64
perGameStats_FTA               float64
perGameStats_FTPerc            float64
perGameStats_ORB               float64
perGameStats_DRB               float64
perGameStats_TRB               float64
perGameStats_AST               float64
perGameStats_STL               float64
perGameStats_BLK               float64
perGameStats_TOV               float64
perGameStats_PF                float64
perGameStats_PTS               float64
opponentPerGameStats_FG        float64
opponentPerGameStats_FGA       float64
opponentPerGameStats_FGPerc    float64
opponentPerGameStats_2P        float64
opponentPerGameStats_2PA       float64
opponentPerGameStats_2PPerc    float64
opponentPerGameStats_3P        float64
opponentPerGameStats_3PA       float64
opponentPerGameStats_3PPerc    float64
opponentPerGameStats_FT        float64
opponentPerGameStats_FTA       float64
opponentPerGameStats_FTPerc    float64
opponentPerGameStats_ORB       float64
opponentPerGameStats_DRB       float64
opponentPerGameStats_TRB       float64
opponentPerGameStats_AST       float64
opponentPerGameStats_STL       float64
opponentPerGameStats_BLK       float64
opponentPerGameStats_TOV       float64
opponentPerGameStats_PF        float64
opponentPerGameStats_PTS       float64
season_start_year                int64
rtg_diff                       float64
dtype: object

In [124]:
# This function adjusts the input stats for pace and outputs per 100 possession metrics
def paceConversion(df, listOfFields):
for field in listOfFields:
df['{}_per_100_poss'.format(field)] = (100/df['baseStats_Pace'])*(48/(df['perGameStats_MP']/5))*df[field]

return df

# Select a subset of columns to manage size of dataframe
teamAggDfToAnalyzeSelectedColumns = teamAggDfToAnalyze[[
'season_start_year',
'perGameStats_Tm',
'baseStats_W',
'baseStats_WLPerc',
'perGameStats_MP',
'baseStats_Pace',
'baseStats_Rel_Pace',
'baseStats_ORtg',
'baseStats_Rel_ORtg',
'baseStats_DRtg',
'baseStats_Rel_DRtg',
'perGameStats_PTS',
'perGameStats_2PA',
'perGameStats_2PPerc',
'perGameStats_3PA',
'perGameStats_3PPerc',
'perGameStats_FGA',
'perGameStats_FGPerc',
'perGameStats_FTA',
'perGameStats_FTPerc',
'perGameStats_ORB',
'perGameStats_DRB',
'perGameStats_AST',
'perGameStats_STL',
'perGameStats_BLK',
'perGameStats_TOV',
'opponentPerGameStats_PTS',
'opponentPerGameStats_2PA',
'opponentPerGameStats_2PPerc',
'opponentPerGameStats_3PA',
'opponentPerGameStats_3PPerc',
'opponentPerGameStats_FGA',
'opponentPerGameStats_FGPerc',
'opponentPerGameStats_FTA',
'opponentPerGameStats_FTPerc',
'opponentPerGameStats_ORB',
'opponentPerGameStats_DRB',
'opponentPerGameStats_AST',
'opponentPerGameStats_STL',
'opponentPerGameStats_BLK',
'opponentPerGameStats_TOV'
]]

# Pace adjust the following metrics
teamAggDfToAnalyzeSelectedColumns,
[
'opponentPerGameStats_PTS',
'opponentPerGameStats_2PA',
'opponentPerGameStats_3PA',
'opponentPerGameStats_FGA',
'opponentPerGameStats_FTA',
'opponentPerGameStats_ORB',
'perGameStats_DRB',
'perGameStats_STL',
'perGameStats_BLK',
'opponentPerGameStats_TOV',
'opponentPerGameStats_STL',
'opponentPerGameStats_BLK'
]
)

C:\Users\chixwang\AppData\Local\Continuum\Anaconda2\lib\site-packages\ipykernel\__main__.py:4: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy


Let’s refresh our memory again to see what DRtg vs W/L% look like

In [125]:
# Scatter of DRtg vs W/L%
teamAggDfToAnalyzePaceAdjusted.plot(kind = 'scatter', x = 'baseStats_DRtg', y = 'baseStats_WLPerc', title = 'League Historical DRtg vs W/L%')

Out[125]:
<matplotlib.axes._subplots.AxesSubplot at 0x122c12b0>

Although the inverse relationship can definitely be seen, we don’t see quite the same strength of correlation between DRtg and W/L%. The the teams with the best DRtg are not the best teams of all time, but range anywhere from 35% to 80% W/L%. The worst DRtg teams are a bit more concentrated in the lower W/L% ranges, but still we see some variation here. Regardless, let’s look into the numbers to get a better sense of what’s going on.

Let’s exclude anything before the 80’s again to ensure we can pace adjust properly (recall that certain key stats weren’t recorded before the 80’s in the NBA).

In [126]:
# Drop all seasons before the 80's
print 'There have been {} teams in NBA history starting from the 79-80 season'.format(teamAggDfToAnalyzePaceAdjusted1979.shape[0])

There have been 1044 teams in NBA history starting from the 79-80 season

In [127]:
# Set variable top N teams to take
topN = 10

# Order by DRtg ascending (lower DRtg is better)
teamAggDfToAnalyzePaceAdjusted1979.sort_values('baseStats_DRtg', ascending = True, inplace = True)

# We'll give each team a unique identifier based on the year and team because some teams repeat (CHI)

# Extract top 10 teams

# Extract bottom 10 teams

print teamAggDfToAnalyzeTiersBottom

      season_start_year perGameStats_Tm  baseStats_W  baseStats_WLPerc  \
1034               2016             DEN           37             0.481
1035               2008             WAS           19             0.232
1036               2016             LAL           22             0.286
1037               1981             SDC           17             0.207
1038               1981             DEN           46             0.561
1039               1989             ORL           18             0.220
1040               2005             SEA           35             0.427
1041               1990             DEN           20             0.244
1042               2008             SAC           17             0.207
1043               1992             DAL           11             0.134

perGameStats_MP  baseStats_Pace  baseStats_Rel_Pace  baseStats_ORtg  \
1034            241.0            98.0                 1.6           113.6
1035            240.3            91.0                -0.7           105.4
1036            240.3            98.5                 2.1           106.1
1037            240.9           101.4                 0.5           106.6
1038            241.8           109.8                 8.9           114.3
1039            241.5           104.1                 5.8           105.8
1040            241.8            91.6                 1.1           111.1
1041            240.6           113.7                15.9           105.2
1042            242.7            94.2                 2.5           105.5
1043            240.6            99.5                 2.7            99.5

baseStats_Rel_ORtg  baseStats_DRtg       ...        \
1034                 4.8           113.5       ...
1035                -2.9           113.6       ...
1036                -2.7           113.7       ...
1037                -0.3           113.8       ...
1038                 7.4           113.9       ...
1039                -2.3           114.3       ...
1040                 4.9           114.4       ...
1041                -2.7           114.7       ...
1042                -2.8           114.7       ...
1043                -8.5           114.7       ...

opponentPerGameStats_FGA_per_100_poss  \
1034                              89.423321
1035                              87.912088
1036                              87.403436
1037                              85.085269
1038                              89.763929
1039                              90.309724
1040                              87.119529
1041                              85.187208
1042                              86.920237
1043                              82.908307

opponentPerGameStats_FTA_per_100_poss  \
1034                              22.355830
1035                              26.230948
1036                              24.639252
1037                              31.735037
1038                              25.943855
1039                              29.116771
1040                              29.798346
1041                              32.811551
1042                              30.862983
1043                              37.594456

opponentPerGameStats_ORB_per_100_poss  perGameStats_DRB_per_100_poss  \
1034                               9.348802                      34.753154
1035                              12.511833                      31.169829
1036                              10.545194                      32.649543
1037                              12.379612                      26.331238
1038                              15.005853                      26.938218
1039                              13.651470                      28.734912
1040                              13.219630                      29.473274
1041                              13.247444                      27.109008
1042                              13.017040                      30.338102
1043                              13.032745                      27.669520

perGameStats_STL_per_100_poss  perGameStats_BLK_per_100_poss  \
1034                       7.011601                       3.963079
1035                       8.231469                       4.938881
1036                       8.111688                       3.954448
1037                       7.663569                       3.537032
1038                       7.322133                       4.067852
1039                       7.159862                       3.436734
1040                       8.235179                       4.009232
1041                       9.124068                       4.386571
1042                       7.243353                       4.513974
1043                       7.919899                       4.310831

opponentPerGameStats_TOV_per_100_poss  \
1034                              12.194089
1035                              15.255656
1036                              14.398246
1037                              16.014895
1038                              16.271407
1039                              14.128794
1040                              15.820213
1041                              16.318044
1042                              15.116563
1043                              15.539042

opponentPerGameStats_STL_per_100_poss  \
1034                               8.434245
1035                               7.902210
1036                               8.618668
1037                               9.235584
1038                               8.226100
1039                               8.591834
1040                               7.910107
1041                               8.071291
1042                               9.027947
1043                               9.824685

opponentPerGameStats_BLK_per_100_poss  unique_team_id
1034                               5.080871        2016-DEN
1035                               5.816905        2008-WAS
1036                               5.373993        2016-LAL
1037                               5.796802        1981-SDC
1038                               6.237373        1981-DEN
1039                               6.491608        1989-ORL
1040                               5.309524        2005-SEA
1041                               5.614811        1990-DEN
1042                               5.458759        2008-SAC
1043                               6.315869        1992-DAL

[10 rows x 54 columns]

C:\Users\chixwang\AppData\Local\Continuum\Anaconda2\lib\site-packages\ipykernel\__main__.py:5: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
C:\Users\chixwang\AppData\Local\Continuum\Anaconda2\lib\site-packages\ipykernel\__main__.py:7: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
C:\Users\chixwang\AppData\Local\Continuum\Anaconda2\lib\site-packages\ipykernel\__main__.py:10: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy


Quick sanity check on the data looks good for now. No missing values.

## The Good

Let’s take a look at the best defensive teams in history.

In [128]:
pd.set_option('display.max_columns', len(teamAggDfToAnalyzeTiersTop.columns))
print(teamAggDfToAnalyzeTiersTop)
pd.reset_option('display.max_columns')

   season_start_year perGameStats_Tm  baseStats_W  baseStats_WLPerc  \
0               2003             SAS           57             0.695
1               1998             SAS           37             0.740
2               2003             DET           54             0.659
3               1998             ATL           31             0.620
4               2003             IND           61             0.744
5               1998             ORL           33             0.660
6               1998             NYK           27             0.540
7               1998             PHI           28             0.560
8               1998             POR           35             0.700
9               2000             SAS           58             0.707

perGameStats_MP  baseStats_Pace  baseStats_Rel_Pace  baseStats_ORtg  \
0            240.9            89.2                -0.9           102.2
1            241.5            88.6                -0.3           104.0
2            241.2            87.9                -2.2           102.0
3            241.5            85.3                -3.6           100.5
4            241.5            87.5                -2.6           103.8
5            241.0            88.8                -0.1           100.3
6            242.0            86.9                -2.0            98.6
7            243.0            88.6                -0.3            99.9
8            243.5            89.2                 0.3           104.8
9            241.8            89.6                -1.7           106.6

baseStats_Rel_ORtg  baseStats_DRtg  baseStats_Rel_DRtg  perGameStats_PTS  \
0                -0.7            94.1                -8.8              91.5
1                 1.8            95.0                -7.2              92.8
2                -0.9            95.4                -7.5              90.1
3                -1.7            97.1                -5.1              86.3
4                 0.9            97.2                -5.7              91.4
5                -1.9            97.4                -4.8              89.5
6                -3.6            97.5                -4.7              86.4
7                -2.3            97.6                -4.6              89.7
8                 2.6            97.7                -4.5              94.8
9                 3.6            98.0                -5.0              96.2

perGameStats_2PA  perGameStats_2PPerc  perGameStats_3PA  \
0              64.6                0.460              13.9
1              65.8                0.476              10.4
2              65.2                0.452              11.8
3              62.3                0.431              12.9
4              61.5                0.457              15.6
5              65.4                0.448              13.5
6              62.3                0.450              11.8
7              70.2                0.444               7.4
8              65.6                0.457              13.5
9              63.0                0.472              13.3

perGameStats_3PPerc  perGameStats_FGA  perGameStats_FGPerc  \
0                0.358              78.5                0.442
1                0.330              76.2                0.456
2                0.344              77.0                0.435
3                0.306              75.2                0.409
4                0.351              77.1                0.435
5                0.330              78.9                0.428
6                0.353              74.1                0.435
7                0.264              77.7                0.426
8                0.364              79.1                0.442
9                0.407              76.4                0.461

perGameStats_FTA  perGameStats_FTPerc  perGameStats_ORB  perGameStats_DRB  \
0              25.2                0.681              12.5              32.5
1              28.3                0.698              12.3              31.7
2              25.3                0.753              12.4              30.4
3              28.4                0.731              13.5              30.0
4              24.6                0.764              11.8              29.9
5              25.0                0.700              13.8              28.9
6              24.4                0.732              11.0              30.2
7              29.7                0.722              14.6              28.6
8              27.0                0.743              12.9              31.4
9              28.5                0.715              11.0              33.1

perGameStats_AST  perGameStats_STL  perGameStats_BLK  perGameStats_TOV  \
0              20.4               8.1               6.5              14.7
1              22.0               8.4               7.0              15.2
2              20.8               8.0               7.0              15.1
3              15.6               6.9               5.2              14.9
4              21.6               8.9               5.0              14.4
5              21.3               9.9               4.3              16.4
6              19.3               7.9               5.2              16.1
7              18.7              10.8               5.4              16.4
8              21.5               8.2               5.8              15.4
9              21.7               6.9               7.0              14.0

opponentPerGameStats_PTS  opponentPerGameStats_2PA  \
0                      84.3                      66.3
1                      84.7                      70.0
2                      84.3                      63.4
3                      83.4                      64.8
4                      85.6                      63.0
5                      86.9                      63.8
6                      85.4                      62.6
7                      87.6                      61.4
8                      88.5                      65.0
9                      88.4                      69.8

opponentPerGameStats_2PPerc  opponentPerGameStats_3PA  \
0                        0.423                      11.6
1                        0.417                      11.2
2                        0.438                      14.4
3                        0.435                      12.7
4                        0.453                      12.4
5                        0.463                      13.3
6                        0.414                      13.2
7                        0.443                      14.3
8                        0.438                      13.8
9                        0.435                      12.7

opponentPerGameStats_3PPerc  opponentPerGameStats_FGA  \
0                        0.327                      77.9
1                        0.304                      81.2
2                        0.302                      77.8
3                        0.300                      77.5
4                        0.324                      75.4
5                        0.345                      77.1
6                        0.353                      75.8
7                        0.337                      75.7
8                        0.318                      78.8
9                        0.329                      82.6

opponentPerGameStats_FGPerc  opponentPerGameStats_FTA  \
0                        0.409                      22.5
1                        0.402                      23.0
2                        0.413                      21.1
3                        0.413                      21.5
4                        0.432                      22.0
5                        0.443                      19.7
6                        0.403                      26.7
7                        0.423                      25.8
8                        0.417                      25.3
9                        0.419                      20.3

opponentPerGameStats_FTPerc  opponentPerGameStats_ORB  \
0                        0.744                      11.1
1                        0.701                      13.9
2                        0.744                      12.0
3                        0.729                      11.6
4                        0.750                      10.6
5                        0.707                      11.9
6                        0.733                      12.3
7                        0.731                      12.4
8                        0.725                      12.3
9                        0.741                      11.8

opponentPerGameStats_DRB  opponentPerGameStats_AST  \
0                      30.0                      17.3
1                      28.1                      18.8
2                      28.7                      19.0
3                      27.4                      17.9
4                      29.5                      20.1
5                      28.5                      20.8
6                      28.5                      18.5
7                      28.0                      20.0
8                      27.8                      19.2
9                      29.7                      19.7

opponentPerGameStats_STL  opponentPerGameStats_BLK  \
0                       7.7                       4.6
1                       8.7                       4.9
2                       7.9                       5.0
3                       7.6                       4.9
4                       7.1                       6.2
5                       9.4                       4.8
6                       8.5                       4.3
7                       8.7                       5.3
8                       8.2                       4.9
9                       7.3                       5.2

opponentPerGameStats_TOV  opponentPerGameStats_PTS_per_100_poss  \
0                      15.3                              94.153650
1                      14.6                              95.004417
2                      16.0                              95.427300
3                      13.5                              97.165284
4                      15.9                              97.220941
5                      17.3                              97.454301
6                      15.3                              97.461697
7                      17.9                              97.650698
8                      15.7                              97.789155
9                      13.5                              97.926267

opponentPerGameStats_2PA_per_100_poss  \
0                              74.049668
1                              78.516047
2                              71.768575
3                              75.495329
4                              71.552795
5                              71.548727
6                              71.441478
7                              68.444667
8                              71.822543
9                              77.321872

opponentPerGameStats_3PA_per_100_poss  \
0                              12.955900
1                              12.562567
2                              16.300749
3                              14.796152
4                              14.083407
5                              14.915330
6                              15.064337
7                              15.940696
8                              15.248478
9                              14.068593

opponentPerGameStats_FGA_per_100_poss  \
0                              87.005568
1                              91.078614
2                              88.069323
3                              90.291481
4                              85.636202
5                              86.464057
6                              86.505816
7                              84.385364
8                              87.071021
9                              91.501241

opponentPerGameStats_FTA_per_100_poss  \
0                              25.129978
1                              25.798130
2                              23.885125
3                              25.048604
4                              24.986690
5                              22.092632
6                              30.471046
7                              28.760137
8                              27.955544
9                              22.487593

opponentPerGameStats_ORB_per_100_poss  perGameStats_DRB_per_100_poss  \
0                              12.397456                      36.298857
1                              15.591044                      35.556553
2                              13.583957                      34.412692
3                              13.514596                      34.951541
4                              12.039042                      33.959184
5                              13.345296                      32.410003
6                              14.037223                      34.465378
7                              13.822702                      31.881392
8                              13.591035                      34.695813
9                              13.071606                      36.666962

perGameStats_STL_per_100_poss  perGameStats_BLK_per_100_poss  \
0                       9.046792                       7.259771
1                       9.421926                       7.851605
2                       9.055972                       7.923975
3                       8.038854                       6.058267
4                      10.108252                       5.678793
5                      11.102389                       4.822250
6                       9.015778                       5.934436
7                      12.039127                       6.019564
8                       9.060690                       6.408781
9                       7.643566                       7.754342

opponentPerGameStats_TOV_per_100_poss  \
0                              17.088385
1                              16.376204
2                              18.111943
3                              15.728194
4                              18.058563
5                              19.401144
6                              17.460936
7                              19.953739
8                              17.347907
9                              14.954803

opponentPerGameStats_STL_per_100_poss  \
0                               8.600037
1                               9.758423
2                               8.942772
3                               8.854390
4                               8.063886
5                              10.541662
6                               9.700520
7                               9.698186
8                               9.060690
9                               8.086671

opponentPerGameStats_BLK_per_100_poss unique_team_id
0                               5.137684       2003-SAS
1                               5.496123       1998-SAS
2                               5.659982       2003-DET
3                               5.708752       1998-ATL
4                               7.041704       2003-IND
5                               5.382976       1998-ORL
6                               4.907322       1998-NYK
7                               5.908090       1998-PHI
8                               5.414315       1998-POR
9                               5.760369       2000-SAS


Hmm, 6 of the 10 teams are from from the 1998 season. Upon googling, this was one of the lockout seasons with only 50 games played. Perhaps the shortened schedule. The wiki article on the 98-99 season also indicated that certain teams didn’t meet each other, and inter-conference games were slashed to preserve intra-conference games. I’m going to exclude the 1998 data, which is a bit shady because theoretically I should have removed it from my offensive analysis as well. Looking back, there was only 1 team from 98 (bulls) that showed up in either the top 10 / bottom 10 offensive teams, so maybe not that big of a deal. But for integrity in later analysis, I’ll have to keep this in mind.

In [129]:
# Drop all seasons before the 80's
print 'There have been {} teams in NBA history starting from the 79-80 season, excluding the 98-99 season'.format(teamAggDfToAnalyzePaceAdjusted19791998Excl.shape[0])

There have been 1015 teams in NBA history starting from the 79-80 season, excluding the 98-99 season

In [130]:
# Set variable top N teams to take
topN = 10

# Order by DRtg ascending (lower DRtg is better)
teamAggDfToAnalyzePaceAdjusted19791998Excl.sort_values('baseStats_DRtg', ascending = True, inplace = True)

# We'll give each team a unique identifier based on the year and team because some teams repeat (CHI)

# Extract top 10 teams

# Extract bottom 10 teams

pd.set_option('display.max_columns', len(teamAggDfToAnalyzeTiersTop.columns))
print(teamAggDfToAnalyzeTiersTop)
pd.reset_option('display.max_columns')

   season_start_year perGameStats_Tm  baseStats_W  baseStats_WLPerc  \
0               2003             SAS           57             0.695
1               2003             DET           54             0.659
2               2003             IND           61             0.744
3               2003             NJN           47             0.573
4               2000             PHO           51             0.622
5               2000             SAS           58             0.707
6               2002             NJN           49             0.598
7               2011             BOS           39             0.591
8               1999             LAL           67             0.817
9               1993             NYK           57             0.695

perGameStats_MP  baseStats_Pace  baseStats_Rel_Pace  baseStats_ORtg  \
0            240.9            89.2                -0.9           102.2
1            241.2            87.9                -2.2           102.0
2            241.5            87.5                -2.6           103.8
3            240.3            89.4                -0.7           100.8
4            241.5            93.1                 1.8           100.3
5            241.8            89.6                -1.7           106.6
6            240.9            91.6                 0.6           103.8
7            241.5            90.4                -0.9           101.0
8            241.5            93.3                 0.2           107.3
9            240.9            92.8                -2.3           105.7

baseStats_Rel_ORtg  baseStats_DRtg  baseStats_Rel_DRtg  perGameStats_PTS  \
0                -0.7            94.1                -8.8              91.5
1                -0.9            95.4                -7.5              90.1
2                 0.9            97.2                -5.7              91.4
3                -2.1            98.0                -4.9              90.3
4                -2.7            98.0                -5.0              94.0
5                 3.6            98.0                -5.0              96.2
6                 0.2            98.1                -5.5              95.4
7                -3.6            98.2                -6.4              91.8
8                 3.2            98.2                -5.9             100.8
9                -0.6            98.2                -8.1              98.5

perGameStats_2PA  perGameStats_2PPerc  perGameStats_3PA  \
0              64.6                0.460              13.9
1              65.2                0.452              11.8
2              61.5                0.457              15.6
3              64.0                0.464              13.7
4              69.5                0.458              12.9
5              63.0                0.472              13.3
6              67.6                0.462              12.7
7              62.1                0.483              15.0
8              70.6                0.482              12.8
9              71.1                0.477              11.1

perGameStats_3PPerc  perGameStats_FGA  perGameStats_FGPerc  \
0                0.358              78.5                0.442
1                0.344              77.0                0.435
2                0.351              77.1                0.435
3                0.336              77.7                0.441
4                0.315              82.4                0.436
5                0.407              76.4                0.461
6                0.332              80.3                0.441
7                0.367              77.1                0.460
8                0.329              83.4                0.459
9                0.348              82.1                0.460

perGameStats_FTA  perGameStats_FTPerc  perGameStats_ORB  perGameStats_DRB  \
0              25.2                0.681              12.5              32.5
1              25.3                0.753              12.4              30.4
2              24.6                0.764              11.8              29.9
3              22.6                0.753              10.5              30.2
4              24.1                0.755              11.8              30.8
5              28.5                0.715              11.0              33.1
6              26.8                0.757              12.1              30.8
7              19.8                0.778               7.7              31.1
8              28.9                0.696              13.6              33.4
9              25.6                0.746              14.3              31.0

perGameStats_AST  perGameStats_STL  perGameStats_BLK  perGameStats_TOV  \
0              20.4               8.1               6.5              14.7
1              20.8               8.0               7.0              15.1
2              21.6               8.9               5.0              14.4
3              24.5               8.6               3.9              14.7
4              23.2               9.5               5.2              15.2
5              21.7               6.9               7.0              14.0
6              23.0               8.7               4.6              14.8
7              23.6               7.5               5.5              14.8
8              23.4               7.5               6.5              13.9
9              25.2               9.2               4.7              16.6

opponentPerGameStats_PTS  opponentPerGameStats_2PA  \
0                      84.3                      66.3
1                      84.3                      63.4
2                      85.6                      63.0
3                      87.8                      62.3
4                      91.8                      66.9
5                      88.4                      69.8
6                      90.1                      64.3
7                      89.3                      62.8
8                      92.3                      69.3
9                      91.5                      68.6

opponentPerGameStats_2PPerc  opponentPerGameStats_3PA  \
0                        0.423                      11.6
1                        0.438                      14.4
2                        0.453                      12.4
3                        0.445                      14.5
4                        0.449                      11.4
5                        0.435                      12.7
6                        0.442                      14.5
7                        0.449                      16.9
8                        0.434                      13.9
9                        0.450                      10.1

opponentPerGameStats_3PPerc  opponentPerGameStats_FGA  \
0                        0.327                      77.9
1                        0.302                      77.8
2                        0.324                      75.4
3                        0.350                      76.9
4                        0.349                      78.3
5                        0.329                      82.6
6                        0.359                      78.8
7                        0.308                      79.7
8                        0.326                      83.2
9                        0.307                      78.7

opponentPerGameStats_FGPerc  opponentPerGameStats_FTA  \
0                        0.409                      22.5
1                        0.413                      21.1
2                        0.432                      22.0
3                        0.427                      22.3
4                        0.435                      25.9
5                        0.419                      20.3
6                        0.427                      23.7
7                        0.419                      22.7
8                        0.416                      24.9
9                        0.431                      28.5

opponentPerGameStats_FTPerc  opponentPerGameStats_ORB  \
0                        0.744                      11.1
1                        0.744                      12.0
2                        0.750                      10.6
3                        0.761                      10.6
4                        0.761                      11.0
5                        0.741                      11.8
6                        0.749                      11.4
7                        0.760                      11.8
8                        0.742                      12.3
9                        0.719                      12.4

opponentPerGameStats_DRB  opponentPerGameStats_AST  \
0                      30.0                      17.3
1                      28.7                      19.0
2                      29.5                      20.1
3                      30.1                      19.8
4                      31.6                      20.1
5                      29.7                      19.7
6                      30.0                      19.6
7                      31.4                      18.7
8                      30.9                      19.5
9                      27.4                      20.5

opponentPerGameStats_STL  opponentPerGameStats_BLK  \
0                       7.7                       4.6
1                       7.9                       5.0
2                       7.1                       6.2
3                       8.0                       4.6
4                       8.3                       5.1
5                       7.3                       5.2
6                       8.5                       5.2
7                       7.8                       4.6
8                       7.6                       4.2
9                       8.3                       4.1

opponentPerGameStats_TOV  opponentPerGameStats_PTS_per_100_poss  \
0                      15.3                              94.153650
1                      16.0                              95.427300
2                      15.9                              97.220941
3                      16.1                              98.087681
4                      17.5                              97.991207
5                      13.5                              97.926267
6                      16.6                              97.994964
7                      15.7                              98.169626
8                      14.6                              98.313728
9                      17.3                              98.230773

opponentPerGameStats_2PA_per_100_poss  \
0                              74.049668
1                              71.768575
2                              71.552795
3                              69.599801
4                              71.411893
5                              77.321872
6                              69.934253
7                              69.037542
8                              73.815182
9                              73.646240

opponentPerGameStats_3PA_per_100_poss  \
0                              12.955900
1                              16.300749
2                              14.083407
3                              16.198991
4                              12.168843
5                              14.068593
6                              15.770555
7                              18.578574
8                              14.805643
9                              10.842960

opponentPerGameStats_FGA_per_100_poss  \
0                              87.005568
1                              88.069323
2                              85.636202
3                              85.910509
4                              83.580735
5                              91.501241
6                              85.704808
7                              87.616116
8                              88.620825
9                              84.489200

opponentPerGameStats_FTA_per_100_poss  \
0                              25.129978
1                              23.885125
2                              24.986690
3                              24.912930
4                              27.646757
5                              22.487593
6                              25.776700
7                              24.954653
8                              26.522338
9                              30.596470

opponentPerGameStats_ORB_per_100_poss  perGameStats_DRB_per_100_poss  \
0                              12.397456                      36.298857
1                              13.583957                      34.412692
2                              12.039042                      33.959184
3                              11.842021                      33.738587
4                              11.741866                      32.877224
5                              13.071606                      36.666962
6                              12.398919                      33.498834
7                              12.972022                      34.188974
8                              13.101396                      35.576149
9                              13.312148                      33.280371

perGameStats_STL_per_100_poss  perGameStats_BLK_per_100_poss  \
0                       9.046792                       7.259771
1                       9.055972                       7.923975
2                      10.108252                       5.678793
3                       9.607677                       4.356970
4                      10.140702                       5.550700
5                       7.643566                       7.754342
6                       9.462333                       5.003073
7                       8.244929                       6.046282
8                       7.988656                       6.923502
9                       9.876755                       5.045734

opponentPerGameStats_TOV_per_100_poss  \
0                              17.088385
1                              18.111943
2                              18.058563
3                              17.986465
4                              18.680241
5                              14.954803
6                              18.054566
7                              17.259385
8                              15.551251
9                              18.572594

opponentPerGameStats_STL_per_100_poss  \
0                               8.600037
1                               8.942772
2                               8.063886
3                               8.937374
4                               8.859771
5                               8.086671
6                               9.244808
7                               8.574727
8                               8.095172
9                               8.910551

opponentPerGameStats_BLK_per_100_poss unique_team_id
0                               5.137684       2003-SAS
1                               5.659982       2003-DET
2                               7.041704       2003-IND
3                               5.138990       2003-NJN
4                               5.443956       2000-PHO
5                               5.760369       2000-SAS
6                               5.655647       2002-NJN
7                               5.056890       2011-BOS
8                               4.473647       1999-LAL
9                               4.401597       1993-NYK

C:\Users\chixwang\AppData\Local\Continuum\Anaconda2\lib\site-packages\ipykernel\__main__.py:5: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
C:\Users\chixwang\AppData\Local\Continuum\Anaconda2\lib\site-packages\ipykernel\__main__.py:7: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
C:\Users\chixwang\AppData\Local\Continuum\Anaconda2\lib\site-packages\ipykernel\__main__.py:10: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy


Hmm, the top 4 teams are all from 2003. Am I missing something else here? Looking at the wiki page for the 03-04 season, nothing seems too out of the ordinary. Detroit won the championship, but they were one of the best defensive teams ever. SAS and IND also had good defensive teams then. I’ll just take this for what it is and go ahead with the data. Let’s take a look at some basic metrics

In [131]:
%%R -i teamAggDfToAnalyzeTiersTop -w 1000 -h 800 -u px

leagueNTeamsPlot <- function(tiersDf, tier){
# Opponent 2PA Scatter
leagueNTeams2PShooting = ggplot(
tiersDf,
aes(
x = opponentPerGameStats_2PA_per_100_poss,
y = opponentPerGameStats_2PPerc,
color = unique_team_id,
label = unique_team_id
)
) +
geom_point(size = 7) +
geom_text(hjust = -0.3) +
ggtitle(sprintf("%s Opponent Historical 2P Shooting", tier)) +
scale_x_continuous(expand = c(0, 2)) +
theme(legend.position="none")

# Opponent 3PA Scatter
leagueNTeams3PShooting = ggplot(
tiersDf,
aes(
x = opponentPerGameStats_3PA_per_100_poss,
y = opponentPerGameStats_3PPerc,
color = unique_team_id,
label = unique_team_id
)
) +
geom_point(size = 7) +
geom_text(hjust = -0.3) +
ggtitle(sprintf("%s Opponent Historical 3P Shooting", tier)) +
scale_x_continuous(expand = c(0, 2)) +
theme(legend.position="none")

# BLK / Opponent FG%
leagueNTeamsFTShooting = ggplot(
tiersDf,
aes(
x = perGameStats_BLK_per_100_poss,
y = opponentPerGameStats_FGPerc,
color = unique_team_id,
label = unique_team_id
)
) +
geom_point(size = 7) +
geom_text(hjust = -0.3) +
ggtitle(sprintf("%s Team Historical BLK / Opponent FG Shooting", tier)) +
scale_x_continuous(expand = c(0, 1)) +
theme(legend.position="none")

# ORB / TOV Scatter
leagueNTeamsORBTOVShooting = ggplot(
tiersDf,
aes(
x = perGameStats_STL_per_100_poss,
y = opponentPerGameStats_TOV_per_100_poss,
color = unique_team_id,
label = unique_team_id
)
) +
geom_point(size = 7) +
geom_text(hjust = -0.3) +
ggtitle(sprintf("%s Team Historical STL / Opponent TOV Stats", tier)) +
scale_x_continuous(expand = c(0, 1)) +
theme(legend.position="none")

grid.arrange(leagueNTeams2PShooting, leagueNTeams3PShooting, leagueNTeamsFTShooting, leagueNTeamsORBTOVShooting, ncol = 2)
}

leagueNTeamsPlot(teamAggDfToAnalyzeTiersTop, 'Top')


Okay, initial thoughts in no particular order:

• The rise of the 3-point shot is kind of apparent again! With the average percentages that teams have shot in league history, 47% 2P and 33% 3P, the 3P shot is actually more efficient, getting you more points per attempt (not by much, but over time would add up). Other than the 2011 celtics, all teams didn’t face too many 3 point shooting teams. Back in those days, you’d want your opponents to shoot 3’s because they may have been less favourable looks than 2’s if you had a good center. The percentages on 3’s are about average probably because teams weren’t shooting that many of them, guarding the 3 didn’t make too much of a different on your DRtg. For the 2011 celtics, teams were shooting more 3’s (nearly 20 attempts per game, more on par with the number of 3PA we see in the league today), but the celtics guarded that very very well, holding opponents to nearly 30%.
• The best defensive teams guarded their 2PA quite well, most holding their opponents to that 44-45% range, which is close to what we saw for very poor offensive teams. These guys essentially turned their opponents into horrible offensive teams. Attempts remained pretty consistent with what we’ve seen though per 100 possessions.
• Blocks share an inverse relationship with FG%
• Each block causes a missed FGA
• If your team gets the ball after your block, it’s counted as a missed FGA and a rebound
• If their team gets the ball after your block, it’s counted as a missed FGA and a rebound, and they an extended possession
• In both cases, a missed FGA is recorded and their FG% would go down. We see that trend here (albeit small sample size), and I have some questions but I’ll dive into it a bit later.
• Steals share a proportional relationship with turnovers, almost at a 1 to 1 ratio, and this was what I was hoping for because steals directly translate to turnovers at the end of the day

We’ve already discussed FGs in detail in our last post, so I will skip over this for now and focus on blocks and steals. FG will likely come back into the overall discussion of team defence, and to an extent I don’t even think you can talk about blocks and steals without talking about team defence or FG, but baby steps…

## Blocks

Let’s just start with baselining how many blocks an average team usually gets

In [132]:
# Blocks histogram
teamAggDfToAnalyzePaceAdjusted19791998Excl[['perGameStats_BLK_per_100_poss']].plot(kind = 'hist', title = 'League Historical Average Blocks / 100 Possessions')

perGameStats_BLK_per_100_poss    5.323525
dtype: float64


Ok so your average team blocks about 5.3 per game. On average, we saw that the better defensive teams (in terms of blocking) were getting 7-8. The difference in opponent FT% was only 1-2% less. If we go with our initial assumption that a team take about 85 shots, 2 blocks would cause the opponent field goals to go down about 2.3%. Does this matter? I’m honestly not sure. Would they have even made those 2 FGA anyways? Did the 2 blocks come consecutively and ended up in a score on the opponent’s third try anyways? There’s so many things that could happened after the block, it’s difficult to generalize it to a specific scenario. Even then, does 2.3% decrease in FGA even matter? We saw that good teams could shoot the 2 ball at like 50%, if they had shot at 47.7%, is that a big deal? Again, I’m not quite sure. we saw a difference from 50% to 45% matter in terms of being elite, so would 2.3% demote you down to a mid-tier team rather than an elite team? Again, very very difficult to say and depends on so many other factors.

At this point, I want to say that blocks don’t matter as much as steals.

## Steals

Steals to me in some ways define defense. Steals and forcing the other team to put up a tough shot, which in some cases may even be more analogous to a steal than a missed FGA, are exactly what you aim to do. When you steal the ball, their possession is done, period. You could block a shot 8 times in a row and still give up a score on the possession but you can’t steal a ball and give up a score. They’re done. DONE. Count that as a TOV, add one to the number of possessions without a score and continue with the game.

In our last post, we looked at the number of turnovers poor offensive teams had. They averaged around 18-19 TOV. To no surprise, we see that good defensive teams held their opponents to around that mark!

## Team Defense

Let’s pull this back up and look at defence as a whole, perhaps by style of defence or play. Again, honestly I don’t know too much about defence. My knowledge comes from pickup (i.e. no knowledge) or recreational league play (i.e. very very very limited knowledge). I don’t know that much, so the best thing for me to do is probably just dive into a few teams and do a small case study on ones that look interesting from the data and try to explain why things are the way they are. When I talk about team defense here, I’m not trying to be armchair Popovich (even from the armchair, pop can’t be replicated…) but I’m simply talking about styles of defense from an armchair perspective. Do their bigs have great blocking ability? Do their guards have quick hands? Do they seem to switch well on screens? Do they play big? Small? Etc. Leggo.

### 2003 Spurs

There are only 3 teams that break the 98 DRtg barrier, and the spurs sit at 94… alright then! Definitely keep in mind that this doesn’t mean the spurs were runaway the best team in the league. This year, they weren’t even first in their division and they were 3rd in their conference. This team had Timmy, TP, Manu, with Bowen, Horry, Rose, and Nesterovic as well. While the team did have two NBA all-defense calibre players in Bowen and Timmy, the team doesn’t strike me as being stifled with elite defenders. I could be showing my naivety here, but I’m looking to be proven wrong because obviously this team was great at defense.

What made me even pick the 2003 spurs in the first place is undoubtedly the opponent FG%. 42%. 42%. 42%!!!!! Opponents were generating

$(74\ 2PA\times 42\%\times 2\ Points)+(13\ 3PA\times 33\%\times 3\ Points)=75\ Points$

75 points off FGA. Remember that the rockets today pump out about:

$(48\ 2PA\times 55\%\times 2\ Points)+(40\ 3PA\times 36\%\times 3\ Points)=96\ Points$

HOU is one of the best offensive teams, sure, but the spurs held EVERY SINGLE TEAM for A WHOLE SEASON to an average of 20 POINTS LESS THAN THEM OFF FGA.

I wasn’t really sure where to start, so I just watched a spurs-pistons game from the 2005 finals. This is the game where Robert Horry hits the 3 in overtime to beat the pistons in game 5. I know that this is the wrong year, but I’m just trying to get a sense and refresh my memory of basketball in general because I haven’t watched a full game for a while. Just youtubed spurs full game and this one came up first. Notes in no particular order:

• For the spurs, really just two words: TIM F^#&@^# DUNCAN. Alright, fine, three words. Really though, you can see why they win. Forget offense and defense for a second. Tim Duncan does it everywhere and anywhere. On offense, the efficiency of scoring (let alone free throws in this game) just comes so seemingly easy. He’s just built so long and tall that it’s really hard to contest any of his jump hooks. On defense, same thing, his length really allows him to affect shots, rebounds, passes in the lane… you name it. Countless times it seems that Tim Duncan is in the middle of a missed FGA or turnover. There were times in this game where Detroit would keep switching Tim onto Billups. Generally, Billups got the best of Tim, but Billups is an elite and crafty point guard and Tim held his own in more or less any other situation. You rarely saw Sheed or Big Ben with any groundbreaking plays.
• Perhaps this was because Billups generally took over on the weaker TP or on a switch with Duncan. The Detroit offense undoubtedly ran through Billups, and more often than not he took advantage. On the final play of overtime, you see Bruce Bowen pick up Billups, and he gets stopped dead in his tracks. It seemed like a quiet night for Hamilton, though, perhaps because Billups was on HIM the whole time and he may have lit it up if TP was checking him. Regardless, many of the Detroit offensive advantages seemed to stem from Tony Parker. Right now I’m talking about team defense, but for many plays, it seemed the team defense was as bad as their weakest link, TP.
• In general, I felt the offensive talent in this game is just too good to really comment on defense too much. So many times Billups hit a crafty layup, or Tim Duncan just flipped up a swish, let alone Robert Horry taking over in the 4th & OT. Many of Horry and TD’s shots you can’t really defend. Billups shots were often defended decently but he just hit some crazy ones. If I take a look at the box score stats, it seems that both teams were okay.
• SAS had 50% on 2PA and 40% on 3PA. Elite. DET had 47% on 2PA and 22% on 3PA. SAS shot way more 3’s, and were more efficient shooting the 3, with 8 3PM vs 2 3PM. This seemed to even out the 5 extra turnovers they had over the pistons (16-11). So how exactly do you gauge defense here? Detroit couldn’t contain the SAS shooting at all, but when you have a weapon like Robert Horry going off from 3, to what degree can you contest that? DET had 7 steals on SAS, which caused the additional turnovers, so from that perspective, they played a great defensive game. On the other hand, SAS held DET to average 2P shooting and horrible 3P shooting. My initial impression was that Billups was lighting it up on offense, but would they have gotten better percentages had Duncan and Bowen not been there and Sheed and Hamilton could distribute the scoring as well? These are questions I’m not sure I know enough to answer without watching more tape.

### 2003 Pistons

The 2003 Detroit Pistons had your core of Billups, Hamilton, Prince, Sheed, Big Ben. They were notoriously known for defense. Why? I honestly don’t quite remember because I was like 15 then and still hated everything in my life. But now looking at the numbers, I do know that the Pistons held their opponents to

$(71\ 2PA\times 44\%\times 2\ Points)+(16\ 3PA\times 30\%\times 3\ Points)=77\ Points$

off FGA. 2 points worse than SAS, but for all intents and purposes, they were clearly both defensive beasts.

I watched the 2005 pistons – heat ECF game 1 (I know, again, not the same team exactly, but it was just the year after), and much like the spurs game, you could see why Detroit was so good. This was a great game to demonstrate their capabilities across the board.

I’d actually like to start off with offense ironically. The first thing I noticed was that all their starters, as well as many bench players, were deadly. Just deadly. Any of them could hit you with anything at any moment. Billups would scout the floor but had every capability of making a big shot or driving it to the hole. Hamilton could run circles around you and drill a midrange with high accuracy. Sheed basically did it all (especially this game), showing off like 4 threes, multiple jump hooks, and getting a few blocks. Prince, somehow seemingly weighing 90 pounds, could shoot or post up with the best of em. Big Ben, although not as offensively gifted, hit a few good shots but beasted on the defensive end. I mentioned some defensive notes in there, but again, offensively, you pick your poison. Who do you concentrate on? They’re all all-stars… The number of points they got: 16, 13, 13, 18, 20. Who got what? Does it matter? You could assign any name to any point total and you could believe it. 44% 2P% and 55% 3P%!! Great showing by the whole team!

I wanted to start with that because it’s pretty much the same story defensively. They are all gifted, and they move so well with each other. Their bigs are BEASTS. Although this game was also an insight into how dominant Shaq was (jesus christ…), their bigs did a pretty solid job overall. Looking at the data, I’m seeing the difference in numbers between 2-3 blocks, 2-3 steals, a contested shot here and there, a hard fought defensive board here and there… they add up to a ton of points. Miami played good defense too, but when you look at Sheed and Big Ben’s statlines, 3 steals, 6 blocks between the two. This goes for both teams in this game to be honest, but on the blocks front, man, so many shots altered. So many easy shots that should have been gimme layups erased. There were at least 6 points that should have gone down in history as easy points in this game, just gone. For steals, Big Ben (I think) poked the ball away from Shaq 3 times, and I remember distinctly (for both blocks and steals actually) that these lead to easy points on the other end. So in that case, not only did they erase a possible 2-3 points, they gained 2 points for a 4-5 point swing, all stemming from a single poke.

Watching these games, you really start to notice all the intricacies of what 1 number means in the grand scheme of things. Every time I see a block, I gotta think that it can either mean 0 points, or a 4-5 point swing!

Let’s watch one more game.

### 2011 Celtics

Third game. Game 6 2012 ECF BOS-MIA. To talk about BOS defense, you first have to talk about MIA offence. AKA Bron dropping 45 on 77% on 2PA mostly consisting of mid-range jumpers and 50% on 3PA. And therein lies the answer to Boston’s defense. To me, it’s not that Boston’s defense was bad, it’s just that Boston’s defense basically didn’t matter because if Lebron wants to pull up on your team 10 times with a mid-range jumper, you let him. Why would you want him to drive or find a cutting DWade when you can play your luck and see if he goes 25% on the night. Unfortunately, he went 77% on the night and you probably just let that one go.

Boston lost this game 98 – 79 and their starters were basically out midway through the fourth. There was a lot of hustle with MIA and BOS with 8 and 9 steals respectively (Rondo had 7 TOV, with him taking the blame for most of them), but at the end of the day it wasn’t even MIA’s defense that held BOS to such low points. BOS just couldn’t hit shots. KG was 6-14 with so many easy baby hooks missed, Paul Pierce was even worse with 4-18 and the C’s were 1-14 from 3.

Overall, very bad game to watch defense because nothing really happened lol. Bron was great, C’s were bad, and that’s all she wrote.

## The Ugly

Alright, let’s take a look at the ugly.

In [133]:
%%R -i teamAggDfToAnalyzeTiersBottom -w 1000 -h 800 -u px

leagueNTeamsPlot(teamAggDfToAnalyzeTiersBottom, 'Bottom')


I’ll make this one relatively short because I feel I’m starting to repeat a lot of the same concepts.

### Shooting

The thing that jumps out to me the most again is shooting. These teams were allowing FG% that elite teams were achieving. In essence, any team that played these teams played like an all-time elite team for that game. Opponents were shooting >50% up to like 54% on 2PA! Many of these teams were allowing 35-40% on 3PA as well! These, as we’ve seen before, are elite numbers. The answer probably really varies between team to team, but having watched a few games fresh in my mind, I feel that a large part of this was probably because either

1. The team didn’t have any superstars to rely on
2. The team just didn’t gel well together and didn’t play cohesively

If I think about what allows a team to shoot well. It’s one story if you have Lebron going off for 77%, but it’s another thing to let different teams average 54% 2PA on you for the entire season. To me, these teams were probably lacking both 1 and 2.

Their offense probably played a role here too because, after seeing how many easy buckets can happen from blocks and steals, these guys were likely blocked on and stolen from quite a bit as well to lead to easy buckets on the other end and higher FG%.

Let’s take a super quick look.

In [136]:
# Scatter of oppoenent pace adjusted steals and blocks
teamAggDfToAnalyzeTiersBottom.plot(kind = 'scatter', x = 'opponentPerGameStats_BLK_per_100_poss', y = 'opponentPerGameStats_STL_per_100_poss', title = 'Worst Defensive Teams\' Oppoent STL & BLK')

Out[136]:
<matplotlib.axes._subplots.AxesSubplot at 0x1387d048>

Hmm, these teams didn’t have as much STLs and BLKs against them as I would have imagined. The steals are getting up there, but the blocks are quite normal. Perhaps they were so poor offensively as well that they never even got the opportunity to have their shots blocked… if you get a steal, you can’t really get a block on that same possession! Anyways, I’ll avoid reading into this too deeply. Just a thought I had after freshly watching 3 games. Let’s move on.

### Blocks & Steals

Sorry for the possible confusion, but I was just talking about the OPPONENT’S blocks and steals. Let me switch over to the TEAM’S blocks and steals, and remember, these are the teams that are poor defensively.

Blocks immediately jump out. These teams averaged about 4 per game, about 50-75% of what great defensive teams had. I definitely have to do more tape watching to get a better feel for how blocks impact games. Again, when I first started writing these posts, I really didn’t think a block did much. After watching games, a block could result in a 4-5 point swing. That’s major if you keep getting blocks. Not to blow it out of proportion but it isn’t too crazy to see how a few blocks could result in a 10 point swing! Something else I noticed was that blocks get the momentum and crowd going… oh man. I’m not even sure how exactly to describe the intangible here, but honestly it isn’t too hard to see a situation where a team is about to start a run then a block plays a sparkplug role and gets the entire team and crowd into it. Eventually maybe the other team gets rattled and makes some stupid mistakes and you eventually score more easy baskets etc etc. It’s hard to measure with numbers, but it’s so obvious it smacks you in the face when you watch in person.

I’m not so sure I have more to say about steals. Not from a lack of something to say, but probably more from a lack of knowledge about the game. It can mean good individual defense, good team defense, poor decision making by the opponent… etc. However, it is interesting that even poor defensive teams were still getting a good 8 steals per game.

## Tying It All Together…

Over the past few posts, I’ve really just looked at a handful of the most obvious stats. There is so much more I can do, but it’ll be a process to explore everything. Really, what I’ve taken away most from my analysis thus far is a good benchmark / profile of what good teams’ numbers look like, and what bad teams’ numbers look like.

Good teams shoot >50% from 2PA and >33% from 3PA, and keep their opponents under those.
Good teams will do the dirty work in grabbing offensive boards, come up with momentum changing steals (9-10 / 100 poss) or blocks (7-8 / 100 poss).
Good teams will prevent turning the ball over (15 / 100 poss) and will force their opponents to (18-20 / 100 poss)

Out of 100 possessions, a good team will usually capitalize on 40-50 of their 85-90 shots per 100 possessions, and turn the ball over hopefully less than 15 times. Bonus for more ORBs to give them more shot opportunities.

With these numbers, let’s maybe focus back on the raptors and do a deeper dive, perhaps even getting into some of the players.