I’ve been applying some data analysis to gain an edge in fantasy hockey leagues. Part 1 of this series explained how I managed to get each team’s performance data into Python so I can work with it. In this post, we’ll have a look at some of the useful analyses I’ve cooked up over the past few years.
Though I made it sound like my fantasy hockey data analysis started in Python, that’s not exactly the case. What I’m sharing here is the third evolution of my analysis. What started as static records in spreadsheets morphed into dynamic spreadsheet calculators. This latest shift into code-based analysis has proved to be revolutionary in terms of both automation and flexibility. If you’re interested in doing any of this for your own fantasy sports league, I invite you to check out the Jupyter Notebook companion to this piece. It has everything you need to run the analysis for yourself. I’ve intentionally avoided hard-coding parameters, so it should be easy to adapt to your own head-to-head league.
The Round Robin
In Head-to-Head (H2H) fantasy sports, you might only be matched against a particular team once all season. If that’s the case, how can you know how your team will stack up? Early in the season, it’s important to recognize that the league standings are heavily influenced by the quality of a team’s matchup competition. Even a month into the season (20% of the matches played), it can be difficult to know if your team is a contender or a pretender. This stems from the fact that you’ve only tested your lineup against a fraction of the other teams – your sample size is too small.
To address this, I want to know how a team performs against every other team each week. This dramatically increases the sample size, and allows a full picture of team strength after only a few weeks. Those familiar with tournaments of any kind will know that a round robin is a stage where each team plays all the other teams in the tournament. I’m using the same idea here.
In my previous post, I showed how to import into Python a table showing each team’s performance in each category for a week. Once in Python, I can calculate what I need: the week’s round robin results (the round robin results for Week 1 are shown here). There are twelve teams in the league, so each team gets eleven round robin matchups each week, and the table shows their respective records. You can find the details of how I did it in the Jupyter Notebook.
I don’t think there’s a doubt that the round robin provides great insight into team performances, but is that view any different? Let’s compare the conventional measure of a team’s strength (their H2H points – two for a win, one for a tie) to the round robin points. I created plots of each team’s accumulation of points over the first three weeks of the season.
The plot shows the H2H point system is having trouble: after Week 3, teams’ point totals are extremely quantized (limited to one of seven point totals), which makes it hard to differentiate the strength of teams. In addition, half the plot lines are not visible, obscured beneath other teams’ plots. To contrast this situation, look at the plot for the round robin point system, where quantization is not such an issue (teams can have 67 different point totals).
Look closely at the curves for Tyler’s Tilers (grey lines). According to the H2H points system, there are only two teams who are worse than the Tilers (it’s impossible to tell this from the plot, by the way!). Given the situation, Tyler might feel the need to make some roster adjustments. But hold on… according to the round robin points, Tyler’s team is the strongest in the league. It turns out that Tyler’s Tilers were up against some of the best teams in the league for that first part of the season, so his H2H point total was depressed.
After Tyler’s loss in Week 3, he waived Brandon Dubinsky (ranked 9th best player in our league) to pick up free agent Stephen Johns (who? ranked 314th). It’s hard to understand why he would make that move, but my guess is that he felt that he needed to adjust his team after a 1-2-0 start. If he had known his ranking in the round robin point system, I wonder if he still would have waived Dubinsky?
We have the machinery to crank out round robin analyses each week. Accumulate those data to build up a decent sample of results for every possible matchup. I’m always interested to see 1) which team is best, and then 2) which teams have the best outcomes against that best team. The round robin calculations give a robust indication of which teams are best, and I use it to generate a table that shows how a team performs against all other teams.
The Rating System
Growing up, I played a lot of EA Sports NHL99 on my N64. It was light-years ahead of Ice Hockey or Blades of Steel on the old NES, but doesn’t really hold up compared to the latest releases. If you ever played NHL99 (or any other sports video game since), you probably noticed that every team is given a rating. The rating is a number out of a hundred that lets you know how good that team is compared to other teams. Aside from this overall rating, the teams are often given sub-ratings in other categories: maybe offence, defence, goaltending, or others. They want to provide some insight about the team you choose to play with.
I want to know how the teams in my league rate. I’m not so interested in the overall rating (I think the round robin system gives good insight already) — I’m interested in how the teams rate in each of the categories. What are each team’s strengths or weaknesses? What makes the best teams so good? To get this insight, I’m going to use the same approach as those hockey video games.
To calculate a category rating for a team, I’m going to compare a team’s average performance to the average performances of the other teams. The rating in a category will range from 10 (the worst-performing team) to 100 (the best-performing team), and all the other teams will fall somewhere in between. If you’re into equations, here’s how I’ll do it:
Remember calculating the teams’ mean performance in each category in Part I? It’s a straight-forward transformation to turn a table of mean performance into a table of ratings using this formula. Now I could look at a table of ratings, but what’s the fun in that? Let’s visualize the ratings.
Using the Performance Profiles
The character of each team is summarized in these charts. Notice how some teams are built to be competitive in every category (Newfie Rockers, for example), but others excel in certain categories at the expense of performance in the others (see Chotchmahoneless). Interestingly, the top teams in the league (RyansNOTsoRandomTeam, Don’t Toews me Bro, Happy’s Hustlers) found success by using both of these approaches. I expected that one of these would yield better results than the other, but this quick look doesn’t seem to support that. A more thorough investigation might be more enlightening, but I won’t pursue that right now.
The rating charts allow you to compare the performance profile of two teams at a glance. You can quickly see which categories will be most contested in a matchup. I use them to inform which roster moves might give me the best chance of winning each week. As an example, let’s imagine my team (The Gallows Pole) is meeting RyansNOTsoRandomTeam next week. Ryan is almost guaranteed to win blocks and hits (Blk, Hits), and is also likely to win plus/minus (+/-) categories. I’m okay with this though, because I have a real shot at winning the goalie categories (SV%, W), and the goals and assists (G,A) categories. Knowing the teams’ performance profiles, I can make roster moves (moving players in and out of my lineup, acquiring free agent players, or trading players) that improve my chances of winning G and A, while ignoring that move’s effects on the other categories. I could afford to sacrifice a few assists in exchange for a couple extra goals, so I’d consider that when I set my lineup for the week. Ryan’s team is the best performer in the league, but I’ve matched up fairly well against it. In fact, only one team had more success against his team this season (as measured by the round robin). It’s something I attribute, in part, to my matchup preparation.
These profiles are very useful when looking for potential trade partners. First step is deciding how to improve your team. The performance profiles show you where (and to what degree) your strengths and weaknesses are. Consider Happy’s Hustlers: absolute worst rating in both goals and assists. Happy is so far behind in those categories that becoming competitive is essentially hopeless. On the other hand, +/- and SV% could be improved to make the team more competitive in those categories. Once you’ve decided how to improve the team, the charts are used again to identify which teams could provide that improvement. Their performance profile will help to understand what you might offer to reach a trade agreement.
Bringing it Home
As I mentioned before, all of this is available in a Jupyter Notebook so you can try it for yourself. The parameters aren’t hard-coded (for the most part), so it should be easy to adapt to your own head-to-head league.
I’d love to hear about how you’ve done analysis like this to gain an advantage in your H2H fantasy sports league. Leave a comment to start a conversation.