5. Keener’s Method
Keener’s Method states that the strength
\(s\) of a team should
consider its interaction with opponents and these opponents’ strengths, as well as,
be proportionally constant to its
rating
\(r\)\(s = \lambda r\).
The strength statistics \(a_{ij}\) created by the i-th team when playing the j-th team can be derived from something meaning such as wins, yards, passes, etc… For example, \(a_{ij}\) can be the number of wins by the i-th team over the j-th team.
\(a_{ij} = w_{ij}\)
Or it can consider ties as well.
\(a_{ij} = w_{ij} - \dfrac{t_{ij}}{2}\)
Whatever strength statistics you use, we can denoted as \(S_{ij}\).
\(a_{ij} = S_{ij}\)
Typically, we want want to normalize \(a_{ij}\) as follows to avoid disproportionate effects on the ratings.
\(a_{ij} = \dfrac{S_{ij}}{S_{ij} + S_{ji}}\)
But, since there are some pairs of teams that might have not played, we can use Laplace’s rule of succession to normalize as follows.
\(a_{ij} = \dfrac{S_{ij} + 1}{S_{ij} + S_{ji} + 2}\)
Keener also suggests that we apply a skewing function
to combat skew in the data. Skew could come from teams inflating their strength statistics to increase their ratings and thereby ranking. A particular skew function recommended by Keener is as follows.
\(h(x) = \dfrac{1}{2} + \dfrac{\mathrm{sgn} \{x - \frac{1}{2} \} \sqrt{|2x - 1|}}{2}\)
The strength \(s\) of each team is given as
\(s = Ar\),
where
\(A\) is a \(n\) x \(n\) matrix with \(a_{ij}\) element representing the strength statistic of the i-th team when it plays the j-th team, and
\(r\) is the rating.
Remember that we stated two things:
\(s = \lambda r\), and
\(s = Ar\).
Thus,
\(Ar = \lambda r\),
and we can interpret
\(\lambda\) as an eigenvalue, and
\(r\) as the corresponding eigenvector to the eigenvalue.
Using any numerical method we want, when can compute the eigenvectors and eigenvalues of \(A\). The eigenvector associated with the largest eigenvalue will have its elements correspond to the teams and be the ratings. When the ratings are sorted (the values of the eigenvector), then the ranking is produced.
5.1. NFL 2009
Let’s look at the whole NFL 2009 season. This data has scores, yards and turnovers. We will use scores to create the strength statistics.
[1]:
import pandas as pd
def get_nfl_2009():
return pd.read_csv('./nfl/2009.csv')
df = get_nfl_2009()
teams = sorted(list(set(df.t1) | set(df.t2)))
df
[1]:
t1 | t2 | s1 | s2 | yd1 | yd2 | to1 | to2 | home_team | week | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Steelers | Titans | 13 | 10 | 357 | 320 | 3 | 2.0 | Steelers | 1 |
1 | Broncos | Bengals | 12 | 7 | 302 | 307 | 0 | 2.0 | Bengals | 1 |
2 | Ravens | Chiefs | 38 | 24 | 501 | 188 | 1 | 0.0 | Ravens | 1 |
3 | Colts | Jaguars | 14 | 12 | 365 | 228 | 2 | 0.0 | Colts | 1 |
4 | Cowboys | Buccaneers | 34 | 21 | 462 | 450 | 0 | 0.0 | Buccaneers | 1 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
251 | Cowboys | Eagles | 24 | 0 | 474 | 228 | 1 | 1.0 | Cowboys | 17 |
252 | Chiefs | Broncos | 44 | 24 | 524 | 512 | 2 | 3.0 | Broncos | 17 |
253 | Ravens | Raiders | 21 | 13 | 330 | 325 | 0 | 2.0 | Raiders | 17 |
254 | Titans | Seahawks | 17 | 13 | 304 | 309 | 2 | 1.0 | Seahawks | 17 |
255 | Jets | Bengals | 37 | 0 | 320 | 72 | 0 | 3.0 | Jets | 17 |
256 rows × 10 columns
\(a_{ij}\) will actually be the total number of points scored by the i-th team on the j-th team during the whole season. These are the cummulative points.
[2]:
def get_cummulative_score(df, t1, t2, f1='s1', f2='s2'):
s1 = df[(df.t1 == t1) & (df.t2 == t2)][f1].sum()
s2 = df[(df.t1 == t2) & (df.t2 == t1)][f2].sum()
s = s1 + s2
return s
rscore_df = pd.DataFrame([[get_cummulative_score(df, t1, t2) if t1 != t2 else 0 for t2 in teams]
for t1 in teams], index=teams, columns=teams)
rscore_df
[2]:
49ers | Bears | Bengals | Bills | Broncos | Browns | Buccaneers | Cardinals | Chargers | Chiefs | ... | Raiders | Rams | Ravens | Redskins | Saints | Seahawks | Steelers | Texans | Titans | Vikings | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
49ers | 0 | 10 | 0 | 0 | 0 | 0 | 0 | 44 | 0 | 0 | ... | 0 | 63 | 0 | 0 | 0 | 40 | 0 | 21 | 27 | 24 |
Bears | 6 | 0 | 10 | 0 | 0 | 30 | 0 | 21 | 0 | 0 | ... | 0 | 17 | 7 | 0 | 0 | 25 | 17 | 0 | 0 | 46 |
Bengals | 0 | 45 | 0 | 0 | 7 | 39 | 0 | 0 | 24 | 17 | ... | 17 | 0 | 34 | 0 | 0 | 0 | 41 | 17 | 0 | 10 |
Bills | 0 | 0 | 0 | 0 | 0 | 3 | 33 | 0 | 0 | 16 | ... | 0 | 0 | 0 | 0 | 7 | 0 | 0 | 10 | 17 | 0 |
Broncos | 0 | 0 | 12 | 0 | 0 | 27 | 0 | 0 | 37 | 68 | ... | 42 | 0 | 7 | 17 | 0 | 0 | 10 | 0 | 0 | 0 |
Browns | 0 | 6 | 27 | 6 | 6 | 0 | 0 | 0 | 23 | 41 | ... | 23 | 0 | 3 | 0 | 0 | 0 | 27 | 0 | 0 | 20 |
Buccaneers | 0 | 0 | 0 | 20 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 13 | 27 | 24 | 0 | 0 | 0 | 0 |
Cardinals | 25 | 41 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 52 | 0 | 0 | 0 | 58 | 0 | 28 | 17 | 30 |
Chargers | 0 | 0 | 27 | 0 | 55 | 30 | 0 | 0 | 0 | 80 | ... | 48 | 0 | 26 | 23 | 0 | 0 | 28 | 0 | 42 | 0 |
Chiefs | 0 | 0 | 10 | 10 | 57 | 34 | 0 | 0 | 21 | 0 | ... | 26 | 0 | 24 | 14 | 0 | 0 | 27 | 0 | 0 | 0 |
Colts | 18 | 0 | 0 | 7 | 28 | 0 | 0 | 31 | 0 | 0 | ... | 0 | 42 | 17 | 0 | 0 | 34 | 0 | 55 | 58 | 0 |
Cowboys | 0 | 0 | 0 | 0 | 10 | 0 | 34 | 0 | 17 | 26 | ... | 24 | 0 | 0 | 24 | 24 | 38 | 0 | 0 | 0 | 0 |
Dolphins | 0 | 0 | 0 | 52 | 0 | 0 | 25 | 0 | 13 | 0 | ... | 0 | 0 | 0 | 0 | 34 | 0 | 24 | 20 | 24 | 0 |
Eagles | 27 | 24 | 0 | 0 | 30 | 0 | 33 | 0 | 23 | 34 | ... | 9 | 0 | 0 | 54 | 22 | 0 | 0 | 0 | 0 | 0 |
Falcons | 45 | 21 | 0 | 31 | 0 | 0 | 40 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 31 | 50 | 0 | 0 | 0 | 0 | 0 |
Giants | 0 | 0 | 0 | 0 | 6 | 0 | 24 | 17 | 20 | 27 | ... | 44 | 0 | 0 | 68 | 27 | 0 | 0 | 0 | 0 | 7 |
Jaguars | 3 | 0 | 0 | 18 | 0 | 17 | 0 | 17 | 0 | 24 | ... | 0 | 23 | 0 | 0 | 0 | 0 | 0 | 54 | 50 | 0 |
Jets | 0 | 0 | 37 | 32 | 0 | 0 | 26 | 0 | 0 | 0 | ... | 38 | 0 | 0 | 0 | 10 | 0 | 0 | 24 | 24 | 0 |
Lions | 6 | 47 | 13 | 0 | 0 | 38 | 0 | 24 | 0 | 0 | ... | 0 | 10 | 3 | 19 | 27 | 20 | 20 | 0 | 0 | 23 |
Packers | 30 | 42 | 24 | 0 | 0 | 31 | 28 | 33 | 0 | 0 | ... | 0 | 36 | 27 | 0 | 0 | 48 | 36 | 0 | 0 | 49 |
Panthers | 0 | 0 | 0 | 9 | 0 | 0 | 44 | 34 | 0 | 0 | ... | 0 | 0 | 0 | 20 | 43 | 0 | 0 | 0 | 0 | 26 |
Patriots | 0 | 0 | 0 | 42 | 17 | 0 | 35 | 0 | 0 | 0 | ... | 0 | 0 | 27 | 0 | 17 | 0 | 0 | 27 | 59 | 0 |
Raiders | 0 | 0 | 20 | 0 | 23 | 9 | 0 | 0 | 36 | 23 | ... | 0 | 0 | 13 | 13 | 0 | 0 | 27 | 6 | 0 | 0 |
Rams | 6 | 9 | 0 | 0 | 0 | 0 | 0 | 23 | 0 | 0 | ... | 0 | 0 | 0 | 7 | 23 | 17 | 0 | 13 | 7 | 10 |
Ravens | 0 | 31 | 21 | 0 | 30 | 50 | 0 | 0 | 31 | 38 | ... | 21 | 0 | 0 | 0 | 0 | 0 | 40 | 0 | 0 | 31 |
Redskins | 0 | 0 | 0 | 0 | 27 | 0 | 16 | 0 | 20 | 6 | ... | 34 | 9 | 0 | 0 | 30 | 0 | 0 | 0 | 0 | 0 |
Saints | 0 | 0 | 0 | 27 | 0 | 0 | 55 | 0 | 0 | 0 | ... | 0 | 28 | 0 | 33 | 0 | 0 | 0 | 0 | 0 | 0 |
Seahawks | 30 | 19 | 0 | 0 | 0 | 0 | 7 | 23 | 0 | 0 | ... | 0 | 55 | 0 | 0 | 0 | 0 | 0 | 7 | 13 | 9 |
Steelers | 0 | 14 | 32 | 0 | 28 | 33 | 0 | 0 | 38 | 24 | ... | 24 | 0 | 40 | 0 | 0 | 0 | 0 | 0 | 13 | 27 |
Texans | 24 | 0 | 28 | 31 | 0 | 0 | 0 | 21 | 0 | 0 | ... | 29 | 16 | 0 | 0 | 0 | 34 | 0 | 0 | 51 | 0 |
Titans | 34 | 0 | 0 | 41 | 0 | 0 | 0 | 20 | 17 | 0 | ... | 0 | 47 | 0 | 0 | 0 | 17 | 10 | 51 | 0 | 0 |
Vikings | 27 | 66 | 30 | 0 | 0 | 34 | 0 | 17 | 0 | 0 | ... | 0 | 38 | 33 | 0 | 0 | 35 | 17 | 0 | 0 | 0 |
32 rows × 32 columns
We then apply Laplace's rule of succession
.
[3]:
def get_strength(df, i, j):
s_ij = df.iloc[i].iloc[j]
s_ji = df.iloc[j].iloc[i]
s = (s_ij + 1) / (s_ij + s_ji + 2)
return s
sscore_df = pd.DataFrame([[get_strength(rscore_df, i, j) for j in range(len(teams))]
for i in range(len(teams))], index=teams, columns=teams)
sscore_df
[3]:
49ers | Bears | Bengals | Bills | Broncos | Browns | Buccaneers | Cardinals | Chargers | Chiefs | ... | Raiders | Rams | Ravens | Redskins | Saints | Seahawks | Steelers | Texans | Titans | Vikings | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
49ers | 0.500000 | 0.611111 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.633803 | 0.500000 | 0.500000 | ... | 0.500000 | 0.901408 | 0.500000 | 0.500000 | 0.500000 | 0.569444 | 0.500000 | 0.468085 | 0.444444 | 0.471698 |
Bears | 0.388889 | 0.500000 | 0.192982 | 0.500000 | 0.500000 | 0.815789 | 0.500000 | 0.343750 | 0.500000 | 0.500000 | ... | 0.500000 | 0.642857 | 0.200000 | 0.500000 | 0.500000 | 0.565217 | 0.545455 | 0.500000 | 0.500000 | 0.412281 |
Bengals | 0.500000 | 0.807018 | 0.500000 | 0.500000 | 0.380952 | 0.588235 | 0.500000 | 0.500000 | 0.471698 | 0.620690 | ... | 0.461538 | 0.500000 | 0.614035 | 0.500000 | 0.500000 | 0.500000 | 0.560000 | 0.382979 | 0.500000 | 0.261905 |
Bills | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.363636 | 0.618182 | 0.500000 | 0.500000 | 0.607143 | ... | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.222222 | 0.500000 | 0.500000 | 0.255814 | 0.300000 | 0.500000 |
Broncos | 0.500000 | 0.500000 | 0.619048 | 0.500000 | 0.500000 | 0.800000 | 0.500000 | 0.500000 | 0.404255 | 0.543307 | ... | 0.641791 | 0.500000 | 0.205128 | 0.391304 | 0.500000 | 0.500000 | 0.275000 | 0.500000 | 0.500000 | 0.500000 |
Browns | 0.500000 | 0.184211 | 0.411765 | 0.636364 | 0.200000 | 0.500000 | 0.500000 | 0.500000 | 0.436364 | 0.545455 | ... | 0.705882 | 0.500000 | 0.072727 | 0.500000 | 0.500000 | 0.500000 | 0.451613 | 0.500000 | 0.500000 | 0.375000 |
Buccaneers | 0.500000 | 0.500000 | 0.500000 | 0.381818 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | ... | 0.500000 | 0.500000 | 0.500000 | 0.451613 | 0.333333 | 0.757576 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Cardinals | 0.366197 | 0.656250 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | ... | 0.500000 | 0.688312 | 0.500000 | 0.500000 | 0.500000 | 0.710843 | 0.500000 | 0.568627 | 0.461538 | 0.632653 |
Chargers | 0.500000 | 0.500000 | 0.528302 | 0.500000 | 0.595745 | 0.563636 | 0.500000 | 0.500000 | 0.500000 | 0.786408 | ... | 0.569767 | 0.500000 | 0.457627 | 0.533333 | 0.500000 | 0.500000 | 0.426471 | 0.500000 | 0.704918 | 0.500000 |
Chiefs | 0.500000 | 0.500000 | 0.379310 | 0.392857 | 0.456693 | 0.454545 | 0.500000 | 0.500000 | 0.213592 | 0.500000 | ... | 0.529412 | 0.500000 | 0.390625 | 0.681818 | 0.500000 | 0.500000 | 0.528302 | 0.500000 | 0.500000 | 0.500000 |
Colts | 0.558824 | 0.500000 | 0.500000 | 0.205128 | 0.630435 | 0.500000 | 0.500000 | 0.744186 | 0.500000 | 0.500000 | ... | 0.500000 | 0.860000 | 0.529412 | 0.500000 | 0.500000 | 0.660377 | 0.500000 | 0.554455 | 0.686047 | 0.500000 |
Cowboys | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.379310 | 0.500000 | 0.614035 | 0.500000 | 0.461538 | 0.562500 | ... | 0.757576 | 0.500000 | 0.500000 | 0.781250 | 0.581395 | 0.684211 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Dolphins | 0.500000 | 0.500000 | 0.500000 | 0.557895 | 0.500000 | 0.500000 | 0.520000 | 0.500000 | 0.368421 | 0.500000 | ... | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.426829 | 0.500000 | 0.446429 | 0.428571 | 0.471698 | 0.500000 |
Eagles | 0.666667 | 0.543478 | 0.500000 | 0.500000 | 0.525424 | 0.500000 | 0.693878 | 0.500000 | 0.428571 | 0.700000 | ... | 0.416667 | 0.500000 | 0.500000 | 0.567010 | 0.319444 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Falcons | 0.807018 | 0.594595 | 0.500000 | 0.888889 | 0.500000 | 0.500000 | 0.594203 | 0.500000 | 0.500000 | 0.500000 | ... | 0.500000 | 0.500000 | 0.500000 | 0.640000 | 0.451327 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Giants | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.205882 | 0.500000 | 0.961538 | 0.418605 | 0.488372 | 0.622222 | ... | 0.849057 | 0.500000 | 0.500000 | 0.696970 | 0.363636 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.150943 |
Jaguars | 0.160000 | 0.500000 | 0.500000 | 0.542857 | 0.500000 | 0.428571 | 0.500000 | 0.360000 | 0.500000 | 0.531915 | ... | 0.500000 | 0.533333 | 0.500000 | 0.500000 | 0.500000 | 0.023256 | 0.500000 | 0.561224 | 0.515152 | 0.500000 |
Jets | 0.500000 | 0.500000 | 0.974359 | 0.523810 | 0.500000 | 0.500000 | 0.870968 | 0.500000 | 0.500000 | 0.500000 | ... | 0.975000 | 0.500000 | 0.500000 | 0.500000 | 0.305556 | 0.500000 | 0.500000 | 0.757576 | 0.581395 | 0.500000 |
Lions | 0.250000 | 0.358209 | 0.368421 | 0.500000 | 0.500000 | 0.506494 | 0.500000 | 0.438596 | 0.500000 | 0.500000 | ... | 0.500000 | 0.379310 | 0.075472 | 0.571429 | 0.378378 | 0.388889 | 0.420000 | 0.500000 | 0.500000 | 0.303797 |
Packers | 0.553571 | 0.589041 | 0.438596 | 0.500000 | 0.500000 | 0.888889 | 0.426471 | 0.809524 | 0.500000 | 0.500000 | ... | 0.500000 | 0.672727 | 0.651163 | 0.500000 | 0.500000 | 0.816667 | 0.493333 | 0.500000 | 0.500000 | 0.420168 |
Panthers | 0.500000 | 0.500000 | 0.500000 | 0.322581 | 0.500000 | 0.500000 | 0.616438 | 0.614035 | 0.500000 | 0.500000 | ... | 0.500000 | 0.500000 | 0.500000 | 0.538462 | 0.517647 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.771429 |
Patriots | 0.500000 | 0.500000 | 0.500000 | 0.551282 | 0.461538 | 0.500000 | 0.818182 | 0.500000 | 0.500000 | 0.500000 | ... | 0.500000 | 0.500000 | 0.560000 | 0.500000 | 0.315789 | 0.500000 | 0.500000 | 0.444444 | 0.983607 | 0.500000 |
Raiders | 0.500000 | 0.500000 | 0.538462 | 0.500000 | 0.358209 | 0.294118 | 0.500000 | 0.500000 | 0.430233 | 0.470588 | ... | 0.500000 | 0.500000 | 0.388889 | 0.285714 | 0.500000 | 0.500000 | 0.528302 | 0.189189 | 0.500000 | 0.500000 |
Rams | 0.098592 | 0.357143 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.311688 | 0.500000 | 0.500000 | ... | 0.500000 | 0.500000 | 0.500000 | 0.444444 | 0.452830 | 0.243243 | 0.500000 | 0.451613 | 0.142857 | 0.220000 |
Ravens | 0.500000 | 0.800000 | 0.385965 | 0.500000 | 0.794872 | 0.927273 | 0.500000 | 0.500000 | 0.542373 | 0.609375 | ... | 0.611111 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.484848 |
Redskins | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.608696 | 0.500000 | 0.548387 | 0.500000 | 0.466667 | 0.318182 | ... | 0.714286 | 0.555556 | 0.500000 | 0.500000 | 0.476923 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Saints | 0.500000 | 0.500000 | 0.500000 | 0.777778 | 0.500000 | 0.500000 | 0.666667 | 0.500000 | 0.500000 | 0.500000 | ... | 0.500000 | 0.547170 | 0.500000 | 0.523077 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Seahawks | 0.430556 | 0.434783 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.242424 | 0.289157 | 0.500000 | 0.500000 | ... | 0.500000 | 0.756757 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.186047 | 0.437500 | 0.217391 |
Steelers | 0.500000 | 0.454545 | 0.440000 | 0.500000 | 0.725000 | 0.548387 | 0.500000 | 0.500000 | 0.573529 | 0.471698 | ... | 0.471698 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.560000 | 0.608696 |
Texans | 0.531915 | 0.500000 | 0.617021 | 0.744186 | 0.500000 | 0.500000 | 0.500000 | 0.431373 | 0.500000 | 0.500000 | ... | 0.810811 | 0.548387 | 0.500000 | 0.500000 | 0.500000 | 0.813953 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Titans | 0.555556 | 0.500000 | 0.500000 | 0.700000 | 0.500000 | 0.500000 | 0.500000 | 0.538462 | 0.295082 | 0.500000 | ... | 0.500000 | 0.857143 | 0.500000 | 0.500000 | 0.500000 | 0.562500 | 0.440000 | 0.500000 | 0.500000 | 0.500000 |
Vikings | 0.528302 | 0.587719 | 0.738095 | 0.500000 | 0.500000 | 0.625000 | 0.500000 | 0.367347 | 0.500000 | 0.500000 | ... | 0.500000 | 0.780000 | 0.515152 | 0.500000 | 0.500000 | 0.782609 | 0.391304 | 0.500000 | 0.500000 | 0.500000 |
32 rows × 32 columns
Finally, we combat skew in the data.
[4]:
import numpy as np
def h(x):
h = 0.5 + ((np.sign(x - 0.5) * np.sqrt(np.abs(2 * x - 1))) / 2)
return h
X = sscore_df.applymap(h)
X
[4]:
49ers | Bears | Bengals | Bills | Broncos | Browns | Buccaneers | Cardinals | Chargers | Chiefs | ... | Raiders | Rams | Ravens | Redskins | Saints | Seahawks | Steelers | Texans | Titans | Vikings | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
49ers | 0.500000 | 0.735702 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.758653 | 0.500000 | 0.500000 | ... | 0.500000 | 0.948000 | 0.500000 | 0.500000 | 0.500000 | 0.686339 | 0.500000 | 0.373677 | 0.333333 | 0.381042 |
Bears | 0.264298 | 0.500000 | 0.108198 | 0.500000 | 0.500000 | 0.897360 | 0.500000 | 0.220492 | 0.500000 | 0.500000 | ... | 0.500000 | 0.767261 | 0.112702 | 0.500000 | 0.500000 | 0.680579 | 0.650756 | 0.500000 | 0.500000 | 0.290573 |
Bengals | 0.500000 | 0.891802 | 0.500000 | 0.500000 | 0.256025 | 0.710042 | 0.500000 | 0.500000 | 0.381042 | 0.745652 | ... | 0.361325 | 0.500000 | 0.738783 | 0.500000 | 0.500000 | 0.500000 | 0.673205 | 0.258110 | 0.500000 | 0.154967 |
Bills | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.238884 | 0.743086 | 0.500000 | 0.500000 | 0.731455 | ... | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.127322 | 0.500000 | 0.500000 | 0.150582 | 0.183772 | 0.500000 |
Broncos | 0.500000 | 0.500000 | 0.743975 | 0.500000 | 0.500000 | 0.887298 | 0.500000 | 0.500000 | 0.281203 | 0.647151 | ... | 0.766262 | 0.500000 | 0.116026 | 0.266874 | 0.500000 | 0.500000 | 0.164590 | 0.500000 | 0.500000 | 0.500000 |
Browns | 0.500000 | 0.102640 | 0.289958 | 0.761116 | 0.112702 | 0.500000 | 0.500000 | 0.500000 | 0.321623 | 0.650756 | ... | 0.820844 | 0.500000 | 0.037792 | 0.500000 | 0.500000 | 0.500000 | 0.344457 | 0.500000 | 0.500000 | 0.250000 |
Buccaneers | 0.500000 | 0.500000 | 0.500000 | 0.256914 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | ... | 0.500000 | 0.500000 | 0.500000 | 0.344457 | 0.211325 | 0.858870 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Cardinals | 0.241347 | 0.779508 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | ... | 0.500000 | 0.806848 | 0.500000 | 0.500000 | 0.500000 | 0.824687 | 0.500000 | 0.685240 | 0.361325 | 0.757539 |
Chargers | 0.500000 | 0.500000 | 0.618958 | 0.500000 | 0.718797 | 0.678377 | 0.500000 | 0.500000 | 0.500000 | 0.878423 | ... | 0.686772 | 0.500000 | 0.354444 | 0.629099 | 0.500000 | 0.500000 | 0.308259 | 0.500000 | 0.820092 | 0.500000 |
Chiefs | 0.500000 | 0.500000 | 0.254348 | 0.268545 | 0.352849 | 0.349244 | 0.500000 | 0.500000 | 0.121577 | 0.500000 | ... | 0.621268 | 0.500000 | 0.266146 | 0.801511 | 0.500000 | 0.500000 | 0.618958 | 0.500000 | 0.500000 | 0.500000 |
Colts | 0.671499 | 0.500000 | 0.500000 | 0.116026 | 0.755377 | 0.500000 | 0.500000 | 0.849418 | 0.500000 | 0.500000 | ... | 0.500000 | 0.924264 | 0.621268 | 0.500000 | 0.500000 | 0.783176 | 0.500000 | 0.665008 | 0.804997 | 0.500000 |
Cowboys | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.254348 | 0.500000 | 0.738783 | 0.500000 | 0.361325 | 0.676777 | ... | 0.858870 | 0.500000 | 0.500000 | 0.875000 | 0.701737 | 0.803488 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Dolphins | 0.500000 | 0.500000 | 0.500000 | 0.670139 | 0.500000 | 0.500000 | 0.600000 | 0.500000 | 0.243505 | 0.500000 | ... | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.308727 | 0.500000 | 0.336337 | 0.311018 | 0.381042 | 0.500000 |
Eagles | 0.788675 | 0.647442 | 0.500000 | 0.500000 | 0.612747 | 0.500000 | 0.811350 | 0.500000 | 0.311018 | 0.816228 | ... | 0.295876 | 0.500000 | 0.500000 | 0.683044 | 0.199537 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Falcons | 0.891802 | 0.717479 | 0.500000 | 0.940959 | 0.500000 | 0.500000 | 0.717029 | 0.500000 | 0.500000 | 0.500000 | ... | 0.500000 | 0.500000 | 0.500000 | 0.764575 | 0.343999 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Giants | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.116518 | 0.500000 | 0.980384 | 0.298263 | 0.423751 | 0.747207 | ... | 0.917766 | 0.500000 | 0.500000 | 0.813823 | 0.238884 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.082234 |
Jaguars | 0.087689 | 0.500000 | 0.500000 | 0.646385 | 0.500000 | 0.311018 | 0.500000 | 0.235425 | 0.500000 | 0.626323 | ... | 0.500000 | 0.629099 | 0.500000 | 0.500000 | 0.500000 | 0.011766 | 0.500000 | 0.674964 | 0.587039 | 0.500000 |
Jets | 0.500000 | 0.500000 | 0.987011 | 0.609109 | 0.500000 | 0.500000 | 0.930678 | 0.500000 | 0.500000 | 0.500000 | ... | 0.987340 | 0.500000 | 0.500000 | 0.500000 | 0.188195 | 0.500000 | 0.500000 | 0.858870 | 0.701737 | 0.500000 |
Lions | 0.146447 | 0.233738 | 0.243505 | 0.500000 | 0.500000 | 0.556980 | 0.500000 | 0.324781 | 0.500000 | 0.500000 | ... | 0.500000 | 0.254348 | 0.039279 | 0.688982 | 0.253402 | 0.264298 | 0.300000 | 0.500000 | 0.500000 | 0.186789 |
Packers | 0.663663 | 0.710999 | 0.324781 | 0.500000 | 0.500000 | 0.940959 | 0.308259 | 0.893398 | 0.500000 | 0.500000 | ... | 0.500000 | 0.793877 | 0.774921 | 0.500000 | 0.500000 | 0.897911 | 0.442265 | 0.500000 | 0.500000 | 0.300210 |
Panthers | 0.500000 | 0.500000 | 0.500000 | 0.202158 | 0.500000 | 0.500000 | 0.741287 | 0.738783 | 0.500000 | 0.500000 | ... | 0.500000 | 0.500000 | 0.500000 | 0.638675 | 0.593934 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.868394 |
Patriots | 0.500000 | 0.500000 | 0.500000 | 0.660128 | 0.361325 | 0.500000 | 0.898862 | 0.500000 | 0.500000 | 0.500000 | ... | 0.500000 | 0.500000 | 0.673205 | 0.500000 | 0.196512 | 0.500000 | 0.500000 | 0.333333 | 0.991735 | 0.500000 |
Raiders | 0.500000 | 0.500000 | 0.638675 | 0.500000 | 0.233738 | 0.179156 | 0.500000 | 0.500000 | 0.313228 | 0.378732 | ... | 0.500000 | 0.500000 | 0.264298 | 0.172673 | 0.500000 | 0.500000 | 0.618958 | 0.105785 | 0.500000 | 0.500000 |
Rams | 0.052000 | 0.232739 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.193152 | 0.500000 | 0.500000 | ... | 0.500000 | 0.500000 | 0.500000 | 0.333333 | 0.346426 | 0.141701 | 0.500000 | 0.344457 | 0.077423 | 0.125834 |
Ravens | 0.500000 | 0.887298 | 0.261217 | 0.500000 | 0.883974 | 0.962208 | 0.500000 | 0.500000 | 0.645556 | 0.733854 | ... | 0.735702 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.412961 |
Redskins | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.733126 | 0.500000 | 0.655543 | 0.500000 | 0.370901 | 0.198489 | ... | 0.827327 | 0.666667 | 0.500000 | 0.500000 | 0.392583 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Saints | 0.500000 | 0.500000 | 0.500000 | 0.872678 | 0.500000 | 0.500000 | 0.788675 | 0.500000 | 0.500000 | 0.500000 | ... | 0.500000 | 0.653574 | 0.500000 | 0.607417 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Seahawks | 0.313661 | 0.319421 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.141130 | 0.175313 | 0.500000 | 0.500000 | ... | 0.500000 | 0.858299 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.103797 | 0.323223 | 0.124095 |
Steelers | 0.500000 | 0.349244 | 0.326795 | 0.500000 | 0.835410 | 0.655543 | 0.500000 | 0.500000 | 0.691741 | 0.381042 | ... | 0.381042 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.673205 | 0.733126 |
Texans | 0.626323 | 0.500000 | 0.741890 | 0.849418 | 0.500000 | 0.500000 | 0.500000 | 0.314760 | 0.500000 | 0.500000 | ... | 0.894215 | 0.655543 | 0.500000 | 0.500000 | 0.500000 | 0.896203 | 0.500000 | 0.500000 | 0.500000 | 0.500000 |
Titans | 0.666667 | 0.500000 | 0.500000 | 0.816228 | 0.500000 | 0.500000 | 0.500000 | 0.638675 | 0.179908 | 0.500000 | ... | 0.500000 | 0.922577 | 0.500000 | 0.500000 | 0.500000 | 0.676777 | 0.326795 | 0.500000 | 0.500000 | 0.500000 |
Vikings | 0.618958 | 0.709427 | 0.845033 | 0.500000 | 0.500000 | 0.750000 | 0.500000 | 0.242461 | 0.500000 | 0.500000 | ... | 0.500000 | 0.874166 | 0.587039 | 0.500000 | 0.500000 | 0.875905 | 0.266874 | 0.500000 | 0.500000 | 0.500000 |
32 rows × 32 columns
5.2. Numpy
We will use numpy to find the eigenvalues and eigenvectors.
[5]:
e, E = np.linalg.eig(X)
[6]:
e
[6]:
array([1.58321633e+01+0.j , 2.22768644e-03+1.85772142j,
2.22768644e-03-1.85772142j, 3.39712442e-03+1.35674872j,
3.39712442e-03-1.35674872j, 1.00041396e-03+1.26017375j,
1.00041396e-03-1.26017375j, 1.04401936e-02+1.20532274j,
1.04401936e-02-1.20532274j, 4.22054558e-03+1.07142414j,
4.22054558e-03-1.07142414j, 7.62218544e-04+0.95584753j,
7.62218544e-04-0.95584753j, 1.50585060e-02+0.7822698j ,
1.50585060e-02-0.7822698j , 2.70582449e-03+0.72218668j,
2.70582449e-03-0.72218668j, 2.01788728e-03+0.63803178j,
2.01788728e-03-0.63803178j, 4.25439229e-03+0.57011899j,
4.25439229e-03-0.57011899j, 1.11927138e-02+0.4517283j ,
1.11927138e-02-0.4517283j , 7.65441825e-03+0.35245526j,
7.65441825e-03-0.35245526j, 1.15967256e-02+0.24209874j,
1.15967256e-02-0.24209874j, 3.16542655e-03+0.18988739j,
3.16542655e-03-0.18988739j, 2.97621199e-03+0.07044387j,
2.97621199e-03-0.07044387j, 2.49615168e-03+0.j ])
The sorted eigenvector shows that the Saints are at the top with the Rams at the bottom. The Saints won the Super Bowl during the 2009-2010 season.
[7]:
pd.Series(E[:,0], index=teams).sort_values(ascending=True)
[7]:
Saints -0.203355+0.000000j
Packers -0.201014+0.000000j
Patriots -0.197235+0.000000j
Chargers -0.197097+0.000000j
Colts -0.195922+0.000000j
Vikings -0.195730+0.000000j
Cowboys -0.195317+0.000000j
Jets -0.195166+0.000000j
Eagles -0.190664+0.000000j
Ravens -0.190316+0.000000j
Steelers -0.188673+0.000000j
Texans -0.188029+0.000000j
Falcons -0.183949+0.000000j
Cardinals -0.182012+0.000000j
49ers -0.179368+0.000000j
Broncos -0.178877+0.000000j
Bengals -0.177157+0.000000j
Panthers -0.173233+0.000000j
Titans -0.171839+0.000000j
Giants -0.171517+0.000000j
Dolphins -0.167714+0.000000j
Bears -0.165493+0.000000j
Redskins -0.163789+0.000000j
Bills -0.163556+0.000000j
Jaguars -0.162974+0.000000j
Chiefs -0.157590+0.000000j
Browns -0.157127+0.000000j
Seahawks -0.153406+0.000000j
Raiders -0.147552+0.000000j
Buccaneers -0.147396+0.000000j
Lions -0.144028+0.000000j
Rams -0.140011+0.000000j
dtype: complex128
5.3. Scikit-Learn
Here, we use Scikit-Learn to retrieve the eigenvalues and eigenvectors.
[8]:
from sklearn.decomposition import TruncatedSVD
svd = TruncatedSVD(n_components=2, n_iter=100, random_state=37)
svd.fit(X)
[8]:
TruncatedSVD(n_iter=100, random_state=37)
[9]:
svd.singular_values_
[9]:
array([16.16520004, 1.85991954])
Again, we see the Saints at the top.
[10]:
pd.Series(svd.components_[0,:], index=teams).sort_values(ascending=True)
[10]:
Saints 0.148945
Packers 0.151001
Patriots 0.154887
Chargers 0.155021
Colts 0.156045
Vikings 0.156115
Cowboys 0.156881
Jets 0.156972
Eagles 0.161209
Ravens 0.161649
Steelers 0.163317
Texans 0.163902
Falcons 0.167846
Cardinals 0.169756
49ers 0.172460
Broncos 0.172764
Bengals 0.174560
Panthers 0.178314
Titans 0.179604
Giants 0.180136
Dolphins 0.183847
Bears 0.186135
Redskins 0.187734
Bills 0.188043
Jaguars 0.188691
Chiefs 0.193845
Browns 0.194392
Seahawks 0.198091
Buccaneers 0.203681
Raiders 0.203764
Lions 0.207208
Rams 0.211215
dtype: float64
Here are the ratings side-by-side.
[11]:
pd.DataFrame({
'numpy': pd.Series(E[:,0], index=teams),
'scikit': pd.Series(svd.components_[0,:], index=teams)
})
[11]:
numpy | scikit | |
---|---|---|
49ers | -0.179368+0.000000j | 0.172460 |
Bears | -0.165493+0.000000j | 0.186135 |
Bengals | -0.177157+0.000000j | 0.174560 |
Bills | -0.163556+0.000000j | 0.188043 |
Broncos | -0.178877+0.000000j | 0.172764 |
Browns | -0.157127+0.000000j | 0.194392 |
Buccaneers | -0.147396+0.000000j | 0.203681 |
Cardinals | -0.182012+0.000000j | 0.169756 |
Chargers | -0.197097+0.000000j | 0.155021 |
Chiefs | -0.157590+0.000000j | 0.193845 |
Colts | -0.195922+0.000000j | 0.156045 |
Cowboys | -0.195317+0.000000j | 0.156881 |
Dolphins | -0.167714+0.000000j | 0.183847 |
Eagles | -0.190664+0.000000j | 0.161209 |
Falcons | -0.183949+0.000000j | 0.167846 |
Giants | -0.171517+0.000000j | 0.180136 |
Jaguars | -0.162974+0.000000j | 0.188691 |
Jets | -0.195166+0.000000j | 0.156972 |
Lions | -0.144028+0.000000j | 0.207208 |
Packers | -0.201014+0.000000j | 0.151001 |
Panthers | -0.173233+0.000000j | 0.178314 |
Patriots | -0.197235+0.000000j | 0.154887 |
Raiders | -0.147552+0.000000j | 0.203764 |
Rams | -0.140011+0.000000j | 0.211215 |
Ravens | -0.190316+0.000000j | 0.161649 |
Redskins | -0.163789+0.000000j | 0.187734 |
Saints | -0.203355+0.000000j | 0.148945 |
Seahawks | -0.153406+0.000000j | 0.198091 |
Steelers | -0.188673+0.000000j | 0.163317 |
Texans | -0.188029+0.000000j | 0.163902 |
Titans | -0.171839+0.000000j | 0.179604 |
Vikings | -0.195730+0.000000j | 0.156115 |
Here’s the ranking side-by-side. The only difference is with the Buccaneers and Raiders.
[12]:
ranking_df = pd.DataFrame({
'numpy': pd.Series(E[:,0], index=teams).sort_values().index,
'scikit': pd.Series(svd.components_[0,:], index=teams).sort_values().index
})
ranking_df['differs?'] = ranking_df.numpy != ranking_df.scikit
ranking_df
[12]:
numpy | scikit | differs? | |
---|---|---|---|
0 | Saints | Saints | False |
1 | Packers | Packers | False |
2 | Patriots | Patriots | False |
3 | Chargers | Chargers | False |
4 | Colts | Colts | False |
5 | Vikings | Vikings | False |
6 | Cowboys | Cowboys | False |
7 | Jets | Jets | False |
8 | Eagles | Eagles | False |
9 | Ravens | Ravens | False |
10 | Steelers | Steelers | False |
11 | Texans | Texans | False |
12 | Falcons | Falcons | False |
13 | Cardinals | Cardinals | False |
14 | 49ers | 49ers | False |
15 | Broncos | Broncos | False |
16 | Bengals | Bengals | False |
17 | Panthers | Panthers | False |
18 | Titans | Titans | False |
19 | Giants | Giants | False |
20 | Dolphins | Dolphins | False |
21 | Bears | Bears | False |
22 | Redskins | Redskins | False |
23 | Bills | Bills | False |
24 | Jaguars | Jaguars | False |
25 | Chiefs | Chiefs | False |
26 | Browns | Browns | False |
27 | Seahawks | Seahawks | False |
28 | Raiders | Buccaneers | True |
29 | Buccaneers | Raiders | True |
30 | Lions | Lions | False |
31 | Rams | Rams | False |
5.4. Ranking by yards
Let’s use yardage gains instead.
[13]:
rscore_df = pd.DataFrame([[get_cummulative_score(df, t1, t2, 'yd1', 'yd2') if t1 != t2 else 0 for t2 in teams]
for t1 in teams], index=teams, columns=teams)
sscore_df = pd.DataFrame([[get_strength(rscore_df, i, j) for j in range(len(teams))]
for i in range(len(teams))], index=teams, columns=teams)
X = sscore_df.applymap(h)
e, E = np.linalg.eig(X)
svd = TruncatedSVD(n_components=2, n_iter=100, random_state=37)
svd.fit(X)
ranking_df = pd.DataFrame({
'numpy': pd.Series(E[:,0], index=teams).sort_values().index,
'scikit': pd.Series(svd.components_[0,:], index=teams).sort_values().index
})
ranking_df['differs?'] = ranking_df.numpy != ranking_df.scikit
ranking_df
[13]:
numpy | scikit | differs? | |
---|---|---|---|
0 | Browns | Packers | True |
1 | Buccaneers | Cowboys | True |
2 | Raiders | Texans | True |
3 | Lions | Jets | True |
4 | Rams | Steelers | True |
5 | Chiefs | Eagles | True |
6 | Bills | Patriots | True |
7 | 49ers | Vikings | True |
8 | Seahawks | Saints | True |
9 | Falcons | Ravens | True |
10 | Bears | Giants | True |
11 | Dolphins | Chargers | True |
12 | Jaguars | Colts | True |
13 | Cardinals | Panthers | True |
14 | Titans | Broncos | True |
15 | Redskins | Bengals | True |
16 | Bengals | Redskins | True |
17 | Broncos | Titans | True |
18 | Panthers | Cardinals | True |
19 | Colts | Jaguars | True |
20 | Chargers | Dolphins | True |
21 | Giants | Bears | True |
22 | Ravens | Falcons | True |
23 | Saints | Seahawks | True |
24 | Vikings | 49ers | True |
25 | Patriots | Bills | True |
26 | Eagles | Chiefs | True |
27 | Steelers | Rams | True |
28 | Jets | Lions | True |
29 | Texans | Raiders | True |
30 | Cowboys | Buccaneers | True |
31 | Packers | Browns | True |
5.5. Turnovers
Let’s rank the teams by turnovers. It’s interesting that we can also rank teams to see who’s the worst.
[14]:
rscore_df = pd.DataFrame([[get_cummulative_score(df, t1, t2, 'to1', 'to2') if t1 != t2 else 0 for t2 in teams]
for t1 in teams], index=teams, columns=teams)
sscore_df = pd.DataFrame([[get_strength(rscore_df, i, j) for j in range(len(teams))]
for i in range(len(teams))], index=teams, columns=teams)
X = sscore_df.applymap(h)
e, E = np.linalg.eig(X)
svd = TruncatedSVD(n_components=2, n_iter=100, random_state=37)
svd.fit(X)
ranking_df = pd.DataFrame({
'numpy': pd.Series(E[:,0], index=teams).sort_values().index,
'scikit': pd.Series(svd.components_[0,:], index=teams).sort_values().index
})
ranking_df['differs?'] = ranking_df.numpy != ranking_df.scikit
ranking_df
[14]:
numpy | scikit | differs? | |
---|---|---|---|
0 | Lions | Lions | False |
1 | Raiders | Raiders | False |
2 | Rams | Rams | False |
3 | Browns | Browns | False |
4 | Giants | Giants | False |
5 | Seahawks | Seahawks | False |
6 | Dolphins | Dolphins | False |
7 | Steelers | Steelers | False |
8 | Buccaneers | Buccaneers | False |
9 | Titans | Titans | False |
10 | Redskins | Redskins | False |
11 | Jaguars | Jaguars | False |
12 | Bengals | Bengals | False |
13 | Bills | Bills | False |
14 | Bears | Bears | False |
15 | Texans | Texans | False |
16 | Chargers | Chargers | False |
17 | 49ers | 49ers | False |
18 | Cardinals | Cardinals | False |
19 | Colts | Colts | False |
20 | Saints | Saints | False |
21 | Cowboys | Cowboys | False |
22 | Falcons | Falcons | False |
23 | Jets | Jets | False |
24 | Broncos | Broncos | False |
25 | Panthers | Panthers | False |
26 | Vikings | Eagles | True |
27 | Eagles | Vikings | True |
28 | Ravens | Ravens | False |
29 | Chiefs | Chiefs | False |
30 | Patriots | Patriots | False |
31 | Packers | Packers | False |