Building a Worldloppet Recommender App

Michael Caballero
Posted on May 21, 2018

Worldloppet brings the global XC skiing community together

Every ski season, 20 nations showcase the best cross country (XC) skiing that the world has to offer. Tourists from all over the planet participate in this global series. As the organizers of this series highlight, Worldloppet is for everybody! However, one potential entry barrier is the uncertainty of "race fit." While Worldloppet is for everyone, elite skiers can be in attendance. It can be less than ideal to travel across the globe and participate in a race that is above (or below) your skill level.

After all…

Matching racers with host countries can be a serendipitous and enjoyable international experience. So, I designed and constructed a recommendation engine to match an individual's preferences to FIS Worldloppet races. Then I deployed this model as a web-app to help skiers find a race for the 2018/19 season. Read on to learn more!

Scraping race data

My first objective was to extract data on the Worldloppet races. Race results are published, so I extracted the past 5 years of race results data using Scrapy. This was done anonymously as racer names were not extracted - only the race time and skier nationality. In total, over 600,000 race results were gathered.

Several features could be engineered from this data despite scraping only a few variables. For example, I used regular expressions to identify the host country from the race name. This could be compared to the racer’s nationality to get an idea of how many skiers were tourists for a given race or how much a race has grown in popularity. 

Exploring the number of tourists as a function of number of skiers by Worldloppet race from the past 5 years. Axes scaled by square root transformation.


Given the racer’s finish time and the race distance extracted from that page, a race speed can be calculated. A limitation of this calculation is that it does not account for why these speeds differ. For example, paces could be slower because the course is particularly challenging with major elevation gains. Conversely, “faster” races could just be flatter. Nevertheless, there appears to be a distribution of median race speed by host country:

Using scraped data to examine median race speed for each Worldloppet race (Classic XC style).

Building a recommendation engine using KNN

I envisioned the following scenario: given my own personal preferences for race distance, race speed, and how many racers I wanted to ski with, which Worldloppet race would be a good fit for me?

This problem can be solved using a KNN classification approach. I could compare my preferences to those which have already been recorded within the hundreds of thousands of observations (race distance, race speed, number of racers) from the scraping portion of this project.

The next step requires finding consensus of which race (by host country) was a good fit by finding the most similar data-points to my preferences. 

The number of neighbors I selected for the model was determined using a grid search and 10-fold cross validation. The subset of classic skiers was extraordinarily accurate using this model with a minuscule misclassification rate of 0.001 to identify the host country. Classifying skate skiers represented a more challenging problem as the misclassification rate for the host country was (0.21). This less accurate match suggests that there are more skate skiing results with similar race distances/speeds than the classic races.

Deploying the app

Coming to this realization was rewarding, but I wanted to share it with the broader XC skiing community. So I reimplemented the tuned KNN model in R and deployed it as a web-app using R shiny. You can find the application here. The app asks for your preferred XC style, race distance, preferred race speed, and number of skiers you'd like to race with. Then, using the KNN model described above, a host country will be recommended. Popups on the host country markers have a link to that race's website. 

One area for additional development of the model is to factor in the difficulty of a race. What is the elevation of the race? What is the total elevation gain? Do these characteristics affect race speed? Another consideration is how tourists are defined. My EDA defined tourists in a binary fashion. It would be interesting to consider a weighted value based on distance traveled. In other words, which races draw tourists from which countries? These insights and the ones derived from building the app could help Worldloppet personalize marketing strategies to participants by suggesting new races tailored to their preferences.


The Worldloppet series is a fantastic way to experience the best XC skiing that the world has to offer. I built a KNN-based recommendation engine for Worldloppet races and deployed it as a web app.  I gathered data to build this model by scraping race results from the Worldloppet website and performed feature engineering. I hope that this app will make new suggestions for skiers and will enrich their XC skiing experience.

Posted by Worldloppet on Tuesday, October 17, 2017

About Author

Michael Caballero

Michael Caballero

Michael Caballero is a Data Science Fellow at NYCDSA who loves tackling interdisciplinary challenges. He has deployed multiple interactive web apps incorporating data analysis, visualization, and recommender systems. Michael attributes his award winning communication skills to his time...
View all posts by Michael Caballero >

Leave a Comment

No comments found.

View Posts by Categories

Our Recent Popular Posts

View Posts by Tags

#python #trainwithnycdsa 2019 airbnb Alex Baransky alumni Alumni Interview Alumni Reviews Alumni Spotlight alumni story Alumnus API Application artist aws beautiful soup Best Bootcamp Best Data Science 2019 Best Data Science Bootcamp Best Data Science Bootcamp 2020 Best Ranked Big Data Book Launch Book-Signing bootcamp Bootcamp Alumni Bootcamp Prep Bundles California Cancer Research capstone Career Career Day citibike clustering Coding Course Demo Course Report D3.js data Data Analyst data science Data Science Academy Data Science Bootcamp Data science jobs Data Science Reviews Data Scientist Data Scientist Jobs data visualization Deep Learning Demo Day Discount dplyr employer networking feature engineering Finance Financial Data Science Flask gbm Get Hired ggplot2 googleVis Hadoop higgs boson Hiring hiring partner events Hiring Partners Industry Experts Instructor Blog Instructor Interview Job Job Placement Jobs Jon Krohn JP Morgan Chase Kaggle Kickstarter lasso regression Lead Data Scienctist Lead Data Scientist leaflet linear regression Logistic Regression machine learning Maps matplotlib Medical Research Meet the team meetup Networking neural network Neural networks New Courses nlp NYC NYC Data Science nyc data science academy NYC Open Data NYCDSA NYCDSA Alumni Online Online Bootcamp Open Data painter pandas Part-time Portfolio Development prediction Prework Programming PwC python python machine learning python scrapy python web scraping python webscraping Python Workshop R R language R Programming R Shiny r studio R Visualization R Workshop R-bloggers random forest Ranking recommendation recommendation system regression Remote remote data science bootcamp Scrapy scrapy visualization seaborn Selenium sentiment analysis Shiny Shiny Dashboard Spark Special Special Summer Sports statistics streaming Student Interview Student Showcase SVM Switchup Tableau team TensorFlow Testimonial tf-idf Top Data Science Bootcamp twitter visualization web scraping Weekend Course What to expect word cloud word2vec XGBoost yelp