<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Data-Science on Jack Ibsen</title><link>https://198ac40d.ibsen.pages.dev/tags/data-science/</link><description>Recent content in Data-Science on Jack Ibsen</description><generator>Hugo -- gohugo.io</generator><language>en-CA</language><copyright>Jack Ibsen</copyright><lastBuildDate>Tue, 18 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://198ac40d.ibsen.pages.dev/tags/data-science/index.xml" rel="self" type="application/rss+xml"/><item><title>xMargin: Expected Point Margin Model for Curling</title><link>https://198ac40d.ibsen.pages.dev/articles/xmargin/</link><pubDate>Tue, 18 Aug 2026 00:00:00 +0000</pubDate><guid>https://198ac40d.ibsen.pages.dev/articles/xmargin/</guid><description>Source code for this project is available on GitHub
Introduction In curling, the traditional metrics that are used to determine a team’s performance include their hammer efficiency, ability to achieve and prevent steals, the number of big ends scored or given up, and shooting percentages [1]. On their own, when compared to the mean, these metrics can give a general overview of performance. What these metrics do not determine is whether the scoreboard and performance align.</description><content:encoded><![CDATA[</section>
<section>
<p><em>Source code for this project is available on <a href="https://github.com/jmi06/xMargin">GitHub</a></em></p>
<h2 id="introduction">Introduction</h2>
<p>In curling, the traditional metrics that are used to determine a team’s performance include their hammer efficiency, ability to achieve and prevent steals, the number of big ends scored or given up, and shooting percentages [1]. On their own, when compared to the mean, these metrics can give a general overview of performance. What these metrics do not determine is whether the scoreboard and performance align. Consequently, spectators, coaches, and players are unable to compare a team&rsquo;s performance to the result they achieved.</p>
<p>A team dominant in every performance metric could find themselves in a tight game, whereas two opponents with identical shooting percentages could end up with a large point differential due to variability in ice conditions. This article introduces \(xMargin\), a model that predicts a curling team’s expected point margin by analyzing performance differentials between two competing teams after each end. Comparing a team’s \(xMargin\) to the actual point margin demonstrates the influence of variability on the game’s outcome and isolates a team’s performance from the result.</p>
<h2 id="background">Background</h2>
<p>Soccer uses a metric known as xG (expected goals) to predict what the score should be based on the offensive performance of both the playing teams. xG uses historical data of similar shot attempts to predict how likely a shot is to result in a goal. If a player takes a shot from a scenario that resulted in a goal 60% of the time, their xG would be 0.6. The xG values of each shot are summed to determine the expected number of goals during a game. The xG metric is used to evaluate a team’s overall offensive performance, looking past the scoreline and taking note of opportunities created [2]. A very similar model has been used in ice hockey, to evaluate the same concept [3].</p>
<p>In curling, points are not scored on individual shots, rather after an end is played. Individual end performances could be analyzed, and the expected result of each end summed to find what the final score should be, similar to xG. Most performance metrics used in curling such as hammer efficiency and steal defense look at the game as a whole, thus can not be used to determine a team’s performance in an end. Curling does have one metric that changes after each shot is thrown, shot rating percentages. After each shot is thrown, it is given a rating between zero and four. A shot rated four indicates it was perfectly made, where a zero indicates a complete miss. By using the differential shot rating for each position during an end, along with a few other factors, a model could be built to predict the result based on historically similar ends.</p>
<p>Unlike soccer, where any team can score at any time, in curling only one team can score per end. Therefore it does not make sense to calculate the expected score for both teams each end. Rather, our model should track the same team for the entire game, and predict the point margin each end. Positive values indicate points scored, negative values indicate points given up, and zero represents a blank end.</p>
<p>This introduces \(xMargin\), an expected point margin model for curling. After an end is played, the resulting point margin is predicted using game information, as well as positional differentials in shot rating for that end only. These values can be summed over the course of the game to get the cumulative expected point margin for the target team.</p>
<h2 id="methodology">Methodology</h2>
<p>An XGBoost gradient boosted decision tree model was trained to create xMargin. XGBoost was chosen as it works well with structured data, and is meant for determining important relationships between features. There were two main options for models that could be used, regression and classifier. We chose to use a regression model, as data for high scoring ends (\(\pm 3\)) are few and far between. A classifier model would have difficulty predicting large point differentials, as individual numbers (ie +3, +4) are treated as discrete classes with no relation to each other. A regression model is better suited for the task as the point differential is treated as a floating point number, preserving ordering and scale of numbers.</p>
<p>To train the model we analyzed game data for all Brier and Tournament of Hearts championships (the Canadian national men’s and women&rsquo;s championships, respectively) between 2023 and 2026. This range was selected because it encompasses the first national championships to implement the <a href="https://www.curling.ca/blog/2023/10/04/no-tick-rule-added-in-2023-24/">no-tick-rule</a> [4], through to the most recent events as of writing this article. Men’s and Women’s data were kept separate in training.</p>
<p>Data was collected from Curling Canada’s event scoreboard pages (curling.ca/scoreboard) using the underlying curling.io API endpoints.</p>
<table>
<thead>
<tr>
<th></th>
<th>Womens</th>
<th>Mens</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Events</strong></td>
<td>4</td>
<td>4</td>
</tr>
<tr>
<td><strong>Games</strong></td>
<td>321</td>
<td>319</td>
</tr>
<tr>
<td><strong>Ends</strong></td>
<td>2911</td>
<td>2900</td>
</tr>
<tr>
<td><strong>Blank %</strong></td>
<td>9.4%</td>
<td>14%</td>
</tr>
</tbody>
</table>
<p>Using information from each end, we engineered the following features. All differential metrics are calculated from the perspective of the target team, A.</p>
<table>
<thead>
<tr>
<th style="text-align:left">Feature</th>
<th style="text-align:center">Formula</th>
<th style="text-align:left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">\(\Delta Shot Rating_A(Position,End)\)</td>
<td style="text-align:center">\(R_{A,Position} - R_{B,Position}\)</td>
<td style="text-align:left">Difference in shot rating against the opponent at each position for a select end.</td>
</tr>
<tr>
<td style="text-align:left">\(Δ Backend Zeroes_A\)</td>
<td style="text-align:center">\(Zeros_{A,3} + Zeros_{A,4}) - (Zeros_{B,3} + Zeros_{B,4}\)</td>
<td style="text-align:left">Differential number of total missed shots by the third and fourth.</td>
</tr>
<tr>
<td style="text-align:left">\(Δ Cumulative Score\)</td>
<td style="text-align:center">\(Score_A - Score_B\)</td>
<td style="text-align:left">Cumulative point differential for the game at the start of the end.</td>
</tr>
<tr>
<td style="text-align:left">\(EndsRemaining\)</td>
<td style="text-align:center">\(ScheduledEnds-CurrentEnd\)</td>
<td style="text-align:left">Number of scheduled ends remaining in the game.</td>
</tr>
<tr>
<td style="text-align:left">\(Hammer_A\)</td>
<td style="text-align:center">1 if TeamA has hammer, else 0</td>
<td style="text-align:left">Whether or not Team A has the hammer in the end.</td>
</tr>
<tr>
<td style="text-align:left">\(LSFE_A\)</td>
<td style="text-align:center">1 if TeamA had LSFE, else 0</td>
<td style="text-align:left">Whether or not TeamA began the game with hammer</td>
</tr>
<tr>
<td style="text-align:left">\(Even End\)</td>
<td style="text-align:center">\(End\mod{2}\)</td>
<td style="text-align:left">Whether the current end number is even.</td>
</tr>
</tbody>
</table>
<p>These features were engineered as they represent some of the most crucial factors to scoring in curling, not only from a performance perspective, but in terms of strategy as well. The team with the hammer is much more likely to score in the end. Teams down by multiple points will take more risks, either scoring multiple, or giving up a large amount of points. If the game is tied and only one end remains, the end is more likely to be low scoring. Complete misses by backend players (thirds and fourths), are usually detrimental to an end, and can result in large point swings.</p>
<p>Each row in the dataset represents one end of curling. Using scikit-learn&rsquo;s train_test_split function, the data is split into two sets, a training set containing 75% of the ends, and testing set containing 25%. The training set is then used to train the XGBRegressor, with the below configuration.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">xgb</span><span class="o">.</span><span class="n">XGBRegressor</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">eval_metric</span><span class="o">=</span><span class="s1">&#39;mae&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="n">objective</span><span class="o">=</span><span class="s2">&#34;reg:absoluteerror&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="n">tree_method</span> <span class="o">=</span> <span class="s2">&#34;auto&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="n">n_estimators</span> <span class="o">=</span> <span class="mi">500</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">random_state</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="n">early_stopping_rounds</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><h2 id="results">Results</h2>
<p>As stated earlier, data was split by gender. This means two models were trained, one for women&rsquo;s games and one for men&rsquo;s games.</p>
<h3 id="importance">Importance</h3>
<p>To analyze the importance of our features, and how they impact predictions, we used the SHAP (SHapley Additive exPlana-tions). Every end is represented by a point on the following beeswarm charts. Each point is coloured to represent the value of the feature in that end, with blue representing the lower values, blending to red high values. The SHAP score indicates the direction of impact on the predicted point differential. Positive SHAP values indicate the feature in that end pulled the predicted point margin higher (favouring Team A to score), whereas negative values pull the prediction lower (favouring Team A to concede points).</p>
<p><img alt="SHAP beeswarm chart" src="/mens_womens_beeswarm_shap.png"></p>
<p>These beeswarm charts confirm that the chosen features do have significant impact on scoring potential. Most notably, hammer, and the results achieved by backend players.</p>
<h3 id="error-and-loss-functions">Error and Loss Functions</h3>
<p>Both the men&rsquo;s and women&rsquo;s model had very similar accuracy. Both models achieved a Mean Absolute error of less than one.</p>
<table>
<thead>
<tr>
<th></th>
<th>Womens</th>
<th>Mens</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Mean Absolute Error</strong></td>
<td>0.79</td>
<td>0.77</td>
</tr>
<tr>
<td><strong>Median Absolute Error</strong></td>
<td>0.76</td>
<td>0.64</td>
</tr>
<tr>
<td><strong>Mean Squared Error</strong></td>
<td>1.13</td>
<td>1.12</td>
</tr>
<tr>
<td><strong>Root Mean Squared Error</strong></td>
<td>1.06</td>
<td>1.06</td>
</tr>
<tr>
<td><strong>R²</strong></td>
<td>0.67</td>
<td>0.61</td>
</tr>
</tbody>
</table>
<p>As demonstrated by the residual plot below, the majority of xMargin prediction residuals are between -0.5 and +1 (~70%).</p>
<p><img alt="Mens and Womens residual chart" src="/mens_womens_residual.png"></p>
<p>The plot also demonstrates the sparsity of data when we leave the range of \(xMargin \in [-2, +2]\). Only about twelve percent of men&rsquo;s and women&rsquo;s data falls outside of this range.</p>
<p>Measuring the efficacy of xMargin is difficult, as while it is a prediction model, prediction accuracy is not its sole purpose. Ends with large residuals do not mean the model did a poor job, rather that the team may have outperformed or underperformed the scoreboard. There is no concrete way to know what the score should actually be, thus the xMargin model functions as intended. The model does not necessarily get &ldquo;better&rdquo; by adding more data, it gains more understanding of previous ends, and this understanding is used to isolate a team&rsquo;s performance from result.</p>
<h2 id="conclusion-and-future-work">Conclusion and Future Work</h2>
<p>In its current form, the model treats every shot equally. A future version of the model could look at how important each shot is. If a team has a string of four poor shots, it&rsquo;s crucial for the skip to make their final shot perfectly to avoid a big end.</p>
<p>In the future more data from more events around the world could be included to improve predictions. Currently, only the Canadian national championships are included, but data from the Grand Slam of Curling and the World Championships could help reduce loss, especially in higher point margin ends.</p>
<p>The model could also be adapted for use in broadcasted curling games to provide more insight, and bite-sized analysis, much like how xG is used in soccer.</p>
<p>By isolating execution from scoreboard variance, \(xMargin\) provides coaches, analysts, and fans with a clearer view on true team performance in curling.</p>
<h2 id="references">References</h2>
<p>[1] S. E. Erhan, F. Ağduman, and D. Bedir, “Exploring Predictors of Team Performance in Curling Championships: An Investigation of Factors Predicting Success,” CBÜ Beden Eğitimi ve Spor Bilimleri Dergisi, vol. 18, no. 2, pp. 845–853, Dec. 2023, doi: 10.33459/cbubesbd.1307573.</p>
<p>[2] J. Colman, “Expected goals: What is xG in football and how does it work?,” BBC Sport, Sept. 26, 2025. Accessed: Aug. 18, 2026. [Online]. Available: <a href="https://www.bbc.com/sport/football/articles/cgrqd18q0rgo">https://www.bbc.com/sport/football/articles/cgrqd18q0rgo</a></p>
<p>[3] B. Macdonald, “An Expected Goals Model for Evaluating NHL Teams and Players,” Jan. 2012.</p>
<p>[4] Curling Canada, “Curling Canada adopts No-Tick Rule for all events as of 2023-24,” Curling Canada. <a href="https://www.curling.ca/blog/2023/10/04/no-tick-rule-added-in-2023-24/">https://www.curling.ca/blog/2023/10/04/no-tick-rule-added-in-2023-24/</a> (accessed Aug. 18, 2026).</p>
]]></content:encoded></item><item><title>Combined Optimal Route: Audience friendly route optimizations for SailGP</title><link>https://198ac40d.ibsen.pages.dev/articles/cor/</link><pubDate>Thu, 09 Jul 2026 00:00:00 +0000</pubDate><guid>https://198ac40d.ibsen.pages.dev/articles/cor/</guid><description>This project won third place at the 13th DeepSense Ocean of Data Challenge
In SailGP, each team takes a slightly different path in order to capitalize on the best wind conditions. Combined Optimal Route (COR) takes the path of every team, and tries to find the most optimal route between them.
If two cars are racing on a track, one on the inside, one on the outside, which car&amp;rsquo;s path will be faster?</description><content:encoded><![CDATA[<p><em>This project won third place at the <a href="https://deepsense.ca/ocean-of-data-challenge/">13th DeepSense Ocean of Data Challenge</a></em></p>
<p>In SailGP, each team takes a slightly different path in order to capitalize on the best wind conditions. Combined Optimal Route (COR) takes the path of every team, and tries to find the most optimal route between them.</p>
<p>If two cars are racing on a track, one on the inside, one on the outside, which car&rsquo;s path will be faster? COR takes this one step further, asking instead: is there a combination of both routes that is actually the fastest?</p>
<p><img alt="GIF example of combining routes" src="/cor/racecar.gif"></p>
<p>For this project, I was given sensor data collected at a frequency of 1Hz across all competing teams, and all races for two SailGP events.</p>
<p>Every second of a leg is represented as a node in a directed graph. Each node contains the boat&rsquo;s heading, coordinates, the current wind speed, wind direction, and time elapsed during the leg. Directed edges are then connected between every node at time \(t\) to every other node at time \(t+1\)</p>
<p>In order to determine how favourable the conditions are to travel between nodes, we apply a weight to our edges. This weight is known as our penalty, the higher the number, the less favourable and realistic the path becomes. The penalty formula is as follows.</p>
\[Penalty = d(1000 + |h_{w} - h_{b}|)(cos(s))\]
<p>Where:</p>
<ul>
<li>\(d\) is the distance between nodes.</li>
<li>\(s\) is the speed of the wind.</li>
<li>\(h_{w}\) is the heading of the wind.</li>
<li>\(h_{b}\) is the heading of the boat.</li>
</ul>
<p>Dijsktra&rsquo;s algorithm is then run on our network to find the route with the lowest combined penalty. This in turn, becomes our most optimal route.</p>
<p><img alt="Examples of Combined Optimal Routes" src="/cor/example_routes.jpg"></p>
<p>Combined Optimal Route is not a perfect solution. For starters, the teams do not all pass these points at the same time. What might have been ideal conditions when the first place team sailed through, may not be ideal by the time the last place team reaches that point. It also does not take into account the real physics of these boats. A catamaran is not able to instantaneously take a 90 degree turn. But Combined Optimal Route is not meant to be a perfect solution. It is meant to allow a television audience to compare their favourite team&rsquo;s decisions, and how they chose to traverse the course. It gives the viewer a quick glance at how efficient each team&rsquo;s route was, and what theoretically could have been the best possible route.</p>
]]></content:encoded></item></channel></rss>