Zwift Race Recommendation using simple machine learning

Chang Xiao
6 min readOct 31, 2022
Photo by Markus Spiske on Unsplash

Zwift racing is one of the coolest aspects of the virtual cycling platform. It has been growing both from a grassroots level as well as officially (UCI e-sports worlds, etc). However, it is also one of the most heated discussion areas as many complaints about the current watts-per-kilogram (WKG) category system.

The idea of using machine learning to enhance the racing experience has been attempted before. For example, the ZRace app tries to predict a racer’s placement in a race given that racer’s profile (power numbers, HR, etc).

However, I believe the key to applying machine learning to Zwift is more of an unsupervised learning problem, specifically the question:

How do we match the races to a user that optimizes his/her race experience

In other words, how do we recommend races to users that they will enjoy?

Our Hypothesis

We assume that a rider would “enjoy” a race if they have placed high on the result in whatever category they raced in. We then can assign a “rating” based on their result in their perspective categories. For example:

  • Top 3 (podium) — rating = 5
  • Top 10% (outside of top 3) — rating = 4
  • Top 25% — rating = 3
  • Top 50% — rating = 2
  • 50% and below — rating = 1

The ranking percentile is important since some races may have 10 riders and some may have more than 200.

Our Machine Learning Pipeline

1. We collected my own racing data from Zwiftpower.com and generated implicit ratings for the races I participated in.

2. We also collected historical racing data from other racers that participated in the same races as me and generated implicit ratings based on their performance.

3. The dataset is fed into a KNN model with a grid search for the best model parameters using the Python Surprise library.

4. We built a method to generate the top rating predictions for a user to provide recommendations for the event/race courses they might do well.

5. We built a method to find “similar riders” to check if they are reasonable for potential “matchmaking”

Testing the model

For the model testing, we looked at traditional metrics for model accuracies such as RSME, and MAE. However, we also checked individual users for a sanity test to see if the recommendations made sense.

Rating prediction

We first tested what kind of events the algorithm will predict a user will like e.g. the user would rate these events very high (4 to 5)

I used my racing profile as the sample to test.

Race profile on Zwiftpower

I have raced on Zwift 37 times according to Zwiftpower, I have a decent racing record with a number of podium finishes. I have raced on all types of courses: Flat e.g. Crit City, London Classique; Punchy: e.g. Innsbruck ring, Perimeter loop (New York) and Mountainous: e.g. Mountain Route, Road to Sky.

I would summarize myself as a punchy rider who does well on routes with sub-5-minute climbs. My best race course is probably the Innsbruck ring.

Based on the implicit ratings from my racing records, I have an average rating of 3.67. This means any race prediction above this rating can be recommended to me.

The top races/courses recommended to me were:

  • Crit City Race — The Bell lap (7 occurrences)
  • 3R Watopia Flat Sprint Race — 1 Lap (7 occurrences)
  • Crit City Race — Downtown Dolphin (6 occurrences)
  • 3R Racing — Innsbruck Ring ( 6 occurrences)
  • Various Races (sprint races to multi-lap races) — London Classique (5 occurrences)

There were other top predictions such as race courses that included Road to Sky, Keith Hill after party, and Tempus Fugit Time Trial.

The recommendation was both good and somewhat surprising. I have only raced Crit City — Downtown Dolphin once (albeit a winning one). The most surprising was that Tempus Fugit Time Trial was recommended 3 times but I have never done a TT race on this course before since I am a lightweight rider who doesn’t do well on flat time trials.

The initial test shows the system does capture my racing preference and recommends to me races/courses that I can do well at.

Finding Similar Riders

We can also use the algorithm to find similar riders from the dataset using the KNN algorithm, this has many interesting applications including race matchmaking.

Again I used my profile to test finding “similar riders”, the result was interesting as well.

Similar rider 1
The first rider who matched with me had done two of the same races as me. His result in the 2 races was below mine.

Rider 1
My Record

Similar rider 2
The second rider was someone I remember from the races we did together. Our results at the races were very close.

Rider 2
My Record

Other similar riders were less interesting as the similarity score decreased. This is expected from my limited racing history (37) as well as the overall dataset we had for testing.

Initial Observations

There were some interesting takeaways from the initial testing:

  • Race recommendations (predictions) were positive, I was recommended for race courses that I would do well at as well as others I wouldn’t think about racing often.
  • Finding similar riders did not perform as well as I had expected, this is mostly due to the lack of racing history from me as well as the limited dataset.
  • It’s possible to build a recommendation system with heuristic rules such as common races participated by riders, and race courses where riders have placed well. However, it will run into the risk of a closed feedback loop (echo chamber).

Application of the recommendation system

Recommend users to follow
Off the bat, this can be used to suggest other riders follow on Zwift. These will be riders that performed well on similar races as you.

User follow screen

Recommend similar races
We can use our rating prediction for a user and find upcoming races/courses that are similar to the past races the user has done well at.

Race recommendation

About me

I am an avid cyclist who enjoys riding outside or on Zwift. I am also a technologist and data science hobbyist. I have been interested in improving the racing experience for fellow Zwifters using Machine Learning techniques.

The purpose of the blog post is purely for research and personal interest.

--

--

Chang Xiao

Starter, dev, digital consultant, cyclist, tennis player. Currently focused on data science and specifically recommendation systems.