Friday, January 30, 2015

Strength of Schedule & Adjusted Statistics (Part 3)

In this previous post, I described how to calculate a "Strength of Schedule" measure for an arbitrary statistic and one way you might apply it to create an "adjusted" statistic:

`S_"adj"(T) = (S(T))/(SoS(T,S))`

This adjusted statistic is a way of normalizing statistics between teams when they have played different opponents.

One shortcoming of this approach is that the Strength of Schedule is itself based upon the unadjusted statistic:

`SoS(T,S) = (1/(n*m)) sum_(i="opponents"(T))^n sum_(j="opponents"(i))^m (j ne T) S(j)`

So to some extent this measure is biased by the quality of a team's opponents' opponents' opponents (if you can follow that!).  This bias may not be significant -- certainly by the middle of the season, the third-level opponents for a given team is a pretty big set, so there's going to be overlap between most teams.  But each team's opponents will be dominated by their conference teams, and there are sizable differences in strength between conferences, so it may be significant.

The obvious way to eliminate this bias is to use the adjusted statistic in the SoS calculation.  The whole purpose of the adjusted statistic is to normalize away these biases.

`SoS(T,S) = (1/(n*m)) sum_(i="opponents"(T))^n sum_(j="opponents"(i))^m (j ne T) S_"adj"(j)`

However, we've now created a circular definition!  The adjusted statistic for a team depends upon it's opponents' opponents adjusted statistic -- and their adjusted statistic depends upon other teams, and so on.

But just because the definition is circular doesn't mean we can't compute its value.  One approach to do this is to guess some initial value for the adjusted statistic (say, the unadjusted value) and then recalculate all the adjusted statistics.  The values will change and then we can repeat until we converge on an answer.

NOTE: A system of non-linear equations is not guaranteed to have a solution.  For this and other reasons, the iterative approach described here is not guaranteed to converge for every system.  In this case, I believe that the solution will converge if the system has "full support", which for NCAA basketball should be true after about 500 games.  Testing seems to bear this out, because it works for me for data from the past 5 seasons, but I haven't proven that it converges.  It also turns out that the normalization step shown below isn't necessary for convergence, but I'm leaving it in below because the example doesn't work otherwise.
Let's take a look at how this works.  For this experiment, we have a small league of three teams.  They've all played each other once, and here are their unadjusted statistics for 3 point shooting:

Team Unadj

Now we will calculate the Strength of Schedule for each team.  Since each team has played each other once, their opponents' opponents are each of the other two teams.  (I'll wait while you confirm that.)  We'll use the Unadjusted statistic as our first guess for the Adjusted statistic, so the SoS is just the average of the other two teams.

Team UnadjSoS(1)

The Adjusted Statistic is then the Unadjusted Statistic divided by the SoS.

Team UnadjSoS(1)Adj(1)

Finally, we take the Adjusted Statistic and normalize it so that it sums to one to create the Normalized Adjusted Statistic:


Now let's repeat that calculation again for a second iteration.


The Normalized Adjusted Statistics still changed a little bit, so let's do a third iteration.


Still a little bit of change, so we do another iteration.


And voila!  The Normalized Adjusted Statistics (and the SoS) have converged (at least to two decimal places).  And a good thing, too, because that table was getting very wide.  If you compare the adjusted statistics to the unadjusted statistics, you see that Blue is a much better 3 point shooting team than the unadjusted statistic shows, Gold is slightly worse, and Silver slightly better.

So there you have it -- a method for adjusting a non-symmetric statistic to account for strength of schedule, and a way to compute it.  In the next post, I'll share some thoughts on how to create an efficient implementation of this method.

No comments:

Post a Comment