<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Paul Johnson</title>
<link>https://paulrjohnson.net/blog/</link>
<atom:link href="https://paulrjohnson.net/blog/index.xml" rel="self" type="application/rss+xml"/>
<description>This is my blog. These are the many stupid things I&#39;ve done so you don&#39;t have
to tread the same sorry path.&lt;br&gt;&lt;br&gt;[Subscribe via RSS](/blog/index.xml)
</description>
<image>
<url>https://paulrjohnson.net/assets/images/me/headshot_rounded.webp</url>
<title>Paul Johnson</title>
<link>https://paulrjohnson.net/blog/</link>
</image>
<generator>quarto-1.10.18</generator>
<lastBuildDate>Wed, 04 Jun 2025 00:00:00 GMT</lastBuildDate>
<item>
  <title>Automating Netlify Redirects in Quarto Using Lua</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2025-06-04-automating-netlify-redirects-with-lua/</link>
  <description><![CDATA[ 





<p>Last year, I wrote a <a href="../../blog/setting-up-netlify-redirects-with-quarto">blog post</a> about my process for generating Netlify redirects. It was a similar process to that used by many others, adapted slightly to work with my slightly different setup. It involved housing a couple chunks of code in the homepage (<code>index.qmd</code> in the root directory) that would generate redirects every time the homepage is rendered.</p>
<p>This worked fine. It got the job done. However, it bothered me that I had to remember to re-render the homepage every time I needed to update the redirects file. This relied too heavily on my remembering to do something. So, I’ve finally had a crack at fixing this and setting something up that will run without my intervention.</p>
<p>I’ve set up a Lua script that is called before the whole project is rendered. I figured a brief post outlining what I’ve done and how it works might be helpful to others trying to figure this out, and it should be relatively easy to adapt to your own needs.</p>
<section id="the-old-manual-ish-setup" class="level2">
<h2 class="anchored" data-anchor-id="the-old-manual-ish-setup">The Old (Manual-ish) Setup</h2>
<p>I won’t spend too long going over the old approach (you can find it in the <a href="../../blog/setting-up-netlify-redirects-with-quarto">blog post</a> I wrote last year). It worked, and I never actually forgot to re-render the homepage to update the redirects. However, I didn’t love having to go through that extra step, and I certainly didn’t trust myself to remember this detail.</p>
<p>Creating dependencies is an unnecessary mess when all I want to do is generate some redirects from a relatively simple website structure.</p>
</section>
<section id="the-automated-solution" class="level2">
<h2 class="anchored" data-anchor-id="the-automated-solution">The Automated Solution</h2>
<p>Instead, I wrote a <a href="https://www.lua.org">Lua</a> script<sup>1</sup> that is set to run before any Quarto document renders (using Quarto’s <a href="https://quarto.org/docs/projects/scripts.html#pre-and-post-render">pre/post rendering functionality</a>), which generates all my redirects in a file that is stored at the root for Netlify to pick up and use in deployment.</p>
<p>It’s essentially the same process I followed before. Still, by shifting it into a separate script that runs when Netlify renders the site (using the Quarto Netlify plugin), I no longer have to worry about running this before pushing a new post.</p>
<p>I chose Lua because it is already packaged up in Quarto’s installation, as Pandoc uses Lua as its filter language, and Netlify recognises it when deploying the site. That means no extra work is required with a Lua script. Lua is relatively simple, and if you have experience with R and/or Python, it shouldn’t take long to pick it up<sup>2</sup>.</p>
<p>There are three types of redirects handled by this script:</p>
<ul>
<li>Manual Redirects - These are hand-written rules stored in a <code>_manualredirects</code> file, intended to redirect old pages when the website used a different structure.</li>
<li>Blog Post Redirects - Automatically generated rules that redirect from simple URLs (<code>/blog/my-post-title</code>) to the full dated URLs (<code>/blog/2025-05-26-my-post-title</code>).</li>
<li>Category Redirects - Dynamic redirects that map tag-style URLs (<code>/tags/lua</code>) to filtered blog views (<code>/blog/#category=lua</code>).</li>
</ul>
</section>
<section id="redirects-using-lua" class="level2">
<h2 class="anchored" data-anchor-id="redirects-using-lua">Redirects Using Lua</h2>
<p>If you want to skip the details, here is the script in full.</p>
<details>
<summary>
Lua Code (Click to Expand)
</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- build/redirects.lua</span></span>
<span id="cb1-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Generates redirects for blog posts and categories</span></span>
<span id="cb1-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">system</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pandoc.system"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-4"></span>
<span id="cb1-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Toggle for debug output</span></span>
<span id="cb1-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">DEBUG</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span></span>
<span id="cb1-7"></span>
<span id="cb1-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">os.getenv</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"QUARTO_PROJECT_RENDER_ALL"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-9">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Skipping redirects..."</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-10">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">os.exit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-11"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-12"></span>
<span id="cb1-13"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">message</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-14">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">DEBUG</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-15">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">io.stderr</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">write</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[Redirects Debug] "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">message</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-16">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-18"></span>
<span id="cb1-19"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> is_dir<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-20">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">handle</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">io.popen</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'[ -d "'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span></span>
<span id="cb1-21">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'" ] &amp;&amp; echo "yes" || echo "no"'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-22">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">result</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">handle</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"*a"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">):</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gsub</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%s+"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-23">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">handle</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-24">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">result</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"yes"</span></span>
<span id="cb1-25"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-26"></span>
<span id="cb1-27"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> file_exists<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-28">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">io.open</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"r"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-29">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-30">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-31">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span></span>
<span id="cb1-32">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-33">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span></span>
<span id="cb1-34"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-35"></span>
<span id="cb1-36"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> read_lines<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-37">    debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Attempting to read: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-38">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> file_exists<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-39">        debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"File not found: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-40">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-41">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-42"></span>
<span id="cb1-43">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lines</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-44">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">io.open</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"r"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-45">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">line</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lines</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-46">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lines</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">line</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-47">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-48">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-49">    debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Read "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lines</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" lines from: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">file_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-50">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lines</span></span>
<span id="cb1-51"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-52"></span>
<span id="cb1-53"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> extract_categories<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-54">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">qmd_path</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_path</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/index.qmd"</span></span>
<span id="cb1-55">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> file_exists<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">qmd_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-56">        debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Blog post .qmd not found: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">qmd_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-57">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-58">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-59"></span>
<span id="cb1-60">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> read_lines<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">qmd_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-61">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">categories</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-62"></span>
<span id="cb1-63">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">line</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ipairs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-64">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cat_match</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">line</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">match</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^categories:%s*%[(.+)%]"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-65">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cat_match</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-66">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cat</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cat_match</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gmatch</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"([^,]+)"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-67">                <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cat</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cat</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gsub</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^%s*(.-)%s*$"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%1"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Trim whitespace</span></span>
<span id="cb1-68">                <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">categories</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cat</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-69">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-70">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span>
<span id="cb1-71">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-72">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-73">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">categories</span></span>
<span id="cb1-74"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-75"></span>
<span id="cb1-76"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> load_manual_redirects<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">project_root</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-77">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">manual_paths</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-78">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">project_root</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/assets/_manualredirects"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-79">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">project_root</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/build/_manualredirects"</span></span>
<span id="cb1-80">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-81"></span>
<span id="cb1-82">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ipairs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">manual_paths</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-83">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> file_exists<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-84">            debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Found manual redirects at: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-85">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> read_lines<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-86">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-87">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-88">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-89"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-90"></span>
<span id="cb1-91"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> process_blog_posts<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_dir</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-92">    debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Looking for blog posts in: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_dir</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-93"></span>
<span id="cb1-94">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirects</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-95">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_posts</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-96">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_categories</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-97"></span>
<span id="cb1-98">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">dir_cmd</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'find "'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_dir</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span></span>
<span id="cb1-99">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'" -maxdepth 1 -mindepth 1 -type d'</span></span>
<span id="cb1-100">    debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Running directory listing command: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">dir_cmd</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-101"></span>
<span id="cb1-102">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">handle</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">io.popen</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">dir_cmd</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-103">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_path</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">handle</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lines</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-104">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_name</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">match</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"([^/]+)$"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-105">        debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Found potential blog post: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span></span>
<span id="cb1-106">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_name</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"unnamed"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span></span>
<span id="cb1-107"></span>
<span id="cb1-108">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Process only directories matching date pattern</span></span>
<span id="cb1-109">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_name</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">match</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^%d%d%d%d%-%d%d%-%d%d%-"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-110">            <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">title_slug</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gsub</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^%d%d%d%d%-%d%d%-%d%d%-"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-111">            <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">old</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/blog/"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">title_slug</span></span>
<span id="cb1-112">            <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">new</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/blog/"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_name</span></span>
<span id="cb1-113"></span>
<span id="cb1-114">            <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">old</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">new</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-115">            <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_posts</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-116">            debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Added redirect: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">old</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" → "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">new</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-117"></span>
<span id="cb1-118">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Collect categories</span></span>
<span id="cb1-119">            <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_categories</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> extract_categories<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-120">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cat</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ipairs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_categories</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-121">                debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Found category: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cat</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-122">                <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_categories</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cat</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span></span>
<span id="cb1-123">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-124">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-125">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-126">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">handle</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-127"></span>
<span id="cb1-128">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_posts</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_categories</span></span>
<span id="cb1-129"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-130"></span>
<span id="cb1-131"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> generate_category_redirects<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_categories</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-132">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirects</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-133">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">category_count</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb1-134"></span>
<span id="cb1-135">    debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Generating category redirects"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-136">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">category</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pairs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_categories</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-137">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">encoded_category</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">category</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gsub</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%%20"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-138">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">tag</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">category</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lower</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">():</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gsub</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-139">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/tags/"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">tag</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span></span>
<span id="cb1-140">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/blog/#category="</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">encoded_category</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-141">        debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Added category redirect: /tags/"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">tag</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-142">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">category_count</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">category_count</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb1-143">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-144"></span>
<span id="cb1-145">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">category_count</span></span>
<span id="cb1-146"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-147"></span>
<span id="cb1-148"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> write_redirects_file<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">project_root</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-149">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">out_file</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">project_root</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/_redirects"</span></span>
<span id="cb1-150">    debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Writing redirects to: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">out_file</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-151"></span>
<span id="cb1-152">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">io.open</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">out_file</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"w"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-153">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-154">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">line</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ipairs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-155">            <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">write</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">line</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-156">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-157">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-158">        debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Successfully wrote "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirects</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" redirects"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-159">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span></span>
<span id="cb1-160">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span></span>
<span id="cb1-161">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">io.stderr</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">write</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ERROR: Could not open output file for writing: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span></span>
<span id="cb1-162">            <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">out_file</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-163">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span></span>
<span id="cb1-164">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-165"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-166"></span>
<span id="cb1-167"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> Pandoc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-168">    debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Starting redirect generation..."</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-169"></span>
<span id="cb1-170">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">project_root</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">system</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>get_working_directory<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-171">    debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Working directory: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">project_root</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-172"></span>
<span id="cb1-173">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Check Netlify environment (preserved for potential future use)</span></span>
<span id="cb1-174">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">netlify_build_dir</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">os.getenv</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NETLIFY"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span></span>
<span id="cb1-175">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">os.getenv</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NETLIFY_BUILD_BASE"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-176">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">netlify_build_dir</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-177">        debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Running in Netlify environment: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">netlify_build_dir</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-178">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-179"></span>
<span id="cb1-180">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_dir</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">project_root</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/blog"</span></span>
<span id="cb1-181">    debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Blog directory path: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_dir</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-182"></span>
<span id="cb1-183">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> is_dir<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_dir</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-184">        debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Blog directory not found, skipping redirect generation"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-185">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span></span>
<span id="cb1-186">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-187"></span>
<span id="cb1-188">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Load manual redirects</span></span>
<span id="cb1-189">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">manual_redirects</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> load_manual_redirects<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">project_root</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-190">    debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Added "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">manual_redirects</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" manual redirects"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-191"></span>
<span id="cb1-192">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Process blog posts</span></span>
<span id="cb1-193">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_posts</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_categories</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span></span>
<span id="cb1-194">        process_blog_posts<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_dir</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-195"></span>
<span id="cb1-196">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Generate category redirects</span></span>
<span id="cb1-197">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">category_redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">category_count</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span></span>
<span id="cb1-198">        generate_category_redirects<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_categories</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-199"></span>
<span id="cb1-200">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Combine all redirects</span></span>
<span id="cb1-201">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_redirects</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-202">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirect</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ipairs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">manual_redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-203">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirect</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-204">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-205">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirect</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ipairs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-206">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirect</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-207">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-208">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirect</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ipairs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">category_redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-209">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">redirect</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-210">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-211"></span>
<span id="cb1-212">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Write redirects file</span></span>
<span id="cb1-213">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> write_redirects_file<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">project_root</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_redirects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-214">        debug_log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Redirect generation complete"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-215">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Redirects written to _redirects ("</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span></span>
<span id="cb1-216">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">all_redirects</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span></span>
<span id="cb1-217">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" entries, "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span></span>
<span id="cb1-218">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blog_posts</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" posts, "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">manual_redirects</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span></span>
<span id="cb1-219">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" manual, "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">category_count</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" categories)"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-220">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-221"></span>
<span id="cb1-222">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span></span>
<span id="cb1-223"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div></div>
</details>
<section id="key-components" class="level3">
<h3 class="anchored" data-anchor-id="key-components">Key Components</h3>
<p>For anyone interested in how the script works, however, here are some details.</p>
<section id="environment-detection" class="level4">
<h4 class="anchored" data-anchor-id="environment-detection">Environment Detection</h4>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">project_root</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">system</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>get_working_directory<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb2-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">netlify_build_dir</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">os.getenv</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NETLIFY"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">os.getenv</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NETLIFY_BUILD_BASE"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<p>The script first determines where it’s running - locally during development or on Netlify during deployment. This flexibility ensures it works in both environments.</p>
</section>
<section id="file-system-operations" class="level4">
<h4 class="anchored" data-anchor-id="file-system-operations">File System Operations</h4>
<p>Lua provides basic file system operations, which the script uses:</p>
<ul>
<li>Directory checking - Verifying that blog directories exist.</li>
<li>File reading - Processing blog post metadata and manual redirect files.</li>
<li>File writing - Creating the final <code>_redirects</code> file<sup>3</sup>.</li>
</ul>
</section>
<section id="pattern-matching" class="level4">
<h4 class="anchored" data-anchor-id="pattern-matching">Pattern Matching</h4>
<p>One of Lua’s strengths is its pattern-matching system. The script uses this to find my blog posts based on the pattern of ISO dates at the start of a blog post folder.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb3-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_name</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">match</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^%d%d%d%d%-%d%d%-%d%d%-"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb3-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">title_slug</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gsub</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^%d%d%d%d%-%d%d%-%d%d%-"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<p>This finds blog posts with names like <code>2025-05-26-my-post-title</code> and extracts just the title part. If you use a different structure for your posts, you will need to adjust this accordingly.</p>
</section>
<section id="category-processing" class="level4">
<h4 class="anchored" data-anchor-id="category-processing">Category Processing</h4>
<p>The script reads each blog post’s metadata to extract categories.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb4-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cat_match</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">line</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">match</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^categories:%s*%[(.+)%]"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<p>This looks for lines like <code>categories: [Netlify, Quarto, Web Development, Lua]</code> in the blog post’s YAML header.</p>
</section>
</section>
</section>
<section id="wrapping-up" class="level2">
<h2 class="anchored" data-anchor-id="wrapping-up">Wrapping Up</h2>
<p>Now, every time I publish a new blog post or add categories, the redirects are automatically updated without any manual intervention. This process also runs every time I render the entire site<sup>4</sup>. This might be overkill. I could probably set it up to only run when it detects a fresh deployment to Netlify, but this feels like a good way to spot any issues or errors and will make debugging a little easier.</p>
<p>There isn’t that much to what I’ve done, but I figured it was worth sharing because others might like to do something similar. It shouldn’t require significant editing, but it will involve adjusting to fit the structure of your website. Hopefully, this is of value to at least one other person!</p>
</section>




<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Preview image by <a href="https://unsplash.com/@dagny_2020">Dagny Reese</a> on <a href="https://unsplash.com/photos/black-and-yellow-no-smoking-sign-G9l9ejbuHlI">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>


</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>Full disclosure: I put together the script with help from Claude AI, as I had no prior experience with Lua. I’m not claiming to have written this from scratch, but I still wanted to share it, as it may be valuable to others.↩︎</p></li>
<li id="fn2"><p>If you need to learn Lua, I recommend the <a href="https://learnxinyminutes.com/lua/">Learn Lua in 15 Minutes</a> resource, as well as Quarto’s <a href="https://quarto.org/docs/extensions/luarefv51.pdf">Lua Cheatsheet</a>.↩︎</p></li>
<li id="fn3"><p>My manual redirects file is located in the <code>build</code> folder, but if yours (or your redirects script) is stored elsewhere, you will need to update this accordingly.↩︎</p></li>
<li id="fn4"><p>One of the first steps in the script checks if the entire site is rendering:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb5-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">os.getenv</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"QUARTO_PROJECT_RENDER_ALL"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb5-2">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Skipping redirects..."</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb5-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">os.exit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb5-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div></div>
<p>If the command being called is <code>quarto render</code>, then the redirects process runs in full. However, if it is <code>quarto preview</code> or a specific page is being rendered, it skips.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2025" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2025. <span>“Automating Netlify Redirects in Quarto Using
Lua.”</span> June 4. <a href="https://paulrjohnson.net/blog/2025-06-04-automating-netlify-redirects-with-lua/">https://paulrjohnson.net/blog/2025-06-04-automating-netlify-redirects-with-lua/</a>.
</div></div></section></div> ]]></description>
  <category>Netlify</category>
  <category>Quarto</category>
  <category>Web Development</category>
  <category>Lua</category>
  <guid>https://paulrjohnson.net/blog/2025-06-04-automating-netlify-redirects-with-lua/</guid>
  <pubDate>Wed, 04 Jun 2025 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2025-06-04-automating-netlify-redirects-with-lua/traffic.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Testing Transfermarkt’s Squad Market Values</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2025-05-11-testing-transfermarkt-squad-values/</link>
  <description><![CDATA[ 





<div class="cell">
<details class="code-fold">
<summary>Setup Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import packages</span></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">suppressPackageStartupMessages</span>({</span>
<span id="cb1-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(dplyr)</span>
<span id="cb1-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(gt)</span>
<span id="cb1-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ggplot2)</span>
<span id="cb1-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tidymodels)</span>
<span id="cb1-7">})</span>
<span id="cb1-8"></span>
<span id="cb1-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># load helper functions</span></span>
<span id="cb1-10"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">source</span>(here<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">here</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_resources/r_utils/visualisation.R"</span>))</span>
<span id="cb1-11"></span>
<span id="cb1-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set plot theme</span></span>
<span id="cb1-13"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_plot_theme</span>()</span>
<span id="cb1-14"></span>
<span id="cb1-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># load data</span></span>
<span id="cb1-16">buli_resources <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-17">  readr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_rds</span>(</span>
<span id="cb1-18">    here<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">here</span>(</span>
<span id="cb1-19">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"blog"</span>,</span>
<span id="cb1-20">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2025-05-11-testing-transfermarkt-squad-values"</span>,</span>
<span id="cb1-21">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>,</span>
<span id="cb1-22">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"buli_resources.rds"</span></span>
<span id="cb1-23">    )</span>
<span id="cb1-24">  )</span></code></pre></div></div>
</details>
</div>
<p>Last year, I wrote a <a href="https://paulrjohnson.net/blog/analysing-money-in-football/">blog post</a> that modelled the effect that money has on outcomes in Europe’s five biggest football leagues. The key explanatory variable in my model was Transfermarkt’s squad market values. Squad value served as a proxy for a club’s financial clout. The assumption was that clubs generally invest as much money in the team as possible, but data capturing the full extent of squad spending is challenging to source. Research shows Transfermarkt’s player market values are strongly associated with transfer fees <span class="citation" data-cites="herm2014 muller2017 coates2022">(Herm et al. 2014; Müller et al. 2017; Coates and Parshakov 2022)</span> and player salaries <span class="citation" data-cites="prockl2018">(Prockl and Frick 2018)</span>, so I figured squad values would be an adequate proxy for squad spending. But what if I was wrong?</p>
<p>A little over a month ago, I was <a href="https://bsky.app/profile/ansgarw.bsky.social/post/3lm2hgpgxfc2j">made aware</a> of the DFL’s (Deutsche Fussball Liga) <a href="https://www.dfl.de/de/hintergrund/lizenzierungsverfahren/finanzkennzahlen-der-proficlubs/">financial reports</a> detailing the annual accounts for every club in the Bundesliga (and 2. Bundesliga). The accounts include each club’s “staff costs”, which is the amount each club spends on wages for all employees (including but not limited to playing staff). I think this will should be a close approximation of squad wage spending<sup>1</sup>. Never one to miss an opportunity to make <em>content</em>, I went to work and grabbed six seasons of data from 2017/18 to 2022/23. Now, we can determine whether Transfermarkt’s squad values are a reasonable proxy for the data I was too lazy to go and find myself. And more importantly, we can find out if I was wrong<sup>2</sup>.</p>
<section id="exploring-the-data" class="level2">
<h2 class="anchored" data-anchor-id="exploring-the-data">Exploring the Data</h2>
<p>The data is pretty solid, but it comes with some caveats. While most clubs report their staff costs on a seasonal basis, some report staff costs for the financial year. In those cases, the costs don’t perfectly align with a single season, but I don’t think the change in costs from season to season is significant enough to be a huge concern. I also had to drop Frankfurt’s 2022/23 season<sup>3</sup> and Paderborn’s 2021/22 season<sup>4</sup> from the data.</p>
<p>I’m not too worried that these caveats will cause any significant problems. Although the sample size is relatively small, the data seem sufficient for the question I’m trying to answer here.</p>
<section id="the-value-cost-gap-difference" class="level3">
<h3 class="anchored" data-anchor-id="the-value-cost-gap-difference">The Value-Cost Gap (Difference)</h3>
<p>First, it’s probably worth comparing the squad values and staff costs directly to understand what we are working with. I will start by capturing the difference between the two and exploring how this figure varies across the dataset.</p>
<p>Plotting the difference between squad value and staff costs below, we see that the gap between the two is sizeable, with squad value usually (but not always) larger.</p>
<div class="cell">
<details class="code-fold">
<summary>Helper Function Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">scale_euros <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axes =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"both"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">expand =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)) {</span>
<span id="cb2-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># euro label with short scale</span></span>
<span id="cb2-3">  label_euro <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_number</span>(</span>
<span id="cb2-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale_cut =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cut_short_scale</span>(),</span>
<span id="cb2-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prefix =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"€"</span></span>
<span id="cb2-6">  )</span>
<span id="cb2-7"></span>
<span id="cb2-8">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># return ggplot scales based on axis selection</span></span>
<span id="cb2-9">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">switch</span>(</span>
<span id="cb2-10">    axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb2-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_continuous</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> label_euro, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">expand =</span> expand)),</span>
<span id="cb2-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_y_continuous</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> label_euro, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">expand =</span> expand)),</span>
<span id="cb2-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">both =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb2-14">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_continuous</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> label_euro, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">expand =</span> expand),</span>
<span id="cb2-15">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_y_continuous</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> label_euro, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">expand =</span> expand)</span>
<span id="cb2-16">    )</span>
<span id="cb2-17">  )</span>
<span id="cb2-18">}</span></code></pre></div></div>
</details>
</div>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">buli_resources <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">diff =</span> squad_value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> staff_cost) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> diff)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_histogram</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bins =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_hline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">yintercept =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_euros</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axes =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb3-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Differences Between Squad Value &amp; Staff Costs in the Bundesliga"</span>,</span>
<span id="cb3-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb3-10">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb3-11">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The distribution of club value differences (squad value minus staff "</span>,</span>
<span id="cb3-12">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"costs) per season in the Bundesliga from 2017/18 to 2022/23."</span></span>
<span id="cb3-13">      ),</span>
<span id="cb3-14">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb3-15">    ),</span>
<span id="cb3-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Value Difference</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">(Squad Value - Staff Costs)"</span>,</span>
<span id="cb3-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb3-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: DFL &amp; Transfermarkt"</span></span>
<span id="cb3-19">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2025-05-11-testing-transfermarkt-squad-values/index_files/figure-html/difference-distribution-1.png" class="img-fluid figure-img" alt="A histogram visualising the distribution of club value differences (squad market value minus staff costs) per season from 2017/18 to 2022/23. The distribution is right-skewed, peaking at around €50m with a long tail reaching over €500m. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>The difference between the two isn’t an issue. Squad value and staff costs are different things. If they generally vary together, that will suffice.</p>
<p>It’s also worth considering the team-level variance<sup>5</sup>. Table&nbsp;1 shows the median difference between squad value and staff costs per season for clubs that have played three or more seasons in the data<sup>6</sup>.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">buli_resources <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">diff =</span> squad_value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> staff_cost) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add_count</span>(team) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">club_diff =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">median</span>(diff), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> team) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">desc</span>(club_diff)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rowname_col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"team"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_label</span>(</span>
<span id="cb4-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">club_diff =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">md</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Value Difference&lt;br&gt;(Squad Value - Staff Costs)"</span>)</span>
<span id="cb4-10">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fmt_currency</span>(</span>
<span id="cb4-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> club_diff,</span>
<span id="cb4-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">currency =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EUR"</span>,</span>
<span id="cb4-14">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">suffixing =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,</span>
<span id="cb4-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">decimals =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb4-16">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-17">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_align</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> club_diff) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb4-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_fill</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#f8f9fa"</span>)),</span>
<span id="cb4-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_body</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">everything</span>())</span>
<span id="cb4-21">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-22">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table_theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source_note =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Source: DFL &amp; Transfermarkt"</span>)</span></code></pre></div></div>
</details>
<div id="tbl-team-difference" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-team-difference-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Median Value Differences in the Bundesliga from 2017/18 to 2022/23
</figcaption>
<div aria-describedby="tbl-team-difference-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="itibiuqhfd" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#itibiuqhfd table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#itibiuqhfd thead, #itibiuqhfd tbody, #itibiuqhfd tfoot, #itibiuqhfd tr, #itibiuqhfd td, #itibiuqhfd th {
  border-style: none;
}

#itibiuqhfd p {
  margin: 0;
  padding: 0;
}

#itibiuqhfd .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#itibiuqhfd .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#itibiuqhfd .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#itibiuqhfd .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#itibiuqhfd .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#itibiuqhfd .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#itibiuqhfd .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#itibiuqhfd .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#itibiuqhfd .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#itibiuqhfd .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#itibiuqhfd .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#itibiuqhfd .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#itibiuqhfd .gt_spanner_row {
  border-bottom-style: hidden;
}

#itibiuqhfd .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#itibiuqhfd .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#itibiuqhfd .gt_from_md > :first-child {
  margin-top: 0;
}

#itibiuqhfd .gt_from_md > :last-child {
  margin-bottom: 0;
}

#itibiuqhfd .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#itibiuqhfd .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#itibiuqhfd .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#itibiuqhfd .gt_row_group_first td {
  border-top-width: 2px;
}

#itibiuqhfd .gt_row_group_first th {
  border-top-width: 2px;
}

#itibiuqhfd .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#itibiuqhfd .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#itibiuqhfd .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#itibiuqhfd .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#itibiuqhfd .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#itibiuqhfd .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#itibiuqhfd .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#itibiuqhfd .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#itibiuqhfd .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#itibiuqhfd .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#itibiuqhfd .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#itibiuqhfd .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#itibiuqhfd .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#itibiuqhfd .gt_left {
  text-align: left;
}

#itibiuqhfd .gt_center {
  text-align: center;
}

#itibiuqhfd .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#itibiuqhfd .gt_font_normal {
  font-weight: normal;
}

#itibiuqhfd .gt_font_bold {
  font-weight: bold;
}

#itibiuqhfd .gt_font_italic {
  font-style: italic;
}

#itibiuqhfd .gt_super {
  font-size: 65%;
}

#itibiuqhfd .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#itibiuqhfd .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#itibiuqhfd .gt_indent_1 {
  text-indent: 5px;
}

#itibiuqhfd .gt_indent_2 {
  text-indent: 10px;
}

#itibiuqhfd .gt_indent_3 {
  text-indent: 15px;
}

#itibiuqhfd .gt_indent_4 {
  text-indent: 20px;
}

#itibiuqhfd .gt_indent_5 {
  text-indent: 25px;
}

#itibiuqhfd .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#itibiuqhfd div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<colgroup>
<col style="width: 50%">
<col style="width: 50%">
</colgroup>
<thead>
<tr class="gt_col_headings header">
<th id="a::stub" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col"></th>
<th id="club_diff" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Value Difference<br>(Squad Value - Staff Costs)</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<th id="stub_1_1" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Bayern Munich</th>
<td class="gt_row gt_center" headers="stub_1_1 club_diff" style="background-color: #F8F9FA">€463.3M</td>
</tr>
<tr class="even">
<th id="stub_1_2" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Borussia Dortmund</th>
<td class="gt_row gt_center" headers="stub_1_2 club_diff" style="background-color: #F8F9FA">€400.1M</td>
</tr>
<tr class="odd">
<th id="stub_1_3" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">RB Leipzig</th>
<td class="gt_row gt_center" headers="stub_1_3 club_diff" style="background-color: #F8F9FA">€344.1M</td>
</tr>
<tr class="even">
<th id="stub_1_4" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Bayer Leverkusen</th>
<td class="gt_row gt_center" headers="stub_1_4 club_diff" style="background-color: #F8F9FA">€276.0M</td>
</tr>
<tr class="odd">
<th id="stub_1_5" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Borussia Mönchengladbach</th>
<td class="gt_row gt_center" headers="stub_1_5 club_diff" style="background-color: #F8F9FA">€145.0M</td>
</tr>
<tr class="even">
<th id="stub_1_6" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Hoffenheim</th>
<td class="gt_row gt_center" headers="stub_1_6 club_diff" style="background-color: #F8F9FA">€139.1M</td>
</tr>
<tr class="odd">
<th id="stub_1_7" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Frankfurt</th>
<td class="gt_row gt_center" headers="stub_1_7 club_diff" style="background-color: #F8F9FA">€125.0M</td>
</tr>
<tr class="even">
<th id="stub_1_8" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Wolfsburg</th>
<td class="gt_row gt_center" headers="stub_1_8 club_diff" style="background-color: #F8F9FA">€111.5M</td>
</tr>
<tr class="odd">
<th id="stub_1_9" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Hertha BSC</th>
<td class="gt_row gt_center" headers="stub_1_9 club_diff" style="background-color: #F8F9FA">€103.2M</td>
</tr>
<tr class="even">
<th id="stub_1_10" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Schalke</th>
<td class="gt_row gt_center" headers="stub_1_10 club_diff" style="background-color: #F8F9FA">€97.5M</td>
</tr>
<tr class="odd">
<th id="stub_1_11" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Freiburg</th>
<td class="gt_row gt_center" headers="stub_1_11 club_diff" style="background-color: #F8F9FA">€81.2M</td>
</tr>
<tr class="even">
<th id="stub_1_12" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Mainz</th>
<td class="gt_row gt_center" headers="stub_1_12 club_diff" style="background-color: #F8F9FA">€77.1M</td>
</tr>
<tr class="odd">
<th id="stub_1_13" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Stuttgart</th>
<td class="gt_row gt_center" headers="stub_1_13 club_diff" style="background-color: #F8F9FA">€67.9M</td>
</tr>
<tr class="even">
<th id="stub_1_14" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Augsburg</th>
<td class="gt_row gt_center" headers="stub_1_14 club_diff" style="background-color: #F8F9FA">€66.7M</td>
</tr>
<tr class="odd">
<th id="stub_1_15" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Union Berlin</th>
<td class="gt_row gt_center" headers="stub_1_15 club_diff" style="background-color: #F8F9FA">€51.9M</td>
</tr>
<tr class="even">
<th id="stub_1_16" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Werder Bremen</th>
<td class="gt_row gt_center" headers="stub_1_16 club_diff" style="background-color: #F8F9FA">€48.8M</td>
</tr>
<tr class="odd">
<th id="stub_1_17" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Köln</th>
<td class="gt_row gt_center" headers="stub_1_17 club_diff" style="background-color: #F8F9FA">€28.3M</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="2" class="gt_sourcenote" style="text-align: left;">Source: DFL &amp; Transfermarkt</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>Looking at Table&nbsp;1, it is obvious that the differences are at least partially a function of the team’s quality or the resources available to teams. This probably identifies an issue with Transfermarkt’s values. Squad values are updated regularly and will be responsive to player (and team) performances. Good teams play better, leading to better teams seeing their values increase.</p>
<p>Another explanation could be that this is just a product of scales. The squad values are generally larger than the staff costs, but perhaps they are a certain percentage higher, on average, and for teams with higher staff costs, that’s inherently going to mean a bigger difference.</p>
</section>
<section id="when-value-meets-reality-correlation" class="level3">
<h3 class="anchored" data-anchor-id="when-value-meets-reality-correlation">When Value Meets Reality (Correlation)</h3>
<p>If the differences between squad value and staff costs are a mixed bag, the correlation between the two paints a clearer picture. There is a 0.94 correlation between squad value and staff costs, which is pretty remarkable.</p>
<p>When we visualise the association between the two below, it further illustrates how closely tied they are.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1">buli_resources <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> staff_cost, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> squad_value)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb5-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb5-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>,</span>
<span id="cb5-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>,</span>
<span id="cb5-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.15</span></span>
<span id="cb5-9">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_euros</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb5-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value by Staff Costs in the Bundesliga"</span>,</span>
<span id="cb5-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb5-14">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb5-15">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The correlation between staff costs and squad value in the Bundesliga "</span>,</span>
<span id="cb5-16">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"from 2017/18 to 2022/23."</span></span>
<span id="cb5-17">      ),</span>
<span id="cb5-18">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb5-19">    ),</span>
<span id="cb5-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Staff Costs"</span>,</span>
<span id="cb5-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value"</span>,</span>
<span id="cb5-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: DFL &amp; Transfermarkt"</span></span>
<span id="cb5-23">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2025-05-11-testing-transfermarkt-squad-values/index_files/figure-html/costs-by-value-1.png" class="img-fluid figure-img" alt="A regression plot visualising the association between staff costs and squad value. The plot shows a positive linear association with relatively little variance. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>The relationship is incredibly clean. It is clearly linear, and any variance is minimal. Squad values are undervalued at the lower end of staff costs, but the reverse is true, as it increases. At the top end of staff costs, the squad values are all slightly undervalued. Squad value seems to be an excellent approximation of staff costs from this perspective.</p>
</section>
</section>
<section id="comparing-predictive-performance" class="level2">
<h2 class="anchored" data-anchor-id="comparing-predictive-performance">Comparing Predictive Performance</h2>
<p>The final test of squad value’s validity as a proxy for staff costs is to compare how well both predict Bundesliga outcomes. To remain consistent with the original model, I will use the outcomes used in my original blog post—points, goal difference, and expected goal (xG) difference—all standardised using games played (so their value represents outcome value per game).</p>
<p>Squad value and staff costs are strongly correlated with all three league outcomes, as shown in Table&nbsp;2.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># compute correlations</span></span>
<span id="cb6-2">correlation_table <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> buli_resources <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(squad_value, staff_cost, pts, gd, xgd) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-4">  correlation<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">correlation</span>(</span>
<span id="cb6-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">select =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"squad_value"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"staff_cost"</span>),</span>
<span id="cb6-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">select2 =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pts"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gd"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xgd"</span>)</span>
<span id="cb6-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tibble</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb6-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">feature_set =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">if_else</span>(</span>
<span id="cb6-11">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_detect</span>(Parameter1, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"squad_"</span>),</span>
<span id="cb6-12">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value"</span>,</span>
<span id="cb6-13">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Staff Costs"</span></span>
<span id="cb6-14">    ),</span>
<span id="cb6-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">outcome =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">recode</span>(</span>
<span id="cb6-16">      Parameter2,</span>
<span id="cb6-17">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pts =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>,</span>
<span id="cb6-18">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">gd =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Difference"</span>,</span>
<span id="cb6-19">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xgd =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xG Difference"</span>,</span>
<span id="cb6-20">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.default =</span> Parameter2</span>
<span id="cb6-21">    ),</span>
<span id="cb6-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">outcome =</span> forcats<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct</span>(</span>
<span id="cb6-23">      outcome,</span>
<span id="cb6-24">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">levels =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Difference"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xG Difference"</span>)</span>
<span id="cb6-25">    )</span>
<span id="cb6-26">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-27">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(feature_set, outcome, r)</span>
<span id="cb6-28"></span>
<span id="cb6-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># display correlation table</span></span>
<span id="cb6-30">correlation_table <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-31">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rowname_col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outcome"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">groupname_col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"feature_set"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-32">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_label</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">r =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Correlation"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-33">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fmt_number</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> r, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">decimals =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">drop_trailing_zeros =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-34">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_align</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> outcome) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-35">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_align</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> r) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-36">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb6-37">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># bold column spanners</span></span>
<span id="cb6-38">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">weight =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bold"</span>),</span>
<span id="cb6-39">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_column_spanners</span>()</span>
<span id="cb6-40">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-41">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb6-42">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># bold group labels</span></span>
<span id="cb6-43">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">weight =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bold"</span>),</span>
<span id="cb6-44">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_row_groups</span>()</span>
<span id="cb6-45">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-46">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table_theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source_note =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Source: DFL &amp; Transfermarkt"</span>)</span></code></pre></div></div>
</details>
<div id="tbl-correlation" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-correlation-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;2: Correlation Between Squad Value/Staff Costs &amp; Bundesliga Outcomes
</figcaption>
<div aria-describedby="tbl-correlation-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="wmrycvqthh" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#wmrycvqthh table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#wmrycvqthh thead, #wmrycvqthh tbody, #wmrycvqthh tfoot, #wmrycvqthh tr, #wmrycvqthh td, #wmrycvqthh th {
  border-style: none;
}

#wmrycvqthh p {
  margin: 0;
  padding: 0;
}

#wmrycvqthh .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#wmrycvqthh .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#wmrycvqthh .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#wmrycvqthh .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#wmrycvqthh .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#wmrycvqthh .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#wmrycvqthh .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#wmrycvqthh .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#wmrycvqthh .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#wmrycvqthh .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#wmrycvqthh .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#wmrycvqthh .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#wmrycvqthh .gt_spanner_row {
  border-bottom-style: hidden;
}

#wmrycvqthh .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#wmrycvqthh .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#wmrycvqthh .gt_from_md > :first-child {
  margin-top: 0;
}

#wmrycvqthh .gt_from_md > :last-child {
  margin-bottom: 0;
}

#wmrycvqthh .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#wmrycvqthh .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#wmrycvqthh .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#wmrycvqthh .gt_row_group_first td {
  border-top-width: 2px;
}

#wmrycvqthh .gt_row_group_first th {
  border-top-width: 2px;
}

#wmrycvqthh .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#wmrycvqthh .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#wmrycvqthh .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#wmrycvqthh .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#wmrycvqthh .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#wmrycvqthh .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#wmrycvqthh .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#wmrycvqthh .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#wmrycvqthh .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#wmrycvqthh .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#wmrycvqthh .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#wmrycvqthh .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#wmrycvqthh .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#wmrycvqthh .gt_left {
  text-align: left;
}

#wmrycvqthh .gt_center {
  text-align: center;
}

#wmrycvqthh .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#wmrycvqthh .gt_font_normal {
  font-weight: normal;
}

#wmrycvqthh .gt_font_bold {
  font-weight: bold;
}

#wmrycvqthh .gt_font_italic {
  font-style: italic;
}

#wmrycvqthh .gt_super {
  font-size: 65%;
}

#wmrycvqthh .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#wmrycvqthh .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#wmrycvqthh .gt_indent_1 {
  text-indent: 5px;
}

#wmrycvqthh .gt_indent_2 {
  text-indent: 10px;
}

#wmrycvqthh .gt_indent_3 {
  text-indent: 15px;
}

#wmrycvqthh .gt_indent_4 {
  text-indent: 20px;
}

#wmrycvqthh .gt_indent_5 {
  text-indent: 25px;
}

#wmrycvqthh .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#wmrycvqthh div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="a::stub" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col"></th>
<th id="r" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Correlation</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="gt_group_heading_row odd">
<th colspan="2" id="Squad Value" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">Squad Value</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_1" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Points</th>
<td class="gt_row gt_center" headers="Squad Value stub_1_1 r">0.83</td>
</tr>
<tr class="odd">
<th id="stub_1_2" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Goal Difference</th>
<td class="gt_row gt_center" headers="Squad Value stub_1_2 r">0.86</td>
</tr>
<tr class="even">
<th id="stub_1_3" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">xG Difference</th>
<td class="gt_row gt_center" headers="Squad Value stub_1_3 r">0.88</td>
</tr>
<tr class="gt_group_heading_row odd">
<th colspan="2" id="Staff Costs" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">Staff Costs</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_4" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Points</th>
<td class="gt_row gt_center" headers="Staff Costs stub_1_4 r">0.75</td>
</tr>
<tr class="odd">
<th id="stub_1_5" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Goal Difference</th>
<td class="gt_row gt_center" headers="Staff Costs stub_1_5 r">0.79</td>
</tr>
<tr class="even">
<th id="stub_1_6" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">xG Difference</th>
<td class="gt_row gt_center" headers="Staff Costs stub_1_6 r">0.81</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="2" class="gt_sourcenote" style="text-align: left;">Source: DFL &amp; Transfermarkt</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>All three outcomes have stronger correlations with squad value than staff costs. The differences are relatively small, but they are consistent. However, the differences are barely perceptible when we plot the relationship between our two predictors and the Bundesliga outcomes below.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1">buli_resources <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># reshape data to long format for outcomes and metrics</span></span>
<span id="cb7-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(</span>
<span id="cb7-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(pts, xgd, gd),</span>
<span id="cb7-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outcome"</span>,</span>
<span id="cb7-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outcome_value"</span></span>
<span id="cb7-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(</span>
<span id="cb7-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(squad_value, staff_cost),</span>
<span id="cb7-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"metric"</span>,</span>
<span id="cb7-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"metric_value"</span></span>
<span id="cb7-12">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb7-14">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">outcome =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">recode</span>(</span>
<span id="cb7-15">      outcome,</span>
<span id="cb7-16">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pts =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>,</span>
<span id="cb7-17">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">gd =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Difference"</span>,</span>
<span id="cb7-18">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xgd =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xG Difference"</span>,</span>
<span id="cb7-19">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.default =</span> outcome</span>
<span id="cb7-20">    ),</span>
<span id="cb7-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">outcome =</span> forcats<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct</span>(</span>
<span id="cb7-22">      outcome,</span>
<span id="cb7-23">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">levels =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Difference"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xG Difference"</span>)</span>
<span id="cb7-24">    ),</span>
<span id="cb7-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">metric =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">if_else</span>(metric <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"squad_value"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Staff Costs"</span>)</span>
<span id="cb7-26">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-27">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> metric_value, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> outcome_value)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-28">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-29">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb7-30">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># log-linear trend lines</span></span>
<span id="cb7-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb7-32">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">formula =</span> y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(x),</span>
<span id="cb7-33">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>,</span>
<span id="cb7-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">se =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,</span>
<span id="cb7-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb7-36">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span></span>
<span id="cb7-37">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-38">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">facet_grid</span>(</span>
<span id="cb7-39">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># layout by outcome and metric</span></span>
<span id="cb7-40">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(outcome),</span>
<span id="cb7-41">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(metric),</span>
<span id="cb7-42">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scales =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"free"</span>,</span>
<span id="cb7-43">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">switch =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span></span>
<span id="cb7-44">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-45">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_euros</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axes =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-46">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb7-47">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bundesliga Outcomes by Squad Value &amp; Staff Costs"</span>,</span>
<span id="cb7-48">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb7-49">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb7-50">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Comparing squad value and staff costs' assocation with Bundesliga "</span>,</span>
<span id="cb7-51">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outcomes—points, goal difference, and xG difference—from 2017/18 to "</span>,</span>
<span id="cb7-52">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2022/23. Outcomes standardised by games."</span></span>
<span id="cb7-53">      ),</span>
<span id="cb7-54">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">93</span></span>
<span id="cb7-55">    ),</span>
<span id="cb7-56">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb7-57">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb7-58">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: DFL &amp; Transfermarkt"</span></span>
<span id="cb7-59">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-60">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span>(</span>
<span id="cb7-61">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.spacing =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lines"</span>),</span>
<span id="cb7-62">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">strip.placement =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outside"</span>,</span>
<span id="cb7-63">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.spacing.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cm"</span>),</span>
<span id="cb7-64">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">angle =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">vjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb7-65">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2025-05-11-testing-transfermarkt-squad-values/index_files/figure-html/outcome-diffs-1.png" class="img-fluid figure-img" alt="A faceted regression plot visualising the association between the predictors (squad value and staff cost) and the league outcomes (points, goal difference, and xG difference). There are a total of six plots, each showing a positive association, with both predictors log-transformed to fit a non-linear pattern in the data. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>The variance appears to be a little larger in the staff costs plots, particularly at around €100m, where the bulk of the observations are. Still, the difference is not obvious. I’m not sure I would have noticed the difference if I wasn’t already aware of the slightly weaker correlation between staff costs and the league outcomes. Perhaps this is a me problem. Maybe I’m confessing my lack of attention to detail.</p>
<section id="xgboost-models" class="level3">
<h3 class="anchored" data-anchor-id="xgboost-models">XGBoost Models</h3>
<div class="cell">
<details class="code-fold">
<summary>Helper Functions Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># preprocessing function</span></span>
<span id="cb8-2">preprocess_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(recipe_obj) {</span>
<span id="cb8-3">  recipe_obj <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_log</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">any_of</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"squad_value"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"staff_cost"</span>))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_novel</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all_nominal_predictors</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-6">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_dummy</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all_nominal_predictors</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_zv</span>()</span>
<span id="cb8-8">}</span>
<span id="cb8-9"></span>
<span id="cb8-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># target/predictor combination recipes function</span></span>
<span id="cb8-11">create_recipes <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(targets, predictors) {</span>
<span id="cb8-12">  combos <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crossing</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target =</span> targets, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">predictor =</span> predictors)</span>
<span id="cb8-13"></span>
<span id="cb8-14">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set seed</span></span>
<span id="cb8-15">  furrr_opts <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> furrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">furrr_options</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb8-16"></span>
<span id="cb8-17">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># create recipe list</span></span>
<span id="cb8-18">  recipes <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> furrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">future_pmap</span>(</span>
<span id="cb8-19">    combos,</span>
<span id="cb8-20">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(target, predictor) {</span>
<span id="cb8-21">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">recipe</span>(</span>
<span id="cb8-22">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">formula =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.formula</span>(glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb8-23">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"{target} ~ {predictor} + season + team"</span></span>
<span id="cb8-24">        )),</span>
<span id="cb8-25">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> train</span>
<span id="cb8-26">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-27">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">preprocess_data</span>()</span>
<span id="cb8-28">    },</span>
<span id="cb8-29">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.options =</span> furrr_opts</span>
<span id="cb8-30">  )</span>
<span id="cb8-31"></span>
<span id="cb8-32">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># name list elements</span></span>
<span id="cb8-33">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(recipes) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb8-34">    furrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">future_pmap_chr</span>(</span>
<span id="cb8-35">      combos,</span>
<span id="cb8-36">      <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"{..1}_{..2}"</span>),</span>
<span id="cb8-37">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.options =</span> furrr_opts</span>
<span id="cb8-38">    )</span>
<span id="cb8-39"></span>
<span id="cb8-40">  recipes</span>
<span id="cb8-41">}</span></code></pre></div></div>
</details>
</div>
<div class="cell">
<details class="code-fold">
<summary>Model Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set seed for reproducibility</span></span>
<span id="cb9-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb9-3"></span>
<span id="cb9-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set up parallel backend</span></span>
<span id="cb9-5">future<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plan</span>(future<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>multisession, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">workers =</span> parallel<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">detectCores</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb9-6"></span>
<span id="cb9-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># split train/test data and specify folds</span></span>
<span id="cb9-8">splits <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">initial_split</span>(buli_resources, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prop =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb9-9">train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">training</span>(splits)</span>
<span id="cb9-10">test <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">testing</span>(splits)</span>
<span id="cb9-11">folds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vfold_cv</span>(train, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">v =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">repeats =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb9-12"></span>
<span id="cb9-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># generate recipes</span></span>
<span id="cb9-14">recipes <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">create_recipes</span>(</span>
<span id="cb9-15">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">targets =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pts"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gd"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xgd"</span>),</span>
<span id="cb9-16">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">predictors =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"squad_value"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"staff_cost"</span>)</span>
<span id="cb9-17">)</span>
<span id="cb9-18"></span>
<span id="cb9-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># xgboost model spec (with tuning)</span></span>
<span id="cb9-20">xgb_spec <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">boost_tree</span>(</span>
<span id="cb9-21">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">trees =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1200</span>,</span>
<span id="cb9-22">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">learn_rate =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.005</span>,</span>
<span id="cb9-23">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tree_depth =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tune</span>(),</span>
<span id="cb9-24">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">loss_reduction =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tune</span>(),</span>
<span id="cb9-25">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sample_size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tune</span>(),</span>
<span id="cb9-26">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stop_iter =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tune</span>()</span>
<span id="cb9-27">) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-28">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_engine</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xgboost"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-29">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_mode</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"regression"</span>)</span>
<span id="cb9-30"></span>
<span id="cb9-31"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># workflow set from recipes and model</span></span>
<span id="cb9-32">wf_sets <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">workflow_set</span>(</span>
<span id="cb9-33">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">preproc =</span> recipes,</span>
<span id="cb9-34">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">models =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xgb =</span> xgb_spec)</span>
<span id="cb9-35">)</span>
<span id="cb9-36"></span>
<span id="cb9-37"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># tuning control</span></span>
<span id="cb9-38">ctrl <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> finetune<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">control_sim_anneal</span>(</span>
<span id="cb9-39">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">save_pred =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,</span>
<span id="cb9-40">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">parallel_over =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"everything"</span>,</span>
<span id="cb9-41">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">save_workflow =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,</span>
<span id="cb9-42">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">verbose =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb9-43">)</span>
<span id="cb9-44"></span>
<span id="cb9-45"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># tune all workflows</span></span>
<span id="cb9-46">tuned_results <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">workflow_map</span>(</span>
<span id="cb9-47">  wf_sets,</span>
<span id="cb9-48">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fn =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tune_sim_anneal"</span>,</span>
<span id="cb9-49">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">control =</span> ctrl,</span>
<span id="cb9-50">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">metrics =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">metric_set</span>(rmse, rsq),</span>
<span id="cb9-51">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">resamples =</span> folds,</span>
<span id="cb9-52">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span></span>
<span id="cb9-53">)</span>
<span id="cb9-54"></span>
<span id="cb9-55"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># stop future plan</span></span>
<span id="cb9-56">future<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plan</span>(future<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>sequential)</span></code></pre></div></div>
</details>
</div>
<p>The last step in this process is to fit some models that are doing far too much, considering they are ostensibly intended to compare the predictive power of two different features. I’ve fit and tuned six different XGBoost models, one each for squad value and staff costs across the three outcomes. Season and team have been included as additional features, similar to the original model<sup>7</sup>.</p>
<p>I won’t bother walking through the models in detail. The goal isn’t to go to great lengths to fit perfect models. I’ve done a little tuning just for the hell of it<sup>8</sup>, but the focus is on comparing the performance of the squad value and staff costs models.</p>
<p>Model performance, measured using root mean square error (RMSE) and R<sup>2</sup> is shown in Table&nbsp;3.</p>
<div class="cell">
<details class="code-fold">
<summary>Helper Functions Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># select the best parameters</span></span>
<span id="cb10-2">select_best_model <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(results, model_id) {</span>
<span id="cb10-3">  results <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">extract_workflow_set_result</span>(model_id) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select_best</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">metric =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rmse"</span>)</span>
<span id="cb10-6">}</span>
<span id="cb10-7"></span>
<span id="cb10-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># finalize and refit on full training data</span></span>
<span id="cb10-9">finalize_and_fit_model <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(results, model_id, data_split) {</span>
<span id="cb10-10">  best_params <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select_best_model</span>(results, model_id)</span>
<span id="cb10-11"></span>
<span id="cb10-12">  results <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-13">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">extract_workflow</span>(model_id) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-14">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">finalize_workflow</span>(best_params) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-15">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">last_fit</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">split =</span> data_split, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">metrics =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">metric_set</span>(rmse, rsq))</span>
<span id="cb10-16">}</span>
<span id="cb10-17"></span>
<span id="cb10-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># extract test performance metrics</span></span>
<span id="cb10-19">get_test_metrics <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(results, model_id, data_split) {</span>
<span id="cb10-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">finalize_and_fit_model</span>(results, model_id, data_split) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-21">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">collect_metrics</span>()</span>
<span id="cb10-22">}</span></code></pre></div></div>
</details>
</div>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># get test performance for all models</span></span>
<span id="cb11-2">summary_table <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb11-3">  tuned_results <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb11-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">test_metrics =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(wflow_id, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_test_metrics</span>(tuned_results, .x, splits)),</span>
<span id="cb11-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">feature_set =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">if_else</span>(</span>
<span id="cb11-7">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_detect</span>(wflow_id, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_squad"</span>),</span>
<span id="cb11-8">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value"</span>,</span>
<span id="cb11-9">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Staff Costs"</span></span>
<span id="cb11-10">    ),</span>
<span id="cb11-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">outcome =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">case_when</span>(</span>
<span id="cb11-12">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_starts</span>(wflow_id, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pts"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>,</span>
<span id="cb11-13">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_starts</span>(wflow_id, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gd"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Difference"</span>,</span>
<span id="cb11-14">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_starts</span>(wflow_id, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xgd"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xG Difference"</span></span>
<span id="cb11-15">    ),</span>
<span id="cb11-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">outcome =</span> forcats<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct</span>(</span>
<span id="cb11-17">      outcome,</span>
<span id="cb11-18">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">levels =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Difference"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xG Difference"</span>)</span>
<span id="cb11-19">    )</span>
<span id="cb11-20">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(outcome) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-22">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unnest</span>(test_metrics) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-23">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_wider</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_from =</span> .metric, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_from =</span> .estimate) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-24">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(feature_set, outcome, rmse, rsq)</span>
<span id="cb11-25"></span>
<span id="cb11-26"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># display metrics table</span></span>
<span id="cb11-27">summary_table <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-28">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">groupname_col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"feature_set"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rowname_col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outcome"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-29">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_label</span>(</span>
<span id="cb11-30">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rmse =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE"</span>,</span>
<span id="cb11-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rsq =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">html</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R&lt;sup&gt;2&lt;/sup&gt;"</span>)</span>
<span id="cb11-32">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-33">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fmt_number</span>(</span>
<span id="cb11-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(rmse, rsq),</span>
<span id="cb11-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">decimals =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb11-36">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">drop_trailing_zeros =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb11-37">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-38">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_align</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> outcome) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-39">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_align</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(rmse, rsq)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-40">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_spanner</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Evaluation Metrics"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(rmse, rsq)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-41">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_footnote</span>(</span>
<span id="cb11-42">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">footnote =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">html</span>(</span>
<span id="cb11-43">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb11-44">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Calculated using correlation (see "</span>,</span>
<span id="cb11-45">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"&lt;a href='https://yardstick.tidymodels.org/reference/rsq.html'&gt;"</span>,</span>
<span id="cb11-46">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"documentation&lt;/a&gt;)"</span></span>
<span id="cb11-47">      )</span>
<span id="cb11-48">    ),</span>
<span id="cb11-49">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_column_labels</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rsq"</span>)</span>
<span id="cb11-50">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-51">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_footnote</span>(</span>
<span id="cb11-52">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">footnote =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Standardised using games played"</span>,</span>
<span id="cb11-53">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_stub</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">everything</span>())</span>
<span id="cb11-54">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-55">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb11-56">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">weight =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bold"</span>)),</span>
<span id="cb11-57">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_column_spanners</span>()</span>
<span id="cb11-58">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-59">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb11-60">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">weight =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bold"</span>)),</span>
<span id="cb11-61">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_row_groups</span>()</span>
<span id="cb11-62">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-63">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table_theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source_note =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Source: DFL &amp; Transfermarkt"</span>)</span></code></pre></div></div>
</details>
<div id="tbl-model-performance" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-model-performance-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;3: Performance of XGBoost Models Predicting Bundesliga Outcomes
</figcaption>
<div aria-describedby="tbl-model-performance-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="wcraectzbm" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#wcraectzbm table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#wcraectzbm thead, #wcraectzbm tbody, #wcraectzbm tfoot, #wcraectzbm tr, #wcraectzbm td, #wcraectzbm th {
  border-style: none;
}

#wcraectzbm p {
  margin: 0;
  padding: 0;
}

#wcraectzbm .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#wcraectzbm .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#wcraectzbm .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#wcraectzbm .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#wcraectzbm .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#wcraectzbm .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#wcraectzbm .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#wcraectzbm .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#wcraectzbm .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#wcraectzbm .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#wcraectzbm .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#wcraectzbm .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#wcraectzbm .gt_spanner_row {
  border-bottom-style: hidden;
}

#wcraectzbm .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#wcraectzbm .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#wcraectzbm .gt_from_md > :first-child {
  margin-top: 0;
}

#wcraectzbm .gt_from_md > :last-child {
  margin-bottom: 0;
}

#wcraectzbm .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#wcraectzbm .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#wcraectzbm .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#wcraectzbm .gt_row_group_first td {
  border-top-width: 2px;
}

#wcraectzbm .gt_row_group_first th {
  border-top-width: 2px;
}

#wcraectzbm .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#wcraectzbm .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#wcraectzbm .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#wcraectzbm .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#wcraectzbm .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#wcraectzbm .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#wcraectzbm .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#wcraectzbm .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#wcraectzbm .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#wcraectzbm .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#wcraectzbm .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#wcraectzbm .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#wcraectzbm .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#wcraectzbm .gt_left {
  text-align: left;
}

#wcraectzbm .gt_center {
  text-align: center;
}

#wcraectzbm .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#wcraectzbm .gt_font_normal {
  font-weight: normal;
}

#wcraectzbm .gt_font_bold {
  font-weight: bold;
}

#wcraectzbm .gt_font_italic {
  font-style: italic;
}

#wcraectzbm .gt_super {
  font-size: 65%;
}

#wcraectzbm .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#wcraectzbm .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#wcraectzbm .gt_indent_1 {
  text-indent: 5px;
}

#wcraectzbm .gt_indent_2 {
  text-indent: 10px;
}

#wcraectzbm .gt_indent_3 {
  text-indent: 15px;
}

#wcraectzbm .gt_indent_4 {
  text-indent: 20px;
}

#wcraectzbm .gt_indent_5 {
  text-indent: 25px;
}

#wcraectzbm .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#wcraectzbm div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>
<table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
  <thead>
    <tr class="gt_col_headings gt_spanner_row">
      <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="2" colspan="1" scope="col" id="a::stub"></th>
      <th class="gt_center gt_columns_top_border gt_column_spanner_outer" rowspan="1" colspan="2" style="font-weight: bold;" scope="colgroup" id="Evaluation Metrics">
        <div class="gt_column_spanner">Evaluation Metrics</div>
      </th>
    </tr>
    <tr class="gt_col_headings">
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="rmse">RMSE</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="rsq">R<sup>2</sup><span class="gt_footnote_marks gt_asterisk" style="white-space:nowrap;font-style:italic;font-weight:normal;line-height:0;"><sup>*</sup></span></th>
    </tr>
  </thead>
  <tbody class="gt_table_body">
    <tr class="gt_group_heading_row">
      <th colspan="3" class="gt_group_heading" style="font-weight: bold;" scope="colgroup" id="Squad Value">Squad Value</th>
    </tr>
    <tr class="gt_row_group_first"><th id="stub_1_1" scope="row" class="gt_row gt_left gt_stub">Points<span class="gt_footnote_marks" style="white-space:nowrap;font-style:italic;font-weight:normal;line-height:0;"><sup>†</sup></span></th>
<td headers="Squad Value stub_1_1 rmse" class="gt_row gt_center">0.24</td>
<td headers="Squad Value stub_1_1 rsq" class="gt_row gt_center">0.65</td></tr>
    <tr><th id="stub_1_2" scope="row" class="gt_row gt_left gt_stub">Goal Difference<span class="gt_footnote_marks" style="white-space:nowrap;font-style:italic;font-weight:normal;line-height:0;"><sup>†</sup></span></th>
<td headers="Squad Value stub_1_2 rmse" class="gt_row gt_center">0.4</td>
<td headers="Squad Value stub_1_2 rsq" class="gt_row gt_center">0.65</td></tr>
    <tr><th id="stub_1_3" scope="row" class="gt_row gt_left gt_stub">xG Difference<span class="gt_footnote_marks" style="white-space:nowrap;font-style:italic;font-weight:normal;line-height:0;"><sup>†</sup></span></th>
<td headers="Squad Value stub_1_3 rmse" class="gt_row gt_center">0.31</td>
<td headers="Squad Value stub_1_3 rsq" class="gt_row gt_center">0.58</td></tr>
    <tr class="gt_group_heading_row">
      <th colspan="3" class="gt_group_heading" style="font-weight: bold;" scope="colgroup" id="Staff Costs">Staff Costs</th>
    </tr>
    <tr class="gt_row_group_first"><th id="stub_1_4" scope="row" class="gt_row gt_left gt_stub">Points<span class="gt_footnote_marks" style="white-space:nowrap;font-style:italic;font-weight:normal;line-height:0;"><sup>†</sup></span></th>
<td headers="Staff Costs stub_1_4 rmse" class="gt_row gt_center">0.3</td>
<td headers="Staff Costs stub_1_4 rsq" class="gt_row gt_center">0.47</td></tr>
    <tr><th id="stub_1_5" scope="row" class="gt_row gt_left gt_stub">Goal Difference<span class="gt_footnote_marks" style="white-space:nowrap;font-style:italic;font-weight:normal;line-height:0;"><sup>†</sup></span></th>
<td headers="Staff Costs stub_1_5 rmse" class="gt_row gt_center">0.49</td>
<td headers="Staff Costs stub_1_5 rsq" class="gt_row gt_center">0.47</td></tr>
    <tr><th id="stub_1_6" scope="row" class="gt_row gt_left gt_stub">xG Difference<span class="gt_footnote_marks" style="white-space:nowrap;font-style:italic;font-weight:normal;line-height:0;"><sup>†</sup></span></th>
<td headers="Staff Costs stub_1_6 rmse" class="gt_row gt_center">0.36</td>
<td headers="Staff Costs stub_1_6 rsq" class="gt_row gt_center">0.44</td></tr>
  </tbody>
  <tfoot class="gt_sourcenotes">
    <tr>
      <td class="gt_sourcenote" style="text-align: left;" colspan="3">Source: DFL &amp; Transfermarkt</td>
    </tr>
  </tfoot>
  <tfoot class="gt_footnotes">
    <tr>
      <td class="gt_footnote" style="text-align: left;" colspan="3"><span style="white-space:nowrap;font-style:normal;font-weight:normal;line-height:0;">(*)</span> Calculated using correlation (see <a href="https://yardstick.tidymodels.org/reference/rsq.html">documentation</a>)</td>
    </tr>
    <tr>
      <td class="gt_footnote" style="text-align: left;" colspan="3"><span style="white-space:nowrap;font-style:normal;font-weight:normal;line-height:0;">(†)</span> Standardised using games played</td>
    </tr>
  </tfoot>
</table>
</div>
</div>
</div>
</figure>
</div>
</div>
<p>Table&nbsp;3 shows a similar pattern to the correlations in Table&nbsp;2. The squad value models consistently outperform the staff costs models across both metrics, especially R<sup>2</sup>. It’s worth noting that the models are tuned on RMSE, so the variance in R<sup>2</sup> across the two sets of models is possibly a function of this. However, there is a sizable increase in RMSE, too.</p>
<p>The consistency of this finding, plus the evidence in Table&nbsp;1 that the difference between squad value and staff costs is partially a function of team quality, suggests that squad value has some performance bias baked in. I don’t think this invalidates squad values as a proxy for investment in the squad, but it does demonstrate a limitation in this approach.</p>
</section>
</section>
<section id="how-reliable-are-squad-values" class="level2">
<h2 class="anchored" data-anchor-id="how-reliable-are-squad-values">How Reliable are Squad Values?</h2>
<p>There is plenty of research that demonstrates the reliability of Transfermarkt’s player market values (and by extension squad values) across a variety of contexts <span class="citation" data-cites="herm2014 muller2017 prockl2018 smith2021 coates2022 james2022">(Herm et al. 2014; Müller et al. 2017; Prockl and Frick 2018; Smith 2021; Coates and Parshakov 2022; James 2022)</span>. They are a decent approximation of player values on an open market <span class="citation" data-cites="transfermarkt2021">(Transfermarkt 2021)</span>, which makes them pretty handy for several different use cases. I think the evidence shown in this blog post suggests that a proxy for investment in squads is one of those use cases, but that conclusion does come with some caveats.</p>
<p>Given how <a href="https://www.transfermarkt.com/market-value-definition/thread/forum/357/thread_id/3433">Transfermarkt’s values are estimated</a>, I think there will obviously be some performance bias. Historic squad values are a snapshot from previous seasons, and they appear to be an average across the season<sup>9</sup>. As a consequence, adjustments to player values due to performance will have some impact on squad values.</p>
<p>It’s also worth noting that I’m using a small sample of data limited only to the Bundesliga<sup>10</sup>, which reduces how much we can infer from this. Evidence shows that player values vary in predictive value by league <span class="citation" data-cites="muller2017 coates2022">(Müller et al. 2017; Coates and Parshakov 2022)</span>, so findings based on a handful of seasons in a single league should be understood within their limited scope.</p>
<p>Still, I think the results support the idea that Transfermarkt’s squad values are a reasonable proxy for squad spending. Regarding my model specifically, I think the structure of the model should help negate some of these issues, particularly the effects of partial pooling. Generally, though, squad value and staff costs are almost perfectly correlated. While the squad value models are consistently better, I don’t think they are so different that it invalidates using squad value as a proxy.</p>
<p>Instead, I think it is something to be aware of if using squad values in this context. Every approach will have limitations, but if you can identify them, discuss them in your analysis, and even point to the specific ways they impact your model, you should be in a good place. With squad values, better the devil you know.</p>
</section>




<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Many thanks to <a href="https://bsky.app/profile/ansgarw.bsky.social">Ansgar Wolsing</a> for pointing me to the staff costs data I used in this blog post.</p>
<p>Preview image by <a href="https://unsplash.com/@tobiasrehbein">Tobias Rehbein</a> on <a href="https://unsplash.com/photos/a-soccer-ball-sitting-on-top-of-a-lush-green-field-CZ_HwDtvEus">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>



</div></section><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-coates2022" class="csl-entry">
Coates, Dennis, and Petr Parshakov. 2022. <span>“The Wisdom of Crowds and Transfer Market Values.”</span> <em>European Journal of Operational Research</em> 301 (2): 523–34.
</div>
<div id="ref-herm2014" class="csl-entry">
Herm, Steffen, Hans-Markus Callsen-Bracker, and Henning Kreis. 2014. <span>“When the Crowd Evaluates Soccer Players’ Market Values: Accuracy and Evaluation Attributes of an Online Community.”</span> <em>Sport Management Review</em> 17 (4): 484–92. <a href="https://www.sciencedirect.com/science/article/abs/pii/S144135231300096X">https://www.sciencedirect.com/science/article/abs/pii/S144135231300096X</a>.
</div>
<div id="ref-james2022" class="csl-entry">
James, Stuart. 2022. <span>“How Do You Value a Player?”</span> <em>The Athletic</em>. <a href="https://www.nytimes.com/athletic/3085749/2022/01/27/premier-league-how-do-you-value-a-player/">https://www.nytimes.com/athletic/3085749/2022/01/27/premier-league-how-do-you-value-a-player/</a>.
</div>
<div id="ref-muller2017" class="csl-entry">
Müller, Oliver, Alexander Simons, and Markus Weinmann. 2017. <span>“Beyond Crowd Judgments: Data-Driven Estimation of Market Value in Association Football.”</span> <em>European Journal of Operational Research</em> 263 (2): 611–24. <a href="https://www.sciencedirect.com/science/article/pii/S0377221717304332">https://www.sciencedirect.com/science/article/pii/S0377221717304332</a>.
</div>
<div id="ref-prockl2018" class="csl-entry">
Prockl, Franziska, and Bernd Frick. 2018. <span>“Information Precision in Online Communities: Player Valuations on <span class="nocase">www.transfermarkt.de</span>.”</span> <em>International Journal of Sport Finance</em> 13 (4): 319–35. <a href="https://d-nb.info/124512143X/34">https://d-nb.info/124512143X/34</a>.
</div>
<div id="ref-smith2021" class="csl-entry">
Smith, Rory. 2021. <span>“How Transfermarkt Helps Determine the Value of Soccer Players.”</span> <em>New York Times</em>. <a href="https://www.nytimes.com/2021/08/12/sports/soccer/soccer-football-transfermarkt.html">https://www.nytimes.com/2021/08/12/sports/soccer/soccer-football-transfermarkt.html</a>.
</div>
<div id="ref-transfermarkt2021" class="csl-entry">
Transfermarkt. 2021. <em>Transfermarkt Market Value Board - Market Value Definition</em>. Transfermarkt.com. <a href="https://www.transfermarkt.com/market-value-definition/thread/forum/357/thread_id/3433">https://www.transfermarkt.com/market-value-definition/thread/forum/357/thread_id/3433</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>Players and playing staff will make up the majority of staff costs for all clubs, and I think it is reasonable to assume that non-playing staff costs will be directly related to playing staff costs (bigger teams like Bayern Munich will have more non-playing employees).↩︎</p></li>
<li id="fn2"><p>It is actually illegal to tell me I’m wrong.↩︎</p></li>
<li id="fn3"><p>Frankfurt were one of the teams reporting their costs for the financial year, but in 2023, they switched to reporting costs over a season. To line their reports up, this meant the 2023 report is just the costs for the first six months of 2023 (so that the following season is on the correct schedule).↩︎</p></li>
<li id="fn4"><p>The figures published in 2024 refer to the 2022/23 season, but the reports are organised by division, with all teams in the Bundesliga in the 2024/25 season in one report and the same for the 2. Bundesliga. For the most part, this was just an inconvenience. In 2022/23, however, Paderborn were relegated from the Bundesliga, followed by another relegation down to the 3. Liga in 2023/24. The trouble is, while the top two tiers in Germany are governed by the DFL, the third tier is governed by the DFB. Paderborn’s consecutive relegations mean that they aren’t included in these reports. It’s despicable. The real victim here is me.↩︎</p></li>
<li id="fn5"><p>I also looked at differences over time. There was minimal variance from season to season, though 2017/18 was considerably lower than others, and I concluded that time isn’t relevant.↩︎</p></li>
<li id="fn6"><p>My main reason for filtering the data this way was to reduce the list of clubs included and make the table a little smaller. It also removes the noisiest observations (though all are obviously small samples since the maximum seasons are just six).↩︎</p></li>
<li id="fn7"><p>Some minor differences exist between these models and those I fit in my earlier blog post. These differences are primarily due to the flexibility of the original model’s multilevel structure, which allowed me to do a little more.↩︎</p></li>
<li id="fn8"><p>I used this post as an excuse to play around with <a href="https://future.futureverse.org"><strong>future</strong></a> and <a href="https://furrr.futureverse.org"><strong>furrr</strong></a>, so I ended up going to greater lengths to tune the models, but only as a way to make better use of parallel processing.↩︎</p></li>
<li id="fn9"><p>I’m unsure how historic squad values are derived, but they don’t appear to align with values at a specific point in the season, so I assume they are an average. A workaround would be to recreate preseason squad values by scraping Transfermarkt’s player values over time (shout out to <a href="https://johnspacemuller.com">John Muller</a> for pointing this one out to me).↩︎</p></li>
<li id="fn10"><p>And while I am confident that staff and squad costs will be roughly equivalent, this adds another layer of potential noise.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2025" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2025. <span>“Testing Transfermarkt’s Squad Market
Values.”</span> May 11. <a href="https://paulrjohnson.net/blog/2025-05-11-testing-transfermarkt-squad-values/">https://paulrjohnson.net/blog/2025-05-11-testing-transfermarkt-squad-values/</a>.
</div></div></section></div> ]]></description>
  <category>Football Analytics</category>
  <category>Statistics</category>
  <category>Machine Learning</category>
  <category>R</category>
  <guid>https://paulrjohnson.net/blog/2025-05-11-testing-transfermarkt-squad-values/</guid>
  <pubDate>Sun, 11 May 2025 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2025-05-11-testing-transfermarkt-squad-values/ball.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>How to Write About Data Science (Effectively)</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2025-04-14-writing-data-science/</link>
  <description><![CDATA[ 





<p>Many data scientists will have been kids who excelled at math throughout school. Some would have viewed writing with the fear that the rest of the world views their beloved numbers. I’m not like most data scientists, though. I’m much dumber. My instinct is to express myself using words instead of fancy letters, and as someone who struggled with math in school, I am a little more familiar with the intimidation many feel when faced with notation. I’ve always enjoyed writing, and I think I’m at least pretty good at it for someone in a field full of number nerds. I’m the bridge between the nerds and the normies. I have successfully spun my own stupidity as a niche.</p>
<p>This post is intended to offer some tips for writing about data science, conceding my only competitive advantage in the process. I am not arrogant enough to think I have anything to offer to a general audience<sup>1</sup>, but I hope I can give some valuable advice to other data scientists. I will focus on the approach rather than the technicalities of writing about data science. The technical elements of good writing remain consistent across context and domain, so I will defer to the subject matter experts on this<sup>2</sup>.</p>
<p>Everything that follows is neither definitive nor authoritative. It may even be nonsense. You might be right if you think anything I’ve said here is wrong or stupid. This is only intended to share some of what has helped me become a better writer. It’s important to remember I’m just some dumb bozo on the Internet, and whatever you do, don’t be mad at me.</p>
<section id="writing-the-right-way" class="level2">
<h2 class="anchored" data-anchor-id="writing-the-right-way">Writing the Right Way</h2>
<blockquote class="blockquote">
<p>If you’re thinking without writing, you only think you’re thinking. <br><br> - Leslie Lamport</p>
</blockquote>
<p>I really like this quote<sup>3</sup>. It’s one of those pithy things you hear people say. They’re usually nonsense, but I think it is true in this case. It’s a sentiment shared by <a href="https://www.youtube.com/watch?v=aFwVf5a3pZM&amp;t=551s">Larry McEnerney</a> in his talk on academic writing at the University of Chicago<sup>4</sup>.</p>
<p>Writing is essential to good science because it helps you organise your thoughts, identify the weaknesses in your argument, and turn disparate, muddled thoughts into something resembling a coherent idea. The same benefits to thinking also apply to learning, which is a big reason for maintaining this blog. I build on what I know when I have to write it down for others. Partly because I don’t want to make a fool of myself but also because I want to do a good job. And if you are going to write? Well, you might as well do it well, right?</p>
<section id="writing-is-not-an-afterthought" class="level3">
<h3 class="anchored" data-anchor-id="writing-is-not-an-afterthought">Writing is Not an Afterthought</h3>
<p>There are plenty of excellent data scientists who might struggle as writers. It’s natural to prioritise the skills you excel at—such as math, statistics, or programming—and when those skills become a career, it becomes a strong positive feedback loop. Writing can quickly become an afterthought.</p>
<p>Even so, communicating your findings shouldn’t be a lower priority than the findings themselves. Instead of treating the writing stage as the means to an end, treat writing as central to everything you do. If you want to improve your writing, afford it the same weight you do to the other parts of the process and treat it as a part of the journey and a part of the fun. A well-written analysis is just as satisfying as the analysis itself, and a scientist has many tools at their disposal for illuminating their writing<sup>5</sup>.</p>
<p>If you care about your writing like you care about your analysis, you’ll invest a similar amount of time iterating over the results to maximise the performance. <span class="citation" data-cites="zinsser2001">Zinsser (2001)</span> talks about the time he invests in his writing, pouring over every sentence, reading and rereading passages just to identify and replace the word that makes it feel clunky, and playing with draft after draft so that the end result can be the best version of his work. Data scientists will recognise this process. You apply it to the modelling stage. You should also do it with your writing.</p>
</section>
<section id="simple-is-smart" class="level3">
<h3 class="anchored" data-anchor-id="simple-is-smart">Simple is Smart</h3>
<p>William Zinsser <span class="citation" data-cites="zinsser2001">(2001)</span> lists “four articles of faith” in <em>On Writing Well</em>: clarity, simplicity, brevity, and humanity<sup>6</sup>. I think these are excellent guiding principles for writing that is accessible and engaging.</p>
<p>First and foremost, the goal should be to distil complex ideas as simply as possible. Data science is complicated. Why make it more difficult by overcomplicating how you communicate about it? The Pulitzer Prize winner Cormac McCarthy recommends “minimalism to achieve clarity” <span class="citation" data-cites="savage2019">(Savage and Yeh 2019)</span>. He advises writers to constantly ask themselves whether words and punctuation marks need to be there, removing anything superfluous. He also suggests that simple, short sentences are effective when communicating about science because they help the reader focus on the key message. Finally, perhaps his best advice relates to theme and structure, recommending a focus on two or three points you want the reader to take away from reading your work<sup>7</sup>.</p>
<p>I think honest intent is vital, too. Write to show the reader something cool, teach people about an interesting method, or play around with a fun new tool. There are lots of good reasons for writing about data science. But don’t write to demonstrate your intelligence. Going in looking to prove how smart you are will encourage you to overcomplicate things. Complexity is a distraction. “Jargon is the enemy of clarity” <span class="citation" data-cites="plaxco2010">(Plaxco 2010)</span>. Data science is complicated enough, so why make it harder for your readers by taking the scenic route?</p>
<p>There is nothing wrong with wanting to give a good impression. My natural state is the class clown, so I’m more concerned that readers laugh at my dumb jokes than think I’m a clever little boy. But I still don’t want everyone to think I’m talking nonsense. I think it’s important that these goals are secondary, though. Writing about a complex subject with clarity, simplicity, brevity, and humanity will achieve these secondary goals. Readers will be a lot more impressed if you can do this.</p>
<p>So much of this advice ultimately comes down to making your audience a central consideration. Write for yourself, but communicate with your readers. Write about subjects you are passionate about, methods you love, or study questions to which the answer interests you. But when you write, do so with close consideration to who will read your work, and adjust your approach to make it as accessible and engaging as possible. That doesn’t mean that your work can’t be complex. There is plenty of room for deep, complex analyses. But write in simple terms. Write in terms that allow any reader to at least read the words and understand the sentence they just read. If they do not have the necessary prerequisite knowledge to understand what it all means, that’s not on you. But it shouldn’t be your writing that stops someone from following along.</p>
<p>The reality is that data science is not always straightforward, and there are plenty of times when it won’t be possible to write something in simple terms. However, I think the goal should always be to try and simplify what you’re saying without losing its meaning. How far is that? It’s hard to say, and the answer will always vary based on subject, context, and audience. Still, simplicity is generally a good goal for writing, especially when writing about data science.</p>
</section>
<section id="practice-makes-perfect-less-bad" class="level3">
<h3 class="anchored" data-anchor-id="practice-makes-perfect-less-bad">Practice Makes <del>Perfect</del> Less Bad</h3>
<p>The most important step you can take in improving your writing is to write. This blog post forced me to think harder about writing as a craft; otherwise, my writing has improved simply through practice. I’ve spent many years writing for a variety of audiences, including writing a lot of admittedly relatively trivial<sup>8</sup> articles for the Borussia Dortmund fan site, <a href="https://fearthewall.com">Fear the Wall</a>, and this has helped me find and hone my voice without giving it much thought. This experience has made it so much easier for me now.</p>
<p>It’s a little cliché, but the best advice for improving your writing is to carve out the time to write regularly. Like any craft, getting better at writing requires doing more of it. The more you do it, the easier it comes, and the easier it comes, the more you can try to figure out what works for you and what doesn’t. With practice, you will get more comfortable writing in your own voice, making your writing more approachable. This idea is perhaps undervalued when writing about data science, particularly in professional settings. There is still value in finding a consistent voice when communicating findings at work, in academic research, and even (and especially) for your silly little blog posts. Consistency makes your writing flow better, familiarity will make your readers’ lives easier, and a unique voice is more pleasing and engaging.</p>
<p>Your voice will differ from my voice. My voice is stupid. I’m a profoundly unserious person. You might not be that person, and that’s okay (good, even). Finding your voice is essential in your writing journey<sup>9</sup>. Explore what works for you, what you enjoy, and what feels like an authentic representation of your personality.</p>
<p>Many excellent writers stress the importance of writing like a human being <span class="citation" data-cites="zinsser2001">(Zinsser 2001)</span> or writing like you talk <span class="citation" data-cites="graham2015">(Graham 2015)</span>. How do you communicate with people when you are comfortable? How would you explain something to a friend who likes you enough not to disown you for talking at them about data science? This is how you should write. The closer you get to writing like your spoken voice, the closer you are to sounding like an actual human using everyday words in a regular order. This will also make your work much easier to follow. Cormac McCarthy argues that “spoken language and common sense” are the best guides when writing your first draft because it is more important that the reader can understand you than that you write to the letter of the grammatical law <span class="citation" data-cites="savage2019">(Savage and Yeh 2019)</span>. And Cormac McCarthy knows a lot more about writing than I do.</p>
<p>Getting good at writing is often about practice, but it’s also about challenging yourself to improve, taking the time and effort to think about your writing and where it does and does not work, and considering how you can grow as a writer. Writing more will help you improve.</p>
</section>
</section>
<section id="final-thoughts" class="level2">
<h2 class="anchored" data-anchor-id="final-thoughts">Final Thoughts</h2>
<p>Writing is hard. But it can also be fulfilling when you get it right. I’m wary of seeming like the breezy hobbyist claiming that writing is a joyous experience, knowing that the professionals will read this and laugh at me<sup>10</sup>. Still, I think this point is worth reiterating because I get the sense it doesn’t get recognised when talking about writing about data science (or science generally). As much as a clean, well-executed analysis is satisfying, clear and concise findings can make your work shine.</p>
<p>You need to start writing to find those nuggets of joy. To whatever extent I am a good writer, it is because I have plenty of practice. I have developed my voice and learned how to achieve what I want with words. That, and the lower standard expected of a data scientist trying to communicate with words instead of numbers. Whatever your abilities, write honestly, with humanity and some humility. If your intentions are good but your writing is terrible, the latter can at least be fixed with practice.</p>
</section>




<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Preview image by <a href="https://unsplash.com/@patrickian4">Patrick Fore</a> on <a href="https://unsplash.com/photos/person-holding-white-and-black-typewriter-59lC6TgZAbQ">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>



</div></section><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-alexander2023" class="csl-entry">
Alexander, Rohan. 2023. <em>Telling Stories with Data: With Applications in r</em>. Chapman; Hall/CRC. <a href="https://tellingstorieswithdata.com">https://tellingstorieswithdata.com</a>.
</div>
<div id="ref-gopen1990" class="csl-entry">
Gopen, George D, and Judith A Swan. 1990. <span>“The Science of Scientific Writing.”</span> <em>American Scientist</em> 78 (6): 550–58. <a href="https://www.popecol.org/wp-content/uploads/2020/09/Gopen-Swan-1990.pdf">https://www.popecol.org/wp-content/uploads/2020/09/Gopen-Swan-1990.pdf</a>.
</div>
<div id="ref-graham2015" class="csl-entry">
Graham, Paul. 2015. <span>“Write Like You Talk.”</span> <em>Paul Graham</em>. <a href="https://paulgraham.com/talk.html">https://paulgraham.com/talk.html</a>.
</div>
<div id="ref-graham2024" class="csl-entry">
Graham, Paul. 2024. <span>“Writes &amp; Write-Nots.”</span> <em>Paul Graham</em>. <a href="https://paulgraham.com/writes.html">https://paulgraham.com/writes.html</a>.
</div>
<div id="ref-king2020" class="csl-entry">
King, Stephen. 2020. <em>On Writing: A Memoir of the Craft</em>. Scribner.
</div>
<div id="ref-plaxco2010" class="csl-entry">
Plaxco, Kevin W. 2010. <span>“The Art of Writing Science.”</span> <em>Protein Science</em> 19 (12): 2261. <a href="https://onlinelibrary.wiley.com/doi/10.1002/pro.514">https://onlinelibrary.wiley.com/doi/10.1002/pro.514</a>.
</div>
<div id="ref-savage2019" class="csl-entry">
Savage, Van, and Pamela Yeh. 2019. <span>“Novelist Cormac McCarthy’s Tips on How to Write a Great Science Paper.”</span> <em>Nature</em> 574 (7777): 441–43. <a href="https://gwern.net/doc/science/2019-savage.pdf">https://gwern.net/doc/science/2019-savage.pdf</a>.
</div>
<div id="ref-strunk1999" class="csl-entry">
Strunk, William, and Elwyn Brooks White. 1999. <em>The Elements of Style</em>. Pearson. <a href="https://archive.org/details/TheElementsOfStyle4thEdition/">https://archive.org/details/TheElementsOfStyle4thEdition/</a>.
</div>
<div id="ref-zinsser2001" class="csl-entry">
Zinsser, William Knowlton. 2001. <em>On Writing Well: The Classic Guide to Writing Nonfiction</em>. Quill/A Harper Collins Books.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>For general advice on becoming a better writer, you are probably better off seeking the counsel of some actual professional writers. I’d recommend William Zinsser’s <span class="citation" data-cites="zinsser2001">(2001)</span> <em>On Writing Well</em> and Stephen King’s <span class="citation" data-cites="king2020">(2020)</span> <em>On Writing</em>.↩︎</p></li>
<li id="fn2"><p>Regarding the technical aspects of writing, I’d highly recommend William Strunk &amp; E.B. White’s <span class="citation" data-cites="strunk1999">(1999)</span> <em>Elements of Style</em> and George Gopen &amp; Judith Swan’s <span class="citation" data-cites="gopen1990">(1990)</span> <em>The Science of Scientific Writing</em>.↩︎</p></li>
<li id="fn3"><p>I tried to track down a proper source for this quote. I could only find it attributed to Leslie Lamport, but not where he initially said it. I discovered it via Paul Graham’s <a href="https://paulgraham.com/writes.html"><em>Writes and Write-Nots</em></a> <span class="citation" data-cites="graham2024">(2024)</span>.↩︎</p></li>
<li id="fn4"><p>I have <a href="https://get-goalside-newsletter-archive.beehiiv.com">Mark Thompson</a> to thank for this one, which he shared in a <a href="https://get-goalside-newsletter-archive.beehiiv.com/p/bloggings-cool-again">recent post</a>.↩︎</p></li>
<li id="fn5"><p>The writing itself is only one component. Analytics gives you a few other tools that are not always available to other writers. Rohan Alexander’s <span class="citation" data-cites="alexander2023">(2023)</span> <em>Telling Stories With Data</em> goes into detail about this stuff in the Communication section of the book. If your audience is comfortable with notation, there is no more succinct and precise way to express your model, and causal diagrams are an excellent way to lay out your theory intuitively and visually. The most powerful tool is data visualisation. If a picture is worth a thousand words, surely a plot is worth at least a couple hundred?↩︎</p></li>
<li id="fn6"><p>This section focuses on the first three principles, but humanity is no less critical. Writing with humanity means putting human beings at the centre of your writing. Tell human stories, discuss what you love about a particular topic, and highlight your work’s effects on real people. Speak to readers in terms that make them want to keep reading.↩︎</p></li>
<li id="fn7"><p>McCarthy focuses on academic writing, but this approach can be applied to writing in many contexts. It will help when dealing with a complex topic, as often in data science.↩︎</p></li>
<li id="fn8"><p>I think the trivial stuff was most helpful in improving my writing. When tasked with writing several hundred words about some absolutely abysmal game I had nothing to say about, I started experimenting. In those moments of desperation, I found a style that worked for me.↩︎</p></li>
<li id="fn9"><p>Your voice doesn’t have to be serious for your work to be taken seriously. There’s nothing wrong with having fun. Suppose you read my posts and are unconvinced that being a silly goose does not hurt your legitimacy. In that case, I’d point to <a href="https://djnavarro.net">Danielle Navarro</a> and <a href="https://dansblog.netlify.app">Dan Simpson</a> as counters to your understandable reticence. Both are very engaging writers and don’t take themselves too seriously. Both are also excellent at this stuff and are bonafide experts.↩︎</p></li>
<li id="fn10"><p>Don’t laugh at me on the Internet. That’s illegal.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2025" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2025. <span>“How to Write About Data Science
(Effectively).”</span> April 14. <a href="https://paulrjohnson.net/blog/2025-04-14-writing-data-science/">https://paulrjohnson.net/blog/2025-04-14-writing-data-science/</a>.
</div></div></section></div> ]]></description>
  <category>Writing</category>
  <category>Scientific Communication</category>
  <guid>https://paulrjohnson.net/blog/2025-04-14-writing-data-science/</guid>
  <pubDate>Mon, 14 Apr 2025 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2025-04-14-writing-data-science/typewriter.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Predicting Bob’s Burgers Episode Ratings</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/</link>
  <description><![CDATA[ 





<div id="setup" class="cell" data-execution_count="1">
<details class="code-fold">
<summary>Setup Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import packages</span></span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> optuna</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> textwrap</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-7"></span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> great_tables <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> GT</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> plotnine <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> (</span>
<span id="cb1-10">    aes,</span>
<span id="cb1-11">    element_blank,</span>
<span id="cb1-12">    element_line,</span>
<span id="cb1-13">    element_text,</span>
<span id="cb1-14">    facet_wrap,</span>
<span id="cb1-15">    geom_bar,</span>
<span id="cb1-16">    geom_histogram,</span>
<span id="cb1-17">    geom_hline,</span>
<span id="cb1-18">    geom_point,</span>
<span id="cb1-19">    geom_smooth,</span>
<span id="cb1-20">    ggplot,</span>
<span id="cb1-21">    labs,</span>
<span id="cb1-22">    scale_x_continuous,</span>
<span id="cb1-23">    scale_fill_gradient,</span>
<span id="cb1-24">    theme,</span>
<span id="cb1-25">    theme_minimal,</span>
<span id="cb1-26">    theme_set,</span>
<span id="cb1-27">    theme_update,</span>
<span id="cb1-28">)</span>
<span id="cb1-29"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.base <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> BaseEstimator, TransformerMixin</span>
<span id="cb1-30"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.compose <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> ColumnTransformer</span>
<span id="cb1-31"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.dummy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> DummyRegressor</span>
<span id="cb1-32"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.ensemble <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> (</span>
<span id="cb1-33">    ExtraTreesRegressor,</span>
<span id="cb1-34">    GradientBoostingRegressor,</span>
<span id="cb1-35">    RandomForestRegressor,</span>
<span id="cb1-36">)</span>
<span id="cb1-37"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.experimental <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> enable_iterative_imputer</span>
<span id="cb1-38"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.impute <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> IterativeImputer</span>
<span id="cb1-39"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LinearRegression</span>
<span id="cb1-40"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_scorer, root_mean_squared_error</span>
<span id="cb1-41"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> cross_val_score, KFold, train_test_split</span>
<span id="cb1-42"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.pipeline <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Pipeline</span>
<span id="cb1-43"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> FunctionTransformer, OneHotEncoder</span>
<span id="cb1-44"></span>
<span id="cb1-45"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import data</span></span>
<span id="cb1-46">bobs_burgers <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb1-47">    pd.read_csv(</span>
<span id="cb1-48">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://raw.githubusercontent.com/rfordatascience/tidytuesday/"</span></span>
<span id="cb1-49">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"master/data/2024/2024-11-19/episode_metrics.csv"</span></span>
<span id="cb1-50">    )</span>
<span id="cb1-51">    .merge(</span>
<span id="cb1-52">        pd.read_csv(</span>
<span id="cb1-53">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://raw.githubusercontent.com/poncest/bobsburgersR/refs/"</span></span>
<span id="cb1-54">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"heads/main/data-raw/IMDb_Wikipedia_Bobs_Burgers_Data_Clean.csv"</span></span>
<span id="cb1-55">        ),</span>
<span id="cb1-56">        on<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"season"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"episode"</span>],</span>
<span id="cb1-57">    )</span>
<span id="cb1-58">    .assign(</span>
<span id="cb1-59">        wikipedia_directed_by<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_directed_by"</span>]</span>
<span id="cb1-60">        .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.replace(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">\b</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">Boohwan</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">\b</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">?!</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> Lim</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">)</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Boohwan Lim"</span>, regex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb1-61">        .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.replace(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Brian LoSchiavo"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Brian Loschiavo"</span>)</span>
<span id="cb1-62">        .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.replace(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mathew Long"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Matthew Long"</span>)</span>
<span id="cb1-63">    )</span>
<span id="cb1-64">    .assign(</span>
<span id="cb1-65">        wikipedia_written_by<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_written_by"</span>]</span>
<span id="cb1-66">        .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.replace(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Teleplay by : "</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>)</span>
<span id="cb1-67">        .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.replace(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Story by : "</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" &amp; "</span>)</span>
<span id="cb1-68">        .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.replace(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lizzie Molyneux-Logelin"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lizzie Molyneux"</span>)</span>
<span id="cb1-69">        .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.replace(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">r"</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">\b</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">Lizzie</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">\b</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">?!</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> Molyneux</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">)</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lizzie Molyneux"</span>, regex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb1-70">    )</span>
<span id="cb1-71">    .pipe(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: df.astype({col: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"category"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> col <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> df.select_dtypes(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"object"</span>)}))</span>
<span id="cb1-72">)</span>
<span id="cb1-73"></span>
<span id="cb1-74"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set plot theme</span></span>
<span id="cb1-75">theme_set(theme_minimal(base_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, base_family<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>))</span>
<span id="cb1-76">theme_update(</span>
<span id="cb1-77">    panel_grid_major<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_line(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#e5e5e5"</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb1-78">    panel_grid_minor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_blank(),</span>
<span id="cb1-79">    panel_spacing_x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>,</span>
<span id="cb1-80">    panel_spacing_y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>,</span>
<span id="cb1-81">    axis_title_x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_text(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#4d4d4d"</span>, margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"t"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>}, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>),</span>
<span id="cb1-82">    axis_title_y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_text(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#4d4d4d"</span>, margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"r"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>}, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>),</span>
<span id="cb1-83">    axis_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_text(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#7f7f7f"</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>),</span>
<span id="cb1-84">    axis_text_x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_text(angle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, vjust<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, hjust<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.75</span>),</span>
<span id="cb1-85">    axis_ticks<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_line(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#e5e5e5"</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>),</span>
<span id="cb1-86">    axis_ticks_length<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb1-87">    legend_position<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"top"</span>,</span>
<span id="cb1-88">    legend_title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_blank(),</span>
<span id="cb1-89">    legend_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_text(</span>
<span id="cb1-90">        size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, va<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>, margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"t"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"r"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"b"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"l"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>}</span>
<span id="cb1-91">    ),</span>
<span id="cb1-92">    legend_box_margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb1-93">    legend_key_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>,</span>
<span id="cb1-94">    legend_key_spacing<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>,</span>
<span id="cb1-95">    plot_title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_text(</span>
<span id="cb1-96">        ha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>, family<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"t"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"b"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>}</span>
<span id="cb1-97">    ),</span>
<span id="cb1-98">    plot_subtitle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_text(</span>
<span id="cb1-99">        ha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>,</span>
<span id="cb1-100">        color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#4d4d4d"</span>,</span>
<span id="cb1-101">        family<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>,</span>
<span id="cb1-102">        lineheight<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>,</span>
<span id="cb1-103">        size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">11.5</span>,</span>
<span id="cb1-104">        margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"t"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"r"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"b"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"l"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>},</span>
<span id="cb1-105">    ),</span>
<span id="cb1-106">    plot_caption<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_text(</span>
<span id="cb1-107">        color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#7f7f7f"</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>, ha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"right"</span>, margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"t"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"r"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"b"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"l"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>}</span>
<span id="cb1-108">    ),</span>
<span id="cb1-109">    strip_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_text(size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"t"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"r"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"b"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"l"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>}),</span>
<span id="cb1-110">)</span>
<span id="cb1-111"></span>
<span id="cb1-112"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># suppress all optuna logging outputs</span></span>
<span id="cb1-113">optuna.logging.set_verbosity(optuna.logging.CRITICAL)</span>
<span id="cb1-114"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># to switch back - optuna.logging.set_verbosity(optuna.logging.INFO)</span></span></code></pre></div></div>
</details>
</div>
<p>Biologists have been wrestling with the challenge of predicting the structure of proteins for over 50 years. Doing so would enable scientists to better understand diseases and accelerate the development of medications <span class="citation" data-cites="heaven2022">(Heaven 2022)</span>. Experimental methods for predicting protein structures can be arduous, proving inadequate for predicting the structure of the over 200 million proteins discovered in nature <span class="citation" data-cites="service2020">(Service 2020)</span>. On the other hand, the performance of computational methods fell short of the experimental. That was until DeepMind’s <a href="https://deepmind.google/technologies/alphafold/">AlphaFold2</a> was released at CASP14 <span class="citation" data-cites="jumper2021">(<span class="nocase">Jumper et al.</span> 2021)</span>. DeepMind combined a vast repository of training data from the <a href="https://www.wwpdb.org">Protein Data Bank</a> with innovations in deep learning and immense computational resources, achieving landmark performance and solving one of science’s grand challenges.</p>
<p>AlphaFold is a testament to the potential value created by combining massive volumes of data and computational power (when incentives align and intentions are good). The right data can help us solve all kinds of problems, from predicting protein structures to less grand but no less important issues, such as predicting the IMDb user ratings of Bob’s Burgers episodes.</p>
<p>While the big brains at the world’s best universities are busy trying to change the world, I’m creating models no one needs or asks for. I will make a machine learning model that predicts IMDb user ratings for Bob’s Burgers episodes, using features that summarise the episode (episode and season number, date aired, writer, director, etc.) and metrics that describe the dialogue in the episode itself, seeing how far I can stretch the limited sample size.</p>
<p>I don’t know what the TV equivalent is to “football isn’t played on a spreadsheet,” but by the end of this post, I hope everyone is so mad they are telling me to “watch the <del>games</del> TV.”</p>
<section id="data-exploration" class="level2">
<h2 class="anchored" data-anchor-id="data-exploration">Data Exploration</h2>
<p>The Bob’s Burgers data comes from Week 47 of 2024’s <a href="https://github.com/rfordatascience/tidytuesday/tree/main/data/2024/2024-11-19">TidyTuesday</a>. Most of the data is originally from <a href="https://stevenponce.netlify.app">Steven Ponce</a>’s <a href="https://github.com/poncest/bobsburgersR"><code>bobsburgersR</code></a> R package, including many self-explanatory features that describe episode details. But the TidyTuesday data also includes dialogue metrics that are not as clear. Table&nbsp;1 below defines the six dialogue metrics in the dataset.</p>
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">(</span>
<span id="cb2-2">    pd.DataFrame(</span>
<span id="cb2-3">        {</span>
<span id="cb2-4">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Features"</span>: [</span>
<span id="cb2-5">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dialogue_density"</span>,</span>
<span id="cb2-6">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"avg_length"</span>,</span>
<span id="cb2-7">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sentiment_variance"</span>,</span>
<span id="cb2-8">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"unique_words"</span>,</span>
<span id="cb2-9">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"question_ratio"</span>,</span>
<span id="cb2-10">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"exclamation_ratio"</span>,</span>
<span id="cb2-11">            ],</span>
<span id="cb2-12">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Description"</span>: [</span>
<span id="cb2-13">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The number of non-blank lines in this episode."</span>,</span>
<span id="cb2-14">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The average number of characters (technically codepoints) per line "</span></span>
<span id="cb2-15">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"of dialogue."</span>,</span>
<span id="cb2-16">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The variance in the numeric AFINN sentiment of words in this episode."</span>,</span>
<span id="cb2-17">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The number of unique lowercase words in this episode."</span>,</span>
<span id="cb2-18">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The proportion of lines of dialogue that contain at least one "</span></span>
<span id="cb2-19">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"question mark ('?')."</span>,</span>
<span id="cb2-20">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The proportion of lines of dialogue that contain at least one "</span></span>
<span id="cb2-21">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"exclamation point ('!')."</span>,</span>
<span id="cb2-22">            ],</span>
<span id="cb2-23">        }</span>
<span id="cb2-24">    ).pipe(</span>
<span id="cb2-25">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: (</span>
<span id="cb2-26">            GT(df).tab_source_note(source_note<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span>)</span>
<span id="cb2-27">        )</span>
<span id="cb2-28">    )</span>
<span id="cb2-29">)</span></code></pre></div></div>
</details>
<div id="tbl-dialogue-metrics" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-dialogue-metrics-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Bob’s Burgers Episode Dialogue Metrics
</figcaption>
<div aria-describedby="tbl-dialogue-metrics-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div id="cell-dialogue-metrics" class="cell" data-execution_count="2">
<div id="dialogue-metrics" class="cell-output cell-output-display" data-execution_count="2">
<div id="wdcrjmdqbk" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#wdcrjmdqbk table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

#wdcrjmdqbk thead, tbody, tfoot, tr, td, th { border-style: none; }
 tr { background-color: transparent; }
#wdcrjmdqbk p { margin: 0; padding: 0; }
 #wdcrjmdqbk .gt_table { display: table; border-collapse: collapse; line-height: normal; margin-left: auto; margin-right: auto; color: #333333; font-size: 16px; font-weight: normal; font-style: normal; background-color: #FFFFFF; width: auto; border-top-style: solid; border-top-width: 2px; border-top-color: #A8A8A8; border-right-style: none; border-right-width: 2px; border-right-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #A8A8A8; border-left-style: none; border-left-width: 2px; border-left-color: #D3D3D3; }
 #wdcrjmdqbk .gt_caption { padding-top: 4px; padding-bottom: 4px; }
 #wdcrjmdqbk .gt_title { color: #333333; font-size: 125%; font-weight: initial; padding-top: 4px; padding-bottom: 4px; padding-left: 5px; padding-right: 5px; border-bottom-color: #FFFFFF; border-bottom-width: 0; }
 #wdcrjmdqbk .gt_subtitle { color: #333333; font-size: 85%; font-weight: initial; padding-top: 3px; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; border-top-color: #FFFFFF; border-top-width: 0; }
 #wdcrjmdqbk .gt_heading { background-color: #FFFFFF; text-align: center; border-bottom-color: #FFFFFF; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; }
 #wdcrjmdqbk .gt_bottom_border { border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; }
 #wdcrjmdqbk .gt_col_headings { border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; }
 #wdcrjmdqbk .gt_col_heading { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: normal; text-transform: inherit; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; }
 #wdcrjmdqbk .gt_column_spanner_outer { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: normal; text-transform: inherit; padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; }
 #wdcrjmdqbk .gt_column_spanner_outer:first-child { padding-left: 0; }
 #wdcrjmdqbk .gt_column_spanner_outer:last-child { padding-right: 0; }
 #wdcrjmdqbk .gt_column_spanner { border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 5px; overflow-x: hidden; display: inline-block; width: 100%; }
 #wdcrjmdqbk .gt_spanner_row { border-bottom-style: hidden; }
 #wdcrjmdqbk .gt_group_heading { padding-top: 8px; padding-bottom: 8px; padding-left: 5px; padding-right: 5px; color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; text-align: left; }
 #wdcrjmdqbk .gt_empty_group_heading { padding: 0.5px; color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; vertical-align: middle; }
 #wdcrjmdqbk .gt_from_md> :first-child { margin-top: 0; }
 #wdcrjmdqbk .gt_from_md> :last-child { margin-bottom: 0; }
 #wdcrjmdqbk .gt_row { padding-top: 8px; padding-bottom: 8px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; }
 #wdcrjmdqbk .gt_stub { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-right-style: solid; border-right-width: 2px; border-right-color: #D3D3D3; padding-left: 5px; padding-right: 5px; }
 #wdcrjmdqbk .gt_stub_row_group { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-right-style: solid; border-right-width: 2px; border-right-color: #D3D3D3; padding-left: 5px; padding-right: 5px; vertical-align: top; }
 #wdcrjmdqbk .gt_row_group_first td { border-top-width: 2px; }
 #wdcrjmdqbk .gt_row_group_first th { border-top-width: 2px; }
 #wdcrjmdqbk .gt_striped { background-color: rgba(128,128,128,0.05); }
 #wdcrjmdqbk .gt_table_body { border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; }
 #wdcrjmdqbk .gt_sourcenotes { color: #333333; background-color: #FFFFFF; border-bottom-style: none; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 2px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 2px; border-right-color: #D3D3D3; }
 #wdcrjmdqbk .gt_sourcenote { font-size: 90%; padding-top: 4px; padding-bottom: 4px; padding-left: 5px; padding-right: 5px; text-align: left; }
 #wdcrjmdqbk .gt_left { text-align: left; }
 #wdcrjmdqbk .gt_center { text-align: center; }
 #wdcrjmdqbk .gt_right { text-align: right; font-variant-numeric: tabular-nums; }
 #wdcrjmdqbk .gt_font_normal { font-weight: normal; }
 #wdcrjmdqbk .gt_font_bold { font-weight: bold; }
 #wdcrjmdqbk .gt_font_italic { font-style: italic; }
 #wdcrjmdqbk .gt_super { font-size: 65%; }
 #wdcrjmdqbk .gt_footnote_marks { font-size: 75%; vertical-align: 0.4em; position: initial; }
 #wdcrjmdqbk .gt_asterisk { font-size: 100%; vertical-align: 0; }
 
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="Features" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Features</th>
<th id="Description" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Description</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left">dialogue_density</td>
<td class="gt_row gt_left">The number of non-blank lines in this episode.</td>
</tr>
<tr class="even">
<td class="gt_row gt_left">avg_length</td>
<td class="gt_row gt_left">The average number of characters (technically codepoints) per line of dialogue.</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left">sentiment_variance</td>
<td class="gt_row gt_left">The variance in the numeric AFINN sentiment of words in this episode.</td>
</tr>
<tr class="even">
<td class="gt_row gt_left">unique_words</td>
<td class="gt_row gt_left">The number of unique lowercase words in this episode.</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left">question_ratio</td>
<td class="gt_row gt_left">The proportion of lines of dialogue that contain at least one question mark ('?').</td>
</tr>
<tr class="even">
<td class="gt_row gt_left">exclamation_ratio</td>
<td class="gt_row gt_left">The proportion of lines of dialogue that contain at least one exclamation point ('!').</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="2" class="gt_sourcenote">Data: {bobsburgersR} (via TidyTuesday)</td>
</tr>
</tfoot>

</table>


</div>
</div>
</div>
</div>
</figure>
</div>
<p>There are further details about the data in the TidyTuesday repository, including the following quote:</p>
<blockquote class="blockquote">
<p>We would like to emphasise that you should not draw conclusions about causation in the data. There are various moderating variables that affect all data, many of which might not have been captured in these datasets. As such, our suggestion is to use the data provided to practice your data tidying and plotting techniques, and to consider for yourself what nuances might underlie these relationships.</p>
</blockquote>
<p>They are not wrong! If I was doing this <strong>properly</strong>, I’d spend more time trying to understand the data, including extracting more information from the dialogue. I’d also spend some time thinking about what moderating variables they are referring to and including those where possible. While the results might not be groundbreaking, I’m sure the model would be more precise. Instead, I’m just having fun. I’m a silly goose.</p>
<p>I should still do some exploratory analysis first. I’m not a complete monster. Below, we plot the outcome distribution using a colour gradient scale to represent seasons. IMDb ratings are approximately normally distributed, with most values between 7 and 8.</p>
<div id="cell-season-ratings" class="cell" data-execution_count="3">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">(</span>
<span id="cb3-2">    ggplot(bobs_burgers, aes(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rating"</span>, fill<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"factor(season)"</span>))</span>
<span id="cb3-3">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_bar()</span>
<span id="cb3-4">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_hline(yintercept<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, colour<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>)</span>
<span id="cb3-5">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> labs(</span>
<span id="cb3-6">        title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Distribution of Bob's Burgers Episode Ratings by Season"</span>,</span>
<span id="cb3-7">        subtitle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(</span>
<span id="cb3-8">            textwrap.fill(</span>
<span id="cb3-9">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The distribution of IMDb user ratings for Bob's Burgers episodes, "</span></span>
<span id="cb3-10">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"with a gradient scale representing season (blue = earlier seasons; "</span></span>
<span id="cb3-11">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey = later seasons). The earlier seasons of the show are generally "</span></span>
<span id="cb3-12">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"favoured."</span>,</span>
<span id="cb3-13">                width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">92</span>,</span>
<span id="cb3-14">            )</span>
<span id="cb3-15">        ),</span>
<span id="cb3-16">        x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IMDb Rating"</span>,</span>
<span id="cb3-17">        y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>,</span>
<span id="cb3-18">        caption<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span>,</span>
<span id="cb3-19">    )</span>
<span id="cb3-20">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> scale_fill_gradient(low<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>, high<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#D2D2D2"</span>, guide<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>)</span>
<span id="cb3-21">)</span></code></pre></div></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/index_files/figure-html/season-ratings-output-1.png" id="season-ratings" alt="A bar plot visualising the distribution of Bob's Burgers IMDb user ratings, with a gradient scale distinguishing seasons. The plot demonstrates that earlier seasons tend to have higher ratings, but there are several large outliers in later seasons that have ratings of nine or higher." width="672" height="480" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>The earlier seasons (blue) are generally higher-rated, though some of the highest-rated episodes come from the later seasons (grey). Five episodes have ratings of 9+: two in season 6, two in season 13, and one in season 14. The highest-rated episode, <em>The Plight Before Christmas</em> (S13E10), gets a 9.6.</p>
<p>We can also look at the correlation between all the numeric features in the dataset and the target, IMDb ratings, in Table&nbsp;2.</p>
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">(</span>
<span id="cb4-2">    bobs_burgers.select_dtypes(include<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"number"</span>)</span>
<span id="cb4-3">    .drop(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rating"</span>)</span>
<span id="cb4-4">    .corrwith(bobs_burgers[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rating"</span>])</span>
<span id="cb4-5">    .sort_values(ascending<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb4-6">    .reset_index()</span>
<span id="cb4-7">    .rename(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Correlation"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"index"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Feature"</span>})</span>
<span id="cb4-8">    .pipe(</span>
<span id="cb4-9">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: GT(df, rowname_col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Feature"</span>)</span>
<span id="cb4-10">        .fmt_number(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Correlation"</span>, decimals<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb4-11">        .cols_align(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Correlation"</span>, align<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>)</span>
<span id="cb4-12">        .tab_source_note(source_note<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span>)</span>
<span id="cb4-13">        .tab_options(table_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"100%"</span>)</span>
<span id="cb4-14">    )</span>
<span id="cb4-15">)</span></code></pre></div></div>
</details>
<div id="tbl-correlations" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-correlations-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;2: Correlations Between Numeric Features &amp; IMDb User Ratings
</figcaption>
<div aria-describedby="tbl-correlations-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div id="cell-correlations" class="cell" data-execution_count="4">
<div id="correlations" class="cell-output cell-output-display" data-execution_count="4">
<div id="ejyuegqrgf" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#ejyuegqrgf table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

#ejyuegqrgf thead, tbody, tfoot, tr, td, th { border-style: none; }
 tr { background-color: transparent; }
#ejyuegqrgf p { margin: 0; padding: 0; }
 #ejyuegqrgf .gt_table { display: table; border-collapse: collapse; line-height: normal; margin-left: auto; margin-right: auto; color: #333333; font-size: 16px; font-weight: normal; font-style: normal; background-color: #FFFFFF; width: 100%; border-top-style: solid; border-top-width: 2px; border-top-color: #A8A8A8; border-right-style: none; border-right-width: 2px; border-right-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #A8A8A8; border-left-style: none; border-left-width: 2px; border-left-color: #D3D3D3; }
 #ejyuegqrgf .gt_caption { padding-top: 4px; padding-bottom: 4px; }
 #ejyuegqrgf .gt_title { color: #333333; font-size: 125%; font-weight: initial; padding-top: 4px; padding-bottom: 4px; padding-left: 5px; padding-right: 5px; border-bottom-color: #FFFFFF; border-bottom-width: 0; }
 #ejyuegqrgf .gt_subtitle { color: #333333; font-size: 85%; font-weight: initial; padding-top: 3px; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; border-top-color: #FFFFFF; border-top-width: 0; }
 #ejyuegqrgf .gt_heading { background-color: #FFFFFF; text-align: center; border-bottom-color: #FFFFFF; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; }
 #ejyuegqrgf .gt_bottom_border { border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; }
 #ejyuegqrgf .gt_col_headings { border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; }
 #ejyuegqrgf .gt_col_heading { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: normal; text-transform: inherit; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; }
 #ejyuegqrgf .gt_column_spanner_outer { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: normal; text-transform: inherit; padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; }
 #ejyuegqrgf .gt_column_spanner_outer:first-child { padding-left: 0; }
 #ejyuegqrgf .gt_column_spanner_outer:last-child { padding-right: 0; }
 #ejyuegqrgf .gt_column_spanner { border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 5px; overflow-x: hidden; display: inline-block; width: 100%; }
 #ejyuegqrgf .gt_spanner_row { border-bottom-style: hidden; }
 #ejyuegqrgf .gt_group_heading { padding-top: 8px; padding-bottom: 8px; padding-left: 5px; padding-right: 5px; color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; text-align: left; }
 #ejyuegqrgf .gt_empty_group_heading { padding: 0.5px; color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; vertical-align: middle; }
 #ejyuegqrgf .gt_from_md> :first-child { margin-top: 0; }
 #ejyuegqrgf .gt_from_md> :last-child { margin-bottom: 0; }
 #ejyuegqrgf .gt_row { padding-top: 8px; padding-bottom: 8px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; }
 #ejyuegqrgf .gt_stub { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-right-style: solid; border-right-width: 2px; border-right-color: #D3D3D3; padding-left: 5px; padding-right: 5px; }
 #ejyuegqrgf .gt_stub_row_group { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-right-style: solid; border-right-width: 2px; border-right-color: #D3D3D3; padding-left: 5px; padding-right: 5px; vertical-align: top; }
 #ejyuegqrgf .gt_row_group_first td { border-top-width: 2px; }
 #ejyuegqrgf .gt_row_group_first th { border-top-width: 2px; }
 #ejyuegqrgf .gt_striped { background-color: rgba(128,128,128,0.05); }
 #ejyuegqrgf .gt_table_body { border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; }
 #ejyuegqrgf .gt_sourcenotes { color: #333333; background-color: #FFFFFF; border-bottom-style: none; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 2px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 2px; border-right-color: #D3D3D3; }
 #ejyuegqrgf .gt_sourcenote { font-size: 90%; padding-top: 4px; padding-bottom: 4px; padding-left: 5px; padding-right: 5px; text-align: left; }
 #ejyuegqrgf .gt_left { text-align: left; }
 #ejyuegqrgf .gt_center { text-align: center; }
 #ejyuegqrgf .gt_right { text-align: right; font-variant-numeric: tabular-nums; }
 #ejyuegqrgf .gt_font_normal { font-weight: normal; }
 #ejyuegqrgf .gt_font_bold { font-weight: bold; }
 #ejyuegqrgf .gt_font_italic { font-style: italic; }
 #ejyuegqrgf .gt_super { font-size: 65%; }
 #ejyuegqrgf .gt_footnote_marks { font-size: 75%; vertical-align: 0.4em; position: initial; }
 #ejyuegqrgf .gt_asterisk { font-size: 100%; vertical-align: 0; }
 
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col"></th>
<th id="Correlation" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Correlation</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">wikipedia_viewers</th>
<td class="gt_row gt_center">0.31</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">exclamation_ratio</th>
<td class="gt_row gt_center">0.28</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">dialogue_density</th>
<td class="gt_row gt_center">0.17</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">question_ratio</th>
<td class="gt_row gt_center">0.11</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">sentiment_variance</th>
<td class="gt_row gt_center">0.09</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">avg_length</th>
<td class="gt_row gt_center">0.07</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">episode</th>
<td class="gt_row gt_center">−0.06</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">unique_words</th>
<td class="gt_row gt_center">−0.15</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">season</th>
<td class="gt_row gt_center">−0.39</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">episode_overall</th>
<td class="gt_row gt_center">−0.39</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">year</th>
<td class="gt_row gt_center">−0.40</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="2" class="gt_sourcenote">Data: {bobsburgersR} (via TidyTuesday)</td>
</tr>
</tfoot>

</table>


</div>
</div>
</div>
</div>
</figure>
</div>
<p>Several features, including a couple dialogue metrics, appear to be making minimal contributions to the variance in episode ratings. However, ratings are moderately correlated with viewers, exclamation ratio, season, the overall episode number, and the year the episode was aired.</p>
<p>The remarkably similar correlations between ratings and the season, overall episode, and year suggest that those three features capture the same thing—time. The plot below visualises how ratings have changed over time.</p>
<div id="cell-episode-ratings" class="cell" data-execution_count="5">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">(</span>
<span id="cb5-2">    ggplot(bobs_burgers, aes(x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"episode_overall"</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rating"</span>))</span>
<span id="cb5-3">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_point(size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, stroke<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, fill<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>, shape<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>)</span>
<span id="cb5-4">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_smooth(method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lm"</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, se<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>)</span>
<span id="cb5-5">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> scale_x_continuous(breaks<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">150</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">250</span>])</span>
<span id="cb5-6">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> labs(</span>
<span id="cb5-7">        title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bob's Burgers Episode Ratings Over Time"</span>,</span>
<span id="cb5-8">        subtitle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(</span>
<span id="cb5-9">            textwrap.fill(</span>
<span id="cb5-10">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Comparing how Bob's Burgers episode ratings have changed over time. "</span></span>
<span id="cb5-11">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"There has been a steady decline in ratings, with no episode receiving "</span></span>
<span id="cb5-12">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"an average rating below seven until season 10."</span>,</span>
<span id="cb5-13">                width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>,</span>
<span id="cb5-14">            )</span>
<span id="cb5-15">        ),</span>
<span id="cb5-16">        x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Episode"</span>,</span>
<span id="cb5-17">        y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IMDb Rating"</span>,</span>
<span id="cb5-18">        caption<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span>,</span>
<span id="cb5-19">    ) </span>
<span id="cb5-20">)</span></code></pre></div></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/index_files/figure-html/episode-ratings-output-1.png" id="episode-ratings" alt="A regression plot visualising the relationship between Bob's Burgers IMDb user ratings and total episode number. While the average rating is just under 8 when the show first begins, it gradually declines over 250+ episodes, to around 7.5." width="672" height="480" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>While episode ratings are noisy, there is a visible decline over time. The average ratings for the first eight seasons are between 7.7 and 8, dropping in season nine (seen around 150 episodes in the above plot) and hovering around 7.5 for the remaining seasons.</p>
<p>At the other end of Table&nbsp;2, a moderate positive correlation exists between ratings and viewership, which is visualised below.</p>
<div id="cell-viewers-ratings" class="cell" data-execution_count="6">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">(</span>
<span id="cb6-2">    ggplot(bobs_burgers, aes(x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_viewers"</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rating"</span>))</span>
<span id="cb6-3">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_point(size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, stroke<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, fill<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>, shape<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>)</span>
<span id="cb6-4">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_smooth(method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lm"</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, se<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>)</span>
<span id="cb6-5">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> labs(</span>
<span id="cb6-6">        title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bob's Burgers Episode Ratings by Viewers"</span>,</span>
<span id="cb6-7">        subtitle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(</span>
<span id="cb6-8">            textwrap.fill(</span>
<span id="cb6-9">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Comparing the association between IMDb user ratings of Bob's Burgers "</span></span>
<span id="cb6-10">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"episodes and US viewers when first aired. While it is noisy, there "</span></span>
<span id="cb6-11">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"does appear to be a positive correlation between viewing figures and "</span></span>
<span id="cb6-12">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"the episode rating."</span>,</span>
<span id="cb6-13">                width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">91</span>,</span>
<span id="cb6-14">            )</span>
<span id="cb6-15">        ),</span>
<span id="cb6-16">        x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Viewers (Millions)"</span>,</span>
<span id="cb6-17">        y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IMDb Rating"</span>,</span>
<span id="cb6-18">        caption<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span>,</span>
<span id="cb6-19">    )</span>
<span id="cb6-20">)</span></code></pre></div></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/index_files/figure-html/viewers-ratings-output-1.png" id="viewers-ratings" alt="A regression plot visualising the relationship between Bob's Burgers IMDb user ratings and total US viewers when the episode was first aired. There appears to be a moderate increase in ratings as viewership increases, but there are also several outliers that distort the plot, particularly one episode with more than nine million viewers." width="672" height="480" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>One almighty outlier pushes the x-axis out a lot further: S1E1, watched by over nine million people, almost three million more viewers than any other episode. It turns out this was the first episode of Bob’s Burgers, and I think this hints at the likely explanation for the strong correlation between viewers and ratings<sup>1</sup>. The viewership has been steadily declining since the first season. The causal mechanism may go in the other direction (the quality of episodes declining and leading to a decline in the audience), but it’s just as likely the correlation is just capturing time effects.</p>
<p>Is everything a function of time? Maybe the overall episode number is the only feature we need? Table&nbsp;2 might not have given us much hope in the predictive power of the dialogue metrics, but they might be our only hope if we want to include any features that are not just a variety of ways of measuring the effect of time.</p>
<p>The dialogue metrics are intended to describe the episode itself. The assumption is that these metrics will capture characteristics that define the episode and offer some signal about the episode quality (and, therefore, ratings). Below, each dialogue metric is plotted against IMDb ratings.</p>
<div id="cell-metric-ratings" class="cell" data-execution_count="7">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">(</span>
<span id="cb7-2">    bobs_burgers.melt(</span>
<span id="cb7-3">        id_vars<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rating"</span>],</span>
<span id="cb7-4">        value_vars<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[</span>
<span id="cb7-5">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dialogue_density"</span>,</span>
<span id="cb7-6">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"avg_length"</span>,</span>
<span id="cb7-7">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sentiment_variance"</span>,</span>
<span id="cb7-8">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"unique_words"</span>,</span>
<span id="cb7-9">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"question_ratio"</span>,</span>
<span id="cb7-10">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"exclamation_ratio"</span>,</span>
<span id="cb7-11">        ],</span>
<span id="cb7-12">        var_name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"label"</span>,</span>
<span id="cb7-13">        value_name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span>,</span>
<span id="cb7-14">    )</span>
<span id="cb7-15">    .assign(</span>
<span id="cb7-16">        label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"label"</span>]</span>
<span id="cb7-17">        .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.replace(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span>)</span>
<span id="cb7-18">        .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.title()</span>
<span id="cb7-19">        .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.replace(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Avg"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Average"</span>, case<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb7-20">    )</span>
<span id="cb7-21">    .pipe(</span>
<span id="cb7-22">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: ggplot(df, aes(x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rating"</span>, group<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb7-23">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_point(</span>
<span id="cb7-24">            size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, stroke<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, fill<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>, shape<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span></span>
<span id="cb7-25">        )</span>
<span id="cb7-26">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_smooth(method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lm"</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, se<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>)</span>
<span id="cb7-27">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> facet_wrap(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"~label"</span>, scales<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"free_x"</span>, nrow<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb7-28">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> labs(</span>
<span id="cb7-29">            title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bob's Burgers Episode Ratings by Episode Dialogue Metrics"</span>,</span>
<span id="cb7-30">            subtitle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(</span>
<span id="cb7-31">                textwrap.fill(</span>
<span id="cb7-32">                    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Comparing the association between Bob's Burgers IMDb user ratings "</span></span>
<span id="cb7-33">                    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"by the dialogue metrics for each episode. While all six metrics "</span></span>
<span id="cb7-34">                    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"are noisy, the exclamation ratio and the number of unique words do "</span></span>
<span id="cb7-35">                    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"appear to have correlations with the episode's rating."</span>,</span>
<span id="cb7-36">                    width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">88</span>,</span>
<span id="cb7-37">                )</span>
<span id="cb7-38">            ),</span>
<span id="cb7-39">            x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>,</span>
<span id="cb7-40">            y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IMDb Rating"</span>,</span>
<span id="cb7-41">            caption<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(</span>
<span id="cb7-42">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | "</span></span>
<span id="cb7-43">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span></span>
<span id="cb7-44">            ),</span>
<span id="cb7-45">        )</span>
<span id="cb7-46">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> theme(</span>
<span id="cb7-47">            figure_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>),</span>
<span id="cb7-48">            panel_spacing_x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span>,</span>
<span id="cb7-49">            panel_spacing_y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.04</span>,</span>
<span id="cb7-50">            plot_subtitle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>element_text(</span>
<span id="cb7-51">                margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"t"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"r"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"b"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"l"</span>: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>},</span>
<span id="cb7-52">            ),</span>
<span id="cb7-53">        )</span>
<span id="cb7-54">    )</span>
<span id="cb7-55">)</span></code></pre></div></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/index_files/figure-html/metric-ratings-output-1.png" id="metric-ratings" alt="A faceted regression plot visualising the relationship between Bob's Burgers IMDb user ratings and each of the six dialogue metrics. While most of the metrics appear to have minimal effect on ratings, increases in the number of unique words in an episode is associated with a decline in ratings, while the larger exclamation ratio leads to higher ratings." width="672" height="864" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>There appears to be some signal here, but it’s mostly noise. Metrics like dialogue density appear to offer nothing, but exclamation ratio and unique words have stronger associations with ratings. I can strain to convince myself there are some interesting patterns in the question ratio and sentiment variance plots, but that may be explained by motivated reasoning more than any meaningful signal in these features.</p>
<p>Finally, in my desperation, I turn to the categorical features. Specifically, the episode directors and writers could contain predictive value<sup>2</sup>. Table&nbsp;3 &amp; Table&nbsp;4 show the total episodes and average rating for each director and writer credited on at least five Bob’s Burgers episodes.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true" href="">Director Ratings</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false" href="">Writer Ratings</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">(</span>
<span id="cb8-2">    bobs_burgers.assign(</span>
<span id="cb8-3">        wikipedia_directed_by<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: (</span>
<span id="cb8-4">            df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_directed_by"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.split(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" &amp; "</span>)</span>
<span id="cb8-5">        )</span>
<span id="cb8-6">    )</span>
<span id="cb8-7">    .explode(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_directed_by"</span>)</span>
<span id="cb8-8">    .groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_directed_by"</span>)</span>
<span id="cb8-9">    .agg(</span>
<span id="cb8-10">        episodes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_directed_by"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"size"</span>), </span>
<span id="cb8-11">        average_rating<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rating"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>)</span>
<span id="cb8-12">        )</span>
<span id="cb8-13">    .query(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"episodes &gt;= 5"</span>)</span>
<span id="cb8-14">    .sort_values(by<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"average_rating"</span>, ascending<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb8-15">    .reset_index()</span>
<span id="cb8-16">    .pipe(</span>
<span id="cb8-17">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: GT(df, rowname_col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_directed_by"</span>)</span>
<span id="cb8-18">        .fmt_number(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"average_rating"</span>, decimals<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb8-19">        .cols_label(</span>
<span id="cb8-20">            episodes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Total Episodes Directed"</span>, </span>
<span id="cb8-21">            average_rating<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Average Episode Rating"</span></span>
<span id="cb8-22">        )</span>
<span id="cb8-23">        .cols_align(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"episodes"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"average_rating"</span>], align<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>)</span>
<span id="cb8-24">        .tab_source_note(source_note<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span>)</span>
<span id="cb8-25">        .tab_options(table_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"100%"</span>)</span>
<span id="cb8-26">    )</span>
<span id="cb8-27">)</span></code></pre></div></div>
</details>
<div id="tbl-director-ratings" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-director-ratings-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;3: IMDb User Ratings by Director
</figcaption>
<div aria-describedby="tbl-director-ratings-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div id="cell-director-ratings" class="cell" data-execution_count="8">
<div id="director-ratings" class="cell-output cell-output-display" data-execution_count="8">
<div id="dotscgrwos" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#dotscgrwos table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

#dotscgrwos thead, tbody, tfoot, tr, td, th { border-style: none; }
 tr { background-color: transparent; }
#dotscgrwos p { margin: 0; padding: 0; }
 #dotscgrwos .gt_table { display: table; border-collapse: collapse; line-height: normal; margin-left: auto; margin-right: auto; color: #333333; font-size: 16px; font-weight: normal; font-style: normal; background-color: #FFFFFF; width: 100%; border-top-style: solid; border-top-width: 2px; border-top-color: #A8A8A8; border-right-style: none; border-right-width: 2px; border-right-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #A8A8A8; border-left-style: none; border-left-width: 2px; border-left-color: #D3D3D3; }
 #dotscgrwos .gt_caption { padding-top: 4px; padding-bottom: 4px; }
 #dotscgrwos .gt_title { color: #333333; font-size: 125%; font-weight: initial; padding-top: 4px; padding-bottom: 4px; padding-left: 5px; padding-right: 5px; border-bottom-color: #FFFFFF; border-bottom-width: 0; }
 #dotscgrwos .gt_subtitle { color: #333333; font-size: 85%; font-weight: initial; padding-top: 3px; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; border-top-color: #FFFFFF; border-top-width: 0; }
 #dotscgrwos .gt_heading { background-color: #FFFFFF; text-align: center; border-bottom-color: #FFFFFF; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; }
 #dotscgrwos .gt_bottom_border { border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; }
 #dotscgrwos .gt_col_headings { border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; }
 #dotscgrwos .gt_col_heading { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: normal; text-transform: inherit; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; }
 #dotscgrwos .gt_column_spanner_outer { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: normal; text-transform: inherit; padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; }
 #dotscgrwos .gt_column_spanner_outer:first-child { padding-left: 0; }
 #dotscgrwos .gt_column_spanner_outer:last-child { padding-right: 0; }
 #dotscgrwos .gt_column_spanner { border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 5px; overflow-x: hidden; display: inline-block; width: 100%; }
 #dotscgrwos .gt_spanner_row { border-bottom-style: hidden; }
 #dotscgrwos .gt_group_heading { padding-top: 8px; padding-bottom: 8px; padding-left: 5px; padding-right: 5px; color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; text-align: left; }
 #dotscgrwos .gt_empty_group_heading { padding: 0.5px; color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; vertical-align: middle; }
 #dotscgrwos .gt_from_md> :first-child { margin-top: 0; }
 #dotscgrwos .gt_from_md> :last-child { margin-bottom: 0; }
 #dotscgrwos .gt_row { padding-top: 8px; padding-bottom: 8px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; }
 #dotscgrwos .gt_stub { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-right-style: solid; border-right-width: 2px; border-right-color: #D3D3D3; padding-left: 5px; padding-right: 5px; }
 #dotscgrwos .gt_stub_row_group { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-right-style: solid; border-right-width: 2px; border-right-color: #D3D3D3; padding-left: 5px; padding-right: 5px; vertical-align: top; }
 #dotscgrwos .gt_row_group_first td { border-top-width: 2px; }
 #dotscgrwos .gt_row_group_first th { border-top-width: 2px; }
 #dotscgrwos .gt_striped { background-color: rgba(128,128,128,0.05); }
 #dotscgrwos .gt_table_body { border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; }
 #dotscgrwos .gt_sourcenotes { color: #333333; background-color: #FFFFFF; border-bottom-style: none; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 2px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 2px; border-right-color: #D3D3D3; }
 #dotscgrwos .gt_sourcenote { font-size: 90%; padding-top: 4px; padding-bottom: 4px; padding-left: 5px; padding-right: 5px; text-align: left; }
 #dotscgrwos .gt_left { text-align: left; }
 #dotscgrwos .gt_center { text-align: center; }
 #dotscgrwos .gt_right { text-align: right; font-variant-numeric: tabular-nums; }
 #dotscgrwos .gt_font_normal { font-weight: normal; }
 #dotscgrwos .gt_font_bold { font-weight: bold; }
 #dotscgrwos .gt_font_italic { font-style: italic; }
 #dotscgrwos .gt_super { font-size: 65%; }
 #dotscgrwos .gt_footnote_marks { font-size: 75%; vertical-align: 0.4em; position: initial; }
 #dotscgrwos .gt_asterisk { font-size: 100%; vertical-align: 0; }
 
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col"></th>
<th id="Total Episodes Directed" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Total Episodes Directed</th>
<th id="Average Episode Rating" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Average Episode Rating</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Jennifer Coyle</th>
<td class="gt_row gt_center">19</td>
<td class="gt_row gt_center">8.07</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Kyounghee Lim</th>
<td class="gt_row gt_center">15</td>
<td class="gt_row gt_center">8.00</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Boohwan Lim</th>
<td class="gt_row gt_center">15</td>
<td class="gt_row gt_center">7.95</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Bernard Derriman</th>
<td class="gt_row gt_center">9</td>
<td class="gt_row gt_center">7.89</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Mauricio Pardo</th>
<td class="gt_row gt_center">6</td>
<td class="gt_row gt_center">7.87</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Anthony Chun</th>
<td class="gt_row gt_center">8</td>
<td class="gt_row gt_center">7.86</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Tyree Dillihay</th>
<td class="gt_row gt_center">32</td>
<td class="gt_row gt_center">7.86</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Don MacKinnon</th>
<td class="gt_row gt_center">12</td>
<td class="gt_row gt_center">7.85</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Wes Archer</th>
<td class="gt_row gt_center">7</td>
<td class="gt_row gt_center">7.77</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Brian Loschiavo</th>
<td class="gt_row gt_center">23</td>
<td class="gt_row gt_center">7.76</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Ian Hamilton</th>
<td class="gt_row gt_center">11</td>
<td class="gt_row gt_center">7.65</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Chris Song</th>
<td class="gt_row gt_center">47</td>
<td class="gt_row gt_center">7.60</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Matthew Long</th>
<td class="gt_row gt_center">18</td>
<td class="gt_row gt_center">7.53</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Ryan Mattos</th>
<td class="gt_row gt_center">26</td>
<td class="gt_row gt_center">7.49</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Tom Riggin</th>
<td class="gt_row gt_center">19</td>
<td class="gt_row gt_center">7.36</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Simon Chong</th>
<td class="gt_row gt_center">9</td>
<td class="gt_row gt_center">7.31</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="3" class="gt_sourcenote">Data: {bobsburgersR} (via TidyTuesday)</td>
</tr>
</tfoot>

</table>


</div>
</div>
</div>
</div>
</figure>
</div>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1">(</span>
<span id="cb9-2">    bobs_burgers.assign(</span>
<span id="cb9-3">        wikipedia_written_by<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: (</span>
<span id="cb9-4">            df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_written_by"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.split(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" &amp; "</span>)</span>
<span id="cb9-5">        )</span>
<span id="cb9-6">    )</span>
<span id="cb9-7">    .explode(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_written_by"</span>)</span>
<span id="cb9-8">    .groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_written_by"</span>)</span>
<span id="cb9-9">    .agg(</span>
<span id="cb9-10">        episodes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_written_by"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"size"</span>), </span>
<span id="cb9-11">        average_rating<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rating"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>)</span>
<span id="cb9-12">        )</span>
<span id="cb9-13">    .query(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"episodes &gt;= 5"</span>)</span>
<span id="cb9-14">    .sort_values(by<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"average_rating"</span>, ascending<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb9-15">    .reset_index()</span>
<span id="cb9-16">    .pipe(</span>
<span id="cb9-17">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: GT(df, rowname_col<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_written_by"</span>)</span>
<span id="cb9-18">        .fmt_number(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"average_rating"</span>, decimals<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb9-19">        .cols_label(</span>
<span id="cb9-20">            episodes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Total Episodes Written"</span>, </span>
<span id="cb9-21">            average_rating<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Average Episode Rating"</span></span>
<span id="cb9-22">        )</span>
<span id="cb9-23">        .cols_align(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"episodes"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"average_rating"</span>], align<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>)</span>
<span id="cb9-24">        .tab_source_note(source_note<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span>)</span>
<span id="cb9-25">        .tab_options(table_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"100%"</span>)</span>
<span id="cb9-26">    )</span>
<span id="cb9-27">)</span></code></pre></div></div>
</details>
<div id="tbl-writer-ratings" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-writer-ratings-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;4: IMDb User Ratings by Writer
</figcaption>
<div aria-describedby="tbl-writer-ratings-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div id="cell-writer-ratings" class="cell" data-execution_count="9">
<div id="writer-ratings" class="cell-output cell-output-display" data-execution_count="9">
<div id="nowpyzpdqt" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#nowpyzpdqt table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

#nowpyzpdqt thead, tbody, tfoot, tr, td, th { border-style: none; }
 tr { background-color: transparent; }
#nowpyzpdqt p { margin: 0; padding: 0; }
 #nowpyzpdqt .gt_table { display: table; border-collapse: collapse; line-height: normal; margin-left: auto; margin-right: auto; color: #333333; font-size: 16px; font-weight: normal; font-style: normal; background-color: #FFFFFF; width: 100%; border-top-style: solid; border-top-width: 2px; border-top-color: #A8A8A8; border-right-style: none; border-right-width: 2px; border-right-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #A8A8A8; border-left-style: none; border-left-width: 2px; border-left-color: #D3D3D3; }
 #nowpyzpdqt .gt_caption { padding-top: 4px; padding-bottom: 4px; }
 #nowpyzpdqt .gt_title { color: #333333; font-size: 125%; font-weight: initial; padding-top: 4px; padding-bottom: 4px; padding-left: 5px; padding-right: 5px; border-bottom-color: #FFFFFF; border-bottom-width: 0; }
 #nowpyzpdqt .gt_subtitle { color: #333333; font-size: 85%; font-weight: initial; padding-top: 3px; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; border-top-color: #FFFFFF; border-top-width: 0; }
 #nowpyzpdqt .gt_heading { background-color: #FFFFFF; text-align: center; border-bottom-color: #FFFFFF; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; }
 #nowpyzpdqt .gt_bottom_border { border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; }
 #nowpyzpdqt .gt_col_headings { border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; }
 #nowpyzpdqt .gt_col_heading { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: normal; text-transform: inherit; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; }
 #nowpyzpdqt .gt_column_spanner_outer { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: normal; text-transform: inherit; padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; }
 #nowpyzpdqt .gt_column_spanner_outer:first-child { padding-left: 0; }
 #nowpyzpdqt .gt_column_spanner_outer:last-child { padding-right: 0; }
 #nowpyzpdqt .gt_column_spanner { border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 5px; overflow-x: hidden; display: inline-block; width: 100%; }
 #nowpyzpdqt .gt_spanner_row { border-bottom-style: hidden; }
 #nowpyzpdqt .gt_group_heading { padding-top: 8px; padding-bottom: 8px; padding-left: 5px; padding-right: 5px; color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; text-align: left; }
 #nowpyzpdqt .gt_empty_group_heading { padding: 0.5px; color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; vertical-align: middle; }
 #nowpyzpdqt .gt_from_md> :first-child { margin-top: 0; }
 #nowpyzpdqt .gt_from_md> :last-child { margin-bottom: 0; }
 #nowpyzpdqt .gt_row { padding-top: 8px; padding-bottom: 8px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; }
 #nowpyzpdqt .gt_stub { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-right-style: solid; border-right-width: 2px; border-right-color: #D3D3D3; padding-left: 5px; padding-right: 5px; }
 #nowpyzpdqt .gt_stub_row_group { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-right-style: solid; border-right-width: 2px; border-right-color: #D3D3D3; padding-left: 5px; padding-right: 5px; vertical-align: top; }
 #nowpyzpdqt .gt_row_group_first td { border-top-width: 2px; }
 #nowpyzpdqt .gt_row_group_first th { border-top-width: 2px; }
 #nowpyzpdqt .gt_striped { background-color: rgba(128,128,128,0.05); }
 #nowpyzpdqt .gt_table_body { border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; }
 #nowpyzpdqt .gt_sourcenotes { color: #333333; background-color: #FFFFFF; border-bottom-style: none; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 2px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 2px; border-right-color: #D3D3D3; }
 #nowpyzpdqt .gt_sourcenote { font-size: 90%; padding-top: 4px; padding-bottom: 4px; padding-left: 5px; padding-right: 5px; text-align: left; }
 #nowpyzpdqt .gt_left { text-align: left; }
 #nowpyzpdqt .gt_center { text-align: center; }
 #nowpyzpdqt .gt_right { text-align: right; font-variant-numeric: tabular-nums; }
 #nowpyzpdqt .gt_font_normal { font-weight: normal; }
 #nowpyzpdqt .gt_font_bold { font-weight: bold; }
 #nowpyzpdqt .gt_font_italic { font-style: italic; }
 #nowpyzpdqt .gt_super { font-size: 65%; }
 #nowpyzpdqt .gt_footnote_marks { font-size: 75%; vertical-align: 0.4em; position: initial; }
 #nowpyzpdqt .gt_asterisk { font-size: 100%; vertical-align: 0; }
 
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col"></th>
<th id="Total Episodes Written" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Total Episodes Written</th>
<th id="Average Episode Rating" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Average Episode Rating</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Loren Bouchard</th>
<td class="gt_row gt_center">7</td>
<td class="gt_row gt_center">8.30</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Lizzie Molyneux</th>
<td class="gt_row gt_center">29</td>
<td class="gt_row gt_center">7.87</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Wendy Molyneux</th>
<td class="gt_row gt_center">29</td>
<td class="gt_row gt_center">7.87</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Steven Davis</th>
<td class="gt_row gt_center">28</td>
<td class="gt_row gt_center">7.86</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Kelvin Yu</th>
<td class="gt_row gt_center">25</td>
<td class="gt_row gt_center">7.86</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Greg Thompson</th>
<td class="gt_row gt_center">21</td>
<td class="gt_row gt_center">7.80</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Dan Fybel</th>
<td class="gt_row gt_center">27</td>
<td class="gt_row gt_center">7.73</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Nora Smith</th>
<td class="gt_row gt_center">18</td>
<td class="gt_row gt_center">7.73</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Jon Schroeder</th>
<td class="gt_row gt_center">25</td>
<td class="gt_row gt_center">7.66</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Rich Rinaldi</th>
<td class="gt_row gt_center">28</td>
<td class="gt_row gt_center">7.63</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Scott Jacobson</th>
<td class="gt_row gt_center">26</td>
<td class="gt_row gt_center">7.60</td>
</tr>
<tr class="even">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Holly Schlesinger</th>
<td class="gt_row gt_center">28</td>
<td class="gt_row gt_center">7.58</td>
</tr>
<tr class="odd">
<th class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th">Katie Crown</th>
<td class="gt_row gt_center">11</td>
<td class="gt_row gt_center">7.28</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="3" class="gt_sourcenote">Data: {bobsburgersR} (via TidyTuesday)</td>
</tr>
</tfoot>

</table>


</div>
</div>
</div>
</div>
</figure>
</div>
</div>
</div>
</div>
<p>There is plenty of variance in the outcomes across directors and writers. It is reasonable to assume that these should impact the ratings and improve model performance. However, including directors and writers in the model will require inducing considerable sparsity in the data (assuming that one-hot encoding is used).</p>
</section>
<section id="data-preparation" class="level2">
<h2 class="anchored" data-anchor-id="data-preparation">Data Preparation</h2>
<p>A brief exploration of the data has not given me confidence that it is sufficient for developing a cromulent predictive model (maybe the TidyTuesday folks were on to something). But I’m committed to the bit. I’ve never heard of sunken costs.</p>
<p>I will carry out some basic preprocessing but won’t do any feature engineering or add additional data from elsewhere. I will keep all the dialogue metrics in the model because meaningful interactions between them could add some value<sup>3</sup>. However, I will drop the season-episode number and year features because they offer minimal additional value over the season and overall episode number features. Finally, I’m following my instincts and dropping the viewership feature. I think it is just serving as another proxy for time and isn’t needed.</p>
<p>There is a lot more that could be done here. Never underestimate how many different feature engineering methods exist<sup>4</sup>, nor the potential performance gains they can achieve. I think a lot could be gained from the transcripts of each episode’s dialogue, but this is outside the scope of this post (because it’s hard and I’m lazy).</p>
<section id="traintest-split" class="level3">
<h3 class="anchored" data-anchor-id="traintest-split">Train/Test Split</h3>
<p>I should have split the data into <a href="https://mlu-explain.github.io/train-test-validation/">training and test sets</a> before doing the exploratory work, but with only 271 observations, I don’t think we have enough data to justify splitting it up beforehand.</p>
<div id="train-test-split" class="cell" data-execution_count="10">
<details class="code-fold">
<summary>Data Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">X_train, X_test, y_train, y_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(</span>
<span id="cb10-2">    bobs_burgers.drop([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rating"</span>], axis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb10-3">    bobs_burgers[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rating"</span>],</span>
<span id="cb10-4">    test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>,</span>
<span id="cb10-5">    random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>,</span>
<span id="cb10-6">)</span></code></pre></div></div>
</details>
</div>
<p>The data has been split 70/30 into training and testing. I also decided there wasn’t enough to include a validation set.</p>
</section>
<section id="data-preprocessing" class="level3">
<h3 class="anchored" data-anchor-id="data-preprocessing">Data Preprocessing</h3>
<p>The model pipeline includes several preprocessing steps. I have split the features into categorical and numeric, and missing values are imputed using slightly different methods depending on the data type.</p>
<div id="explode-encode-class" class="cell" data-execution_count="11">
<details class="code-fold">
<summary>Class Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> ExplodeAndEncode(TransformerMixin, BaseEstimator):</span>
<span id="cb11-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">__init__</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, min_frequency<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>):</span>
<span id="cb11-3">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># initialise transformer with min frequency for encoding</span></span>
<span id="cb11-4">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.min_frequency <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> min_frequency</span>
<span id="cb11-5">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.ohe_directors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> OneHotEncoder(</span>
<span id="cb11-6">            handle_unknown<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ignore"</span>,</span>
<span id="cb11-7">            sparse_output<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb11-8">            min_frequency<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.min_frequency,</span>
<span id="cb11-9">        )</span>
<span id="cb11-10">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.ohe_writers <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> OneHotEncoder(</span>
<span id="cb11-11">            handle_unknown<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ignore"</span>,</span>
<span id="cb11-12">            sparse_output<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb11-13">            min_frequency<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.min_frequency,</span>
<span id="cb11-14">        )</span>
<span id="cb11-15"></span>
<span id="cb11-16">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> fit(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, X, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>):</span>
<span id="cb11-17">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># check input type</span></span>
<span id="cb11-18">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">isinstance</span>(X, pd.DataFrame):</span>
<span id="cb11-19">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">raise</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">ValueError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Input must be a DataFrame."</span>)</span>
<span id="cb11-20"></span>
<span id="cb11-21">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># rename columns for consistency</span></span>
<span id="cb11-22">        X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.rename(</span>
<span id="cb11-23">            columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{</span>
<span id="cb11-24">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_directed_by"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"director"</span>,</span>
<span id="cb11-25">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_written_by"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"writer"</span>,</span>
<span id="cb11-26">            }</span>
<span id="cb11-27">        )</span>
<span id="cb11-28"></span>
<span id="cb11-29">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fit one-hot encoders on expanded and encoded data</span></span>
<span id="cb11-30">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.ohe_directors.fit(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>._expand_and_encode(X[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"director"</span>]))</span>
<span id="cb11-31">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.ohe_writers.fit(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>._expand_and_encode(X[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"writer"</span>]))</span>
<span id="cb11-32"></span>
<span id="cb11-33">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span></span>
<span id="cb11-34"></span>
<span id="cb11-35">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> transform(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, X, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>):</span>
<span id="cb11-36">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># check input type</span></span>
<span id="cb11-37">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">isinstance</span>(X, pd.DataFrame):</span>
<span id="cb11-38">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">raise</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">ValueError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Input must be a DataFrame."</span>)</span>
<span id="cb11-39"></span>
<span id="cb11-40">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># rename columns for consistency</span></span>
<span id="cb11-41">        X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.rename(</span>
<span id="cb11-42">            columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{</span>
<span id="cb11-43">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_directed_by"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"director"</span>,</span>
<span id="cb11-44">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_written_by"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"writer"</span>,</span>
<span id="cb11-45">            }</span>
<span id="cb11-46">        )</span>
<span id="cb11-47"></span>
<span id="cb11-48">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># expand and encode director and writer columns</span></span>
<span id="cb11-49">        directors_expanded <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>._expand_and_encode(X[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"director"</span>])</span>
<span id="cb11-50">        writers_expanded <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>._expand_and_encode(X[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"writer"</span>])</span>
<span id="cb11-51"></span>
<span id="cb11-52">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># apply one-hot encoding</span></span>
<span id="cb11-53">        transformed_directors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.ohe_directors.transform(directors_expanded)</span>
<span id="cb11-54">        transformed_writers <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.ohe_writers.transform(writers_expanded)</span>
<span id="cb11-55"></span>
<span id="cb11-56">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># create dataframes with meaningful column names</span></span>
<span id="cb11-57">        directors_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb11-58">            pd.DataFrame(</span>
<span id="cb11-59">                transformed_directors,</span>
<span id="cb11-60">                index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>directors_expanded.index,</span>
<span id="cb11-61">                columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[</span>
<span id="cb11-62">                    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"director_</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>col<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb11-63">                    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> col <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.ohe_directors.get_feature_names_out()</span>
<span id="cb11-64">                ],</span>
<span id="cb11-65">            )</span>
<span id="cb11-66">            .groupby(level<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb11-67">            .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># aggregate back to original index level</span></span>
<span id="cb11-68">        )</span>
<span id="cb11-69"></span>
<span id="cb11-70">        writers_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb11-71">            pd.DataFrame(</span>
<span id="cb11-72">                transformed_writers,</span>
<span id="cb11-73">                index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>writers_expanded.index,</span>
<span id="cb11-74">                columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[</span>
<span id="cb11-75">                    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"writer_</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>col<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> col <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.ohe_writers.get_feature_names_out()</span>
<span id="cb11-76">                ],</span>
<span id="cb11-77">            )</span>
<span id="cb11-78">            .groupby(level<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb11-79">            .<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># aggregate back to original index level</span></span>
<span id="cb11-80">        )</span>
<span id="cb11-81"></span>
<span id="cb11-82">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># merge transformed features and fill missing values with zero</span></span>
<span id="cb11-83">        transformed_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> directors_df.join(writers_df, how<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outer"</span>).fillna(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb11-84"></span>
<span id="cb11-85">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> transformed_df.values  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># return as numpy array</span></span>
<span id="cb11-86"></span>
<span id="cb11-87">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> _expand_and_encode(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, series):</span>
<span id="cb11-88">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ensure series is categorical</span></span>
<span id="cb11-89">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">isinstance</span>(series.dtype, pd.CategoricalDtype):</span>
<span id="cb11-90">            series <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> series.astype(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"category"</span>)</span>
<span id="cb11-91"></span>
<span id="cb11-92">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># add 'unknown' category if missing</span></span>
<span id="cb11-93">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Unknown"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> series.cat.categories:</span>
<span id="cb11-94">            series <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> series.cat.add_categories([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Unknown"</span>])</span>
<span id="cb11-95"></span>
<span id="cb11-96">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fill missing values with 'unknown'</span></span>
<span id="cb11-97">        series <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> series.fillna(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Unknown"</span>)</span>
<span id="cb11-98"></span>
<span id="cb11-99">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># split multi-value strings into separate rows</span></span>
<span id="cb11-100">        exploded <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> series.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.split(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" &amp; "</span>).explode()</span>
<span id="cb11-101"></span>
<span id="cb11-102">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># standardise formatting (lowercase, replace spaces with underscores)</span></span>
<span id="cb11-103">        exploded <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> exploded.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.lower().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>.replace(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_"</span>)</span>
<span id="cb11-104"></span>
<span id="cb11-105">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> exploded.to_frame()  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># return as a dataframe</span></span></code></pre></div></div>
</details>
</div>
<p>With the help of ChatGPT<sup>5</sup>, I created a custom transformer class that explodes and formats the categorical columns—episode writers and directors—before one-hot encoding each of the individual writers/directors per episode.</p>
<div id="preprocessing" class="cell" data-execution_count="12">
<details class="code-fold">
<summary>Data Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">categorical_features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_written_by"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wikipedia_directed_by"</span>]</span>
<span id="cb12-2">numeric_features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb12-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"season"</span>,</span>
<span id="cb12-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"episode_overall"</span>,</span>
<span id="cb12-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dialogue_density"</span>,</span>
<span id="cb12-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"unique_words"</span>,</span>
<span id="cb12-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"question_ratio"</span>,</span>
<span id="cb12-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"exclamation_ratio"</span>,</span>
<span id="cb12-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"avg_length"</span>,</span>
<span id="cb12-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sentiment_variance"</span>,</span>
<span id="cb12-11">]</span>
<span id="cb12-12"></span>
<span id="cb12-13">categorical_transformer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline(</span>
<span id="cb12-14">    steps<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"explode_encode"</span>, ExplodeAndEncode(min_frequency<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))]</span>
<span id="cb12-15">)</span>
<span id="cb12-16"></span>
<span id="cb12-17">numeric_transformer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline(steps<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"imputer"</span>, IterativeImputer())])</span>
<span id="cb12-18"></span>
<span id="cb12-19">col_transformer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ColumnTransformer(</span>
<span id="cb12-20">    transformers<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[</span>
<span id="cb12-21">        (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"num"</span>, numeric_transformer, numeric_features),</span>
<span id="cb12-22">        (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cat"</span>, categorical_transformer, categorical_features),</span>
<span id="cb12-23">    ]</span>
<span id="cb12-24">)</span>
<span id="cb12-25"></span>
<span id="cb12-26">preprocessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline(steps<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"col_transformer"</span>, col_transformer)])</span></code></pre></div></div>
</details>
</div>
<p>To prevent the newly created binary features from markedly expanding the data’s dimensionality and sparsity, I have restricted the one-hot encoding to those credited with a minimum of five episodes.</p>
</section>
</section>
<section id="model-training" class="level2">
<h2 class="anchored" data-anchor-id="model-training">Model Training</h2>
<p>I’ll start with a baseline model and then a relatively simple model to compare against. This is always a good starting point, especially when there’s a reasonable chance your model will be garbage. You need to make sure you are at <strong>least</strong> able to build a model that performs better than taking the most basic baseline predictions.</p>
<p>The baseline model predicts that all test set values will equal the mean IMDb ratings in the training set.</p>
<div id="baseline-model" class="cell" data-execution_count="13">
<details class="code-fold">
<summary>Model Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">baseline_model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DummyRegressor(strategy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>)</span>
<span id="cb13-2"></span>
<span id="cb13-3">baseline_model.fit(X_train, y_train)</span>
<span id="cb13-4"></span>
<span id="cb13-5">baseline_preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> baseline_model.predict(X_test)</span>
<span id="cb13-6"></span>
<span id="cb13-7">baseline_rmse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> root_mean_squared_error(y_test, baseline_preds)</span></code></pre></div></div>
</details>
</div>
<p>The RMSE for the baseline model is <strong>0.430</strong>. This gives us a target to try and beat. If we can’t do better than this, we should pack it in and not spend a moment more on this nonsense. Remember to blame the tools, though. It’s certainly not my fault.</p>
<p>I have also built a linear regression to compare against the baseline and help evaluate whether a more complex model is worth the effort. Linear regressions are straightforward. Despite this, they are capable of remarkable performance and typically generalise very well.</p>
<div id="linear-regression" class="cell" data-execution_count="14">
<details class="code-fold">
<summary>Model Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">pipeline <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline(</span>
<span id="cb14-2">    steps<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"preprocessor"</span>, preprocessor), (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"regressor"</span>, LinearRegression())]</span>
<span id="cb14-3">)</span>
<span id="cb14-4"></span>
<span id="cb14-5">pipeline.fit(X_train, y_train)</span>
<span id="cb14-6"></span>
<span id="cb14-7">lm_preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipeline.predict(X_test)</span>
<span id="cb14-8"></span>
<span id="cb14-9">lm_rmse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> root_mean_squared_error(y_test, lm_preds)</span></code></pre></div></div>
</details>
</div>
<p>The linear regression returns a score of <strong>0.415</strong>, which beats the baseline. We can use both these models as a good starting point, but the linear regression performance is the new target to beat.</p>
<section id="model-selection" class="level3">
<h3 class="anchored" data-anchor-id="model-selection">Model Selection</h3>
<p>I decided to stick with algorithms provided by scikit-learn, choosing <a href="https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html">random forests</a> <span class="citation" data-cites="breiman2001">(Breiman 2001)</span>, <a href="https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.ExtraTreesRegressor.html">extremely randomised trees</a> (Extra Trees in scikit-learn) <span class="citation" data-cites="geurts2006">(Geurts et al. 2006)</span>, and <a href="https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.GradientBoostingRegressor.html">gradient boosting</a> <span class="citation" data-cites="friedman2001">(Friedman 2001)</span>.</p>
<p>Random forests<sup>6</sup> and extra trees are bagging ensembles combining multiple decision trees by averaging their predictions. The key difference between the two is that random forests use bootstrapped samples of the data for each tree instead of the entire sample (though you can choose to use this feature in scikit-learn’s extra trees implementation, too), and extra trees split tree nodes randomly, to induce more variance between trees. Gradient boosting<sup>7</sup> combines an ensemble of weak models (typically decision trees) in a sequential, additive fashion. The sequential process, called boosting, allows each model to learn from all that precede it.</p>
<p>I am testing the performance of these algorithms by tuning a couple key hyperparameters for each, split over five folds using <a href="https://mlu-explain.github.io/cross-validation/">k-fold cross-validation</a>. The goal is that this should identify the algorithm that gives us the best opportunity for maximising performance. I am using <a href="https://optuna.org">Optuna</a> for <a href="https://maelfabien.github.io/machinelearning/Explorium4/">hyperparameter optimisation</a> (here and throughout the rest of this post)<sup>8</sup>. Optuna’s default optimisation strategy is Bayesian optimisation using <a href="https://anna-ssi.github.io/blog/tpe/">tree-structured parzen estimators</a>, and I’ve always had good luck with it.</p>
<div id="model-selection" class="cell" data-cache="true" data-execution_count="15">
<details class="code-fold">
<summary>Model Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1">rmse_scorer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_scorer(root_mean_squared_error, greater_is_better<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb15-2"></span>
<span id="cb15-3"></span>
<span id="cb15-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> objective(trial):</span>
<span id="cb15-5">    regressor_name <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> trial.suggest_categorical(</span>
<span id="cb15-6">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"regressor"</span>, [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RandomForest"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ExtraTrees"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GradientBoosting"</span>]</span>
<span id="cb15-7">    )</span>
<span id="cb15-8"></span>
<span id="cb15-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> regressor_name <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RandomForest"</span>:</span>
<span id="cb15-10">        n_estimators <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> trial.suggest_int(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n_estimators"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>, step<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)</span>
<span id="cb15-11">        max_features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> trial.suggest_float(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max_features"</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, step<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)</span>
<span id="cb15-12">        model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> RandomForestRegressor(</span>
<span id="cb15-13">            n_estimators<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_estimators, max_features<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>max_features</span>
<span id="cb15-14">        )</span>
<span id="cb15-15"></span>
<span id="cb15-16">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">elif</span> regressor_name <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ExtraTrees"</span>:</span>
<span id="cb15-17">        n_estimators <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> trial.suggest_int(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n_estimators"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>, step<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)</span>
<span id="cb15-18">        max_features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> trial.suggest_float(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max_features"</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, step<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)</span>
<span id="cb15-19">        model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ExtraTreesRegressor(</span>
<span id="cb15-20">            n_estimators<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_estimators, max_features<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>max_features</span>
<span id="cb15-21">        )</span>
<span id="cb15-22"></span>
<span id="cb15-23">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb15-24">        n_estimators <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> trial.suggest_int(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n_estimators"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>, step<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)</span>
<span id="cb15-25">        learning_rate <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> trial.suggest_float(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"learning_rate"</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, step<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>)</span>
<span id="cb15-26">        model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> GradientBoostingRegressor(</span>
<span id="cb15-27">            n_estimators<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n_estimators, learning_rate<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>learning_rate</span>
<span id="cb15-28">        )</span>
<span id="cb15-29"></span>
<span id="cb15-30">    pipeline <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"preprocesser"</span>, preprocessor), (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"regressor"</span>, model)])</span>
<span id="cb15-31"></span>
<span id="cb15-32">    kf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KFold(n_splits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb15-33">    scores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cross_val_score(</span>
<span id="cb15-34">        pipeline, X_train, np.ravel(y_train), cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>kf, scoring<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>rmse_scorer</span>
<span id="cb15-35">    )</span>
<span id="cb15-36"></span>
<span id="cb15-37">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>scores.mean()</span>
<span id="cb15-38"></span>
<span id="cb15-39"></span>
<span id="cb15-40">select_model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> optuna.create_study(direction<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"minimize"</span>)</span>
<span id="cb15-41">select_model.optimize(objective, n_trials<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)</span></code></pre></div></div>
</details>
</div>
<p>I’m not especially concerned with model performance during this step; it’s just a comparison between algorithms. The study suggests <strong>RandomForest</strong> is the best of the bunch.</p>
</section>
<section id="hyperparameter-tuning" class="level3">
<h3 class="anchored" data-anchor-id="hyperparameter-tuning">Hyperparameter Tuning</h3>
<p>Now, we can get knee-deep in filth, searching for the best hyperparameter values for optimising our random forest. The setup is more or less the same as in the previous section; here, we are digging deeper into one algorithm and beefing up the total number of trials in the study.</p>
<p>The study below includes several more hyperparameters. The search space for the hyperparameters is relatively modest. I have tried to keep the model simple to reflect the data, and I have iteratively refined the study to narrow the hyperparameter values and speed up the tuning. Finally, I’ve also tried to set some constraints to help the model avoid overfitting.</p>
<div id="random-forest" class="cell" data-cache="true" data-execution_count="16">
<details class="code-fold">
<summary>Model Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> objective(trial):</span>
<span id="cb16-2"></span>
<span id="cb16-3">    rf_params <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb16-4">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n_estimators"</span>: trial.suggest_int(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n_estimators"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">250</span>),</span>
<span id="cb16-5">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max_features"</span>: trial.suggest_float(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max_features"</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>),</span>
<span id="cb16-6">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max_samples"</span>: trial.suggest_float(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max_samples"</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>),</span>
<span id="cb16-7">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max_depth"</span>: trial.suggest_int(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"max_depth"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>),</span>
<span id="cb16-8">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"min_samples_split"</span>: trial.suggest_int(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"min_samples_split"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>),</span>
<span id="cb16-9">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"criterion"</span>: trial.suggest_categorical(</span>
<span id="cb16-10">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"criterion"</span>, [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"poisson"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"friedman_mse"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"squared_error"</span>]</span>
<span id="cb16-11">        ),</span>
<span id="cb16-12">    }</span>
<span id="cb16-13"></span>
<span id="cb16-14">    model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> RandomForestRegressor(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span>rf_params, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb16-15"></span>
<span id="cb16-16">    pipeline <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"preprocessor"</span>, preprocessor), (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"regressor"</span>, model)])</span>
<span id="cb16-17"></span>
<span id="cb16-18">    kf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KFold(n_splits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb16-19">    scores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cross_val_score(</span>
<span id="cb16-20">        pipeline, X_train, np.ravel(y_train), cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>kf, scoring<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>rmse_scorer</span>
<span id="cb16-21">    )</span>
<span id="cb16-22"></span>
<span id="cb16-23">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>scores.mean()</span>
<span id="cb16-24"></span>
<span id="cb16-25"></span>
<span id="cb16-26">tuned_rf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> optuna.create_study(direction<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"minimize"</span>)</span>
<span id="cb16-27">tuned_rf.optimize(objective, n_trials<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)</span></code></pre></div></div>
</details>
</div>
<p>The tuned random forest produces an RMSE of <strong>0.395</strong>. Comparisons with the baselines don’t work because they are fit to the test data, while this is the performance of the best trial on the training data<sup>9</sup>. The hope is that how the tuning is set up will make the model’s performance on the training data generalisable. Given the small sample we’re working with, there could be plenty of variance, so while our model shows promise, we can’t draw conclusions yet.</p>
<p>Table&nbsp;5 below shows the tuned hyperparameter values.</p>
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1">(</span>
<span id="cb17-2">    GT(</span>
<span id="cb17-3">        pd.DataFrame(</span>
<span id="cb17-4">            tuned_rf.best_trial.params.items(), columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Hyperparameter"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Value"</span>]</span>
<span id="cb17-5">        ).assign(</span>
<span id="cb17-6">            Value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Value"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">apply</span>(</span>
<span id="cb17-7">                <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> x: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(x, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">isinstance</span>(x, (<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> x</span>
<span id="cb17-8">            )</span>
<span id="cb17-9">        )</span>
<span id="cb17-10">    )</span>
<span id="cb17-11">    .cols_align(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Value"</span>, align<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>)</span>
<span id="cb17-12">    .tab_source_note(source_note<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span>)</span>
<span id="cb17-13">    .tab_options(table_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"100%"</span>)</span>
<span id="cb17-14">)</span></code></pre></div></div>
</details>
<div id="tbl-hyperparameters" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-hyperparameters-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;5: Optimised Random Forest Hyperparameters
</figcaption>
<div aria-describedby="tbl-hyperparameters-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div id="cell-tuned-hyperparameters" class="cell" data-execution_count="17">
<div id="tuned-hyperparameters" class="cell-output cell-output-display" data-execution_count="17">
<div id="gfmeokwuno" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#gfmeokwuno table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

#gfmeokwuno thead, tbody, tfoot, tr, td, th { border-style: none; }
 tr { background-color: transparent; }
#gfmeokwuno p { margin: 0; padding: 0; }
 #gfmeokwuno .gt_table { display: table; border-collapse: collapse; line-height: normal; margin-left: auto; margin-right: auto; color: #333333; font-size: 16px; font-weight: normal; font-style: normal; background-color: #FFFFFF; width: 100%; border-top-style: solid; border-top-width: 2px; border-top-color: #A8A8A8; border-right-style: none; border-right-width: 2px; border-right-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #A8A8A8; border-left-style: none; border-left-width: 2px; border-left-color: #D3D3D3; }
 #gfmeokwuno .gt_caption { padding-top: 4px; padding-bottom: 4px; }
 #gfmeokwuno .gt_title { color: #333333; font-size: 125%; font-weight: initial; padding-top: 4px; padding-bottom: 4px; padding-left: 5px; padding-right: 5px; border-bottom-color: #FFFFFF; border-bottom-width: 0; }
 #gfmeokwuno .gt_subtitle { color: #333333; font-size: 85%; font-weight: initial; padding-top: 3px; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; border-top-color: #FFFFFF; border-top-width: 0; }
 #gfmeokwuno .gt_heading { background-color: #FFFFFF; text-align: center; border-bottom-color: #FFFFFF; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; }
 #gfmeokwuno .gt_bottom_border { border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; }
 #gfmeokwuno .gt_col_headings { border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; }
 #gfmeokwuno .gt_col_heading { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: normal; text-transform: inherit; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; }
 #gfmeokwuno .gt_column_spanner_outer { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: normal; text-transform: inherit; padding-top: 0; padding-bottom: 0; padding-left: 4px; padding-right: 4px; }
 #gfmeokwuno .gt_column_spanner_outer:first-child { padding-left: 0; }
 #gfmeokwuno .gt_column_spanner_outer:last-child { padding-right: 0; }
 #gfmeokwuno .gt_column_spanner { border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 5px; overflow-x: hidden; display: inline-block; width: 100%; }
 #gfmeokwuno .gt_spanner_row { border-bottom-style: hidden; }
 #gfmeokwuno .gt_group_heading { padding-top: 8px; padding-bottom: 8px; padding-left: 5px; padding-right: 5px; color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; text-align: left; }
 #gfmeokwuno .gt_empty_group_heading { padding: 0.5px; color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; vertical-align: middle; }
 #gfmeokwuno .gt_from_md> :first-child { margin-top: 0; }
 #gfmeokwuno .gt_from_md> :last-child { margin-bottom: 0; }
 #gfmeokwuno .gt_row { padding-top: 8px; padding-bottom: 8px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; }
 #gfmeokwuno .gt_stub { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-right-style: solid; border-right-width: 2px; border-right-color: #D3D3D3; padding-left: 5px; padding-right: 5px; }
 #gfmeokwuno .gt_stub_row_group { color: #333333; background-color: #FFFFFF; font-size: 100%; font-weight: initial; text-transform: inherit; border-right-style: solid; border-right-width: 2px; border-right-color: #D3D3D3; padding-left: 5px; padding-right: 5px; vertical-align: top; }
 #gfmeokwuno .gt_row_group_first td { border-top-width: 2px; }
 #gfmeokwuno .gt_row_group_first th { border-top-width: 2px; }
 #gfmeokwuno .gt_striped { background-color: rgba(128,128,128,0.05); }
 #gfmeokwuno .gt_table_body { border-top-style: solid; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #D3D3D3; }
 #gfmeokwuno .gt_sourcenotes { color: #333333; background-color: #FFFFFF; border-bottom-style: none; border-bottom-width: 2px; border-bottom-color: #D3D3D3; border-left-style: none; border-left-width: 2px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 2px; border-right-color: #D3D3D3; }
 #gfmeokwuno .gt_sourcenote { font-size: 90%; padding-top: 4px; padding-bottom: 4px; padding-left: 5px; padding-right: 5px; text-align: left; }
 #gfmeokwuno .gt_left { text-align: left; }
 #gfmeokwuno .gt_center { text-align: center; }
 #gfmeokwuno .gt_right { text-align: right; font-variant-numeric: tabular-nums; }
 #gfmeokwuno .gt_font_normal { font-weight: normal; }
 #gfmeokwuno .gt_font_bold { font-weight: bold; }
 #gfmeokwuno .gt_font_italic { font-style: italic; }
 #gfmeokwuno .gt_super { font-size: 65%; }
 #gfmeokwuno .gt_footnote_marks { font-size: 75%; vertical-align: 0.4em; position: initial; }
 #gfmeokwuno .gt_asterisk { font-size: 100%; vertical-align: 0; }
 
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="Hyperparameter" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Hyperparameter</th>
<th id="Value" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Value</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left">n_estimators</td>
<td class="gt_row gt_center">118</td>
</tr>
<tr class="even">
<td class="gt_row gt_left">max_features</td>
<td class="gt_row gt_center">0.34</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left">max_samples</td>
<td class="gt_row gt_center">0.72</td>
</tr>
<tr class="even">
<td class="gt_row gt_left">max_depth</td>
<td class="gt_row gt_center">14</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left">min_samples_split</td>
<td class="gt_row gt_center">25</td>
</tr>
<tr class="even">
<td class="gt_row gt_left">criterion</td>
<td class="gt_row gt_center">friedman_mse</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="2" class="gt_sourcenote">Data: {bobsburgersR} (via TidyTuesday)</td>
</tr>
</tfoot>

</table>


</div>
</div>
</div>
</div>
</figure>
</div>
<p>The hyperparameters are mostly tailored to optimise the training data, with some thought towards what is appropriate given the sample size. I have constrained the maximum features and samples to make the model more generalisable.</p>
</section>
</section>
<section id="model-evaluation" class="level2">
<h2 class="anchored" data-anchor-id="model-evaluation">Model Evaluation</h2>
<p>Having tuned the hyperparameters, we should hopefully have a model that gives us the best performance on our test set.</p>
<div id="final-model" class="cell" data-cache="true" data-execution_count="18">
<details class="code-fold">
<summary>Model Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">best_params <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tuned_rf.best_params</span>
<span id="cb18-2"></span>
<span id="cb18-3">best_rf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> RandomForestRegressor(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span>best_params, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb18-4"></span>
<span id="cb18-5">pipeline <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"preprocessor"</span>, preprocessor), (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"regressor"</span>, best_rf)])</span>
<span id="cb18-6"></span>
<span id="cb18-7">pipeline.fit(X_train, np.ravel(y_train))</span>
<span id="cb18-8"></span>
<span id="cb18-9">rf_preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipeline.predict(X_test)</span>
<span id="cb18-10"></span>
<span id="cb18-11">rf_rmse <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> root_mean_squared_error(np.ravel(y_test), rf_preds)</span></code></pre></div></div>
</details>
</div>
<p>The model improves on the baseline (<strong>0.430</strong>) and the linear regression (<strong>0.415</strong>) to achieve an RMSE of <strong>0.367</strong>. That is a ~15% improvement on the baseline and ~11% on the linear model<sup>10</sup>. This is not nothing!</p>
<section id="visualising-model-error" class="level3">
<h3 class="anchored" data-anchor-id="visualising-model-error">Visualising Model Error</h3>
<div id="test-errors" class="cell" data-execution_count="19">
<details class="code-fold">
<summary>Data Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1">test_errors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb19-2">    pd.DataFrame(rf_preds.T, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prediction"</span>])</span>
<span id="cb19-3">    .assign(actual<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y_test.values)</span>
<span id="cb19-4">    .assign(error<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prediction"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"actual"</span>])</span>
<span id="cb19-5">    .assign(abs_error<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> df: <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"error"</span>]))</span>
<span id="cb19-6">    .join(X_test.reset_index(drop<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>))</span>
<span id="cb19-7">)</span></code></pre></div></div>
</details>
</div>
<p>Our final model beats both baselines, but I’m sure there remains room for improvement. If we wanted to iteratively fine-tune the model to squeeze out some extra drops of joy, the best place to start would be to understand what the model is getting wrong. There are a few ways to go about this. I will gather the predicted ratings, actual ratings, and prediction error (raw and absolute values) and visualise the model’s performance to see what jumps out.</p>
<p>The distribution of prediction error, plotted below, serves as a quick check that there is no obvious indication that the model is misbehaving. If there is some wild skew in errors or several substantial outliers, this might be cause for concern, but the errors appear to be distributed approximately normally.</p>
<div id="cell-error-dist" class="cell" data-execution_count="20">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">(</span>
<span id="cb20-2">    ggplot(test_errors, aes(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"error"</span>))</span>
<span id="cb20-3">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_histogram(binwidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, colour<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>)</span>
<span id="cb20-4">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_hline(yintercept<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, colour<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>)</span>
<span id="cb20-5">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> labs(</span>
<span id="cb20-6">        title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Distribution of Bob's Burgers Episode Ratings Prediction Error"</span>,</span>
<span id="cb20-7">        subtitle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(</span>
<span id="cb20-8">            textwrap.fill(</span>
<span id="cb20-9">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The distribution of prediction errors for predicted IMDb user ratings "</span></span>
<span id="cb20-10">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"for each episode of Bob's Burgers in the test dataset. Errors peak at "</span></span>
<span id="cb20-11">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"just above zero but the negative errors have a longer tail."</span>,</span>
<span id="cb20-12">                width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>,</span>
<span id="cb20-13">            )</span>
<span id="cb20-14">        ),</span>
<span id="cb20-15">        x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Prediction Error"</span>,</span>
<span id="cb20-16">        y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>,</span>
<span id="cb20-17">        caption<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span>,</span>
<span id="cb20-18">    )</span>
<span id="cb20-19">)</span></code></pre></div></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/index_files/figure-html/error-dist-output-1.png" id="error-dist" alt="A histogram visualising the distribution of prediction errors for the random forest predicting Bob's Burgers IMDb user ratings. While the majority of errors appear to be positive and the distribution peaks just above zero, the negative errors have a longer tail." width="672" height="480" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>With less than 100 observations in the test dataset, it requires a bit of squinting to make some assumptions about the distribution we’d see with a larger sample. Still, nothing concerning jumps out at a glance. The distribution peaks slightly above zero, but the negative errors have a longer tail. There appears to be one outlier that the model struggled with, underestimating the rating by more than one (which is quite a lot when considering the ratings are out of 10).</p>
<p>We can also plot the predicted and actual ratings below to compare the model’s misses more directly.</p>
<div id="cell-predicted-vs-actual" class="cell" data-cache="true" data-execution_count="21">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1">(</span>
<span id="cb21-2">    ggplot(test_errors, aes(x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prediction"</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"actual"</span>))</span>
<span id="cb21-3">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_point(size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, stroke<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, fill<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>, shape<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>)</span>
<span id="cb21-4">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_smooth(method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lm"</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, se<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>)</span>
<span id="cb21-5">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> labs(</span>
<span id="cb21-6">        title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicted vs Actual Bob's Burgers Episode Ratings"</span>,</span>
<span id="cb21-7">        subtitle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(</span>
<span id="cb21-8">            textwrap.fill(</span>
<span id="cb21-9">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Comparing predicted Bob's Burgers ratings and their actual IMDb user "</span></span>
<span id="cb21-10">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ratings for each episode in the test dataset. On average, predictions "</span></span>
<span id="cb21-11">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"appear to slightly overrate episodes."</span>,</span>
<span id="cb21-12">                width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>,</span>
<span id="cb21-13">            )</span>
<span id="cb21-14">        ),</span>
<span id="cb21-15">        x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicted Rating"</span>,</span>
<span id="cb21-16">        y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IMDb Rating"</span>,</span>
<span id="cb21-17">        caption<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span>,</span>
<span id="cb21-18">    )</span>
<span id="cb21-19">)</span></code></pre></div></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/index_files/figure-html/predicted-vs-actual-output-1.png" id="predicted-vs-actual" alt="A regression plot visualising the relationship between predicted and actual ratings for the random forest model predicting Bob's Burgers IMDb user ratings. On average, pedictions seem to overrate episode ratings." width="672" height="480" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>Visualising predictions against actual ratings shows that the model slightly overrates episodes. While there’s plenty of noise, nothing jumps out as an obvious problem. Besides a single pesky outlier, nothing in these first two plots points to areas to try and squeeze out additional performance improvements.</p>
<p>Finally, we can visualise the relationship between prediction error and actual ratings. We are interested in the magnitude of the error, not the direction, so I’ve used absolute prediction error. This highlights the target values the model struggled to predict, and the trend in the error distribution is immediately apparent.</p>
<div id="cell-absolute-error" class="cell" data-execution_count="22">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1">(</span>
<span id="cb22-2">    ggplot(test_errors, aes(x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"actual"</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"abs_error"</span>))</span>
<span id="cb22-3">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_point(size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, stroke<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, fill<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>, shape<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"o"</span>)</span>
<span id="cb22-4">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> geom_smooth(size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, se<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>)</span>
<span id="cb22-5">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> labs(</span>
<span id="cb22-6">        title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Absolute Prediction Error by Bob's Burgers Episode Ratings"</span>,</span>
<span id="cb22-7">        subtitle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(</span>
<span id="cb22-8">            textwrap.fill(</span>
<span id="cb22-9">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Comparing absolute prediction error of predicted Bob's Burgers' "</span></span>
<span id="cb22-10">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"episode ratings and actual IMDb user ratings. Errors are larger "</span></span>
<span id="cb22-11">                <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"at the extreme ends of the ratings."</span>,</span>
<span id="cb22-12">                width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">85</span>,</span>
<span id="cb22-13">            )</span>
<span id="cb22-14">        ),</span>
<span id="cb22-15">        x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IMDb Rating"</span>,</span>
<span id="cb22-16">        y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Absolute Predcition Error"</span>,</span>
<span id="cb22-17">        caption<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{bobsburgersR}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> (via TidyTuesday)"</span>,</span>
<span id="cb22-18">    )</span>
<span id="cb22-19">)</span></code></pre></div></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/index_files/figure-html/absolute-error-output-1.png" id="absolute-error" alt="A regression plot visualising the relationship between IMDb ratings and the absolute prediction error for the random forest model predicting Bob's Burgers ratings. While the model performs relatively well, it struggles at the extreme ends of the ratings." width="672" height="480" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>The model struggles with values at the extreme ends of the target distribution. Most observations in the dataset fall between 7 and 8, and the mean absolute error for episodes in this range in the test set is ~0.2. In fact, the trough in the prediction errors is between 7.5 and 8 and rises quickly once the rating value moves in either direction.</p>
<p>The observation with a rating of over 9 is driving a big spike. The episode responsible is —<em>The Haunting</em> (S6E3). I suspect an indicator that an episode is a “special” of some description (episodes relevant to public holidays, like Christmas and Halloween, extended episodes, or any one-off episodes) would minimise the issues the model seems to be having with very high ratings.</p>
<p>To me, the issue appears to be the sample size. The model handles the well-populated target value ranges but struggles once it gets into the ranges with tiny sample sizes. We just need more episodes.</p>
</section>
</section>
<section id="final-thoughts" class="level2">
<h2 class="anchored" data-anchor-id="final-thoughts">Final Thoughts</h2>
<p>Was this a good use of my time? No, but did we learn something? Also no. Perhaps there’s a moral to this story? Still, no. There is no big reveal. I’m just this stupid. My sincere apologies.</p>
<p>This is the product of my playing around with a fun dataset seeing what I can produce. A more concerted effort to predict Bob’s Burgers episode ratings would involve more exploratory work, including bringing in additional data, particularly the episode dialogue data. Dimensionality reduction methods, such as <a href="https://www.youtube.com/watch?v=FgakZw6K1QQ">principal component analysis</a> (PCA), would have added much value. The process of splitting out and one-hot encoding the writers and directors induced a bunch of sparsity that is probably hampering the model. Using PCA would simplify the data, and given the high chance that many features are not moving the needle that much, I suspect it would do so without losing much predictive value.</p>
<p>Beyond the gains that could be achieved with the data, I think it’s likely that other gradient boosting algorithms would probably beat out the random forest we’ve used here. I chose to limit myself to the models that scikit-learn provides for brevity (and for a bit of a change of pace), but XGBoost, LightGBM, and CatBoost are incredibly popular for a reason. They regularly beat their competition when dealing with structured data.</p>
<p>Despite being limited in scope, I hope this post’s limitations are also illustrative. If not, then at least I had fun. I guess we can’t turn TV shows into spreadsheets just yet.</p>
</section>




<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Preview image by <a href="https://unsplash.com/@s_tsuchiya">S. Tsuchiya</a> on <a href="https://unsplash.com/photos/red-and-white-round-signage-P48JzJc-GhQ">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>



</div></section><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-breiman2001" class="csl-entry">
Breiman, Leo. 2001. <span>“Random Forests.”</span> <em>Machine Learning</em> 45: 5–32.
</div>
<div id="ref-friedman2001" class="csl-entry">
Friedman, Jerome H. 2001. <span>“Greedy Function Approximation: A Gradient Boosting Machine.”</span> <em>Annals of Statistics</em>, 1189–232.
</div>
<div id="ref-geurts2006" class="csl-entry">
Geurts, Pierre, Damien Ernst, and Louis Wehenkel. 2006. <span>“Extremely Randomized Trees.”</span> <em>Machine Learning</em> 63: 3–42.
</div>
<div id="ref-heaven2022" class="csl-entry">
Heaven, Will Douglas. 2022. <span>“This Is the Reason Demis Hassabis Started DeepMind.”</span> <em>MIT Technology Review</em>. <a href="https://www.technologyreview.com/2022/02/23/1045016/ai-deepmind-demis-hassabis-alphafold/">https://www.technologyreview.com/2022/02/23/1045016/ai-deepmind-demis-hassabis-alphafold/</a>.
</div>
<div id="ref-jumper2021" class="csl-entry">
<span class="nocase">Jumper, John, Richard Evans, Alexander Pritzel, et al.</span> 2021. <span>“Highly Accurate Protein Structure Prediction with AlphaFold.”</span> <em>Nature</em> 596 (7873): 583–89. <a href="https://www.nature.com/articles/s41586-021-03819-2">https://www.nature.com/articles/s41586-021-03819-2</a>.
</div>
<div id="ref-service2020" class="csl-entry">
Service, Robert F. 2020. <span>“‘The Game Has Changed.’ AI Triumphs at Solving Protein Structures.”</span> <em>Science</em>. <a href="https://www.science.org/content/article/game-has-changed-ai-triumphs-solving-protein-structures">https://www.science.org/content/article/game-has-changed-ai-triumphs-solving-protein-structures</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>My initial reaction to viewership’s strong correlation with ratings was that this made sense, but as soon as I tried to explain why, I realised, I had the direction of causality mixed up.↩︎</p></li>
<li id="fn2"><p>The other categorical features are the episode title and synopsis, which might include some helpful signal but would require some effort to extract. The date the episode aired is also categorical, but only because I haven’t bothered to convert it (having done some digging and found that there doesn’t appear to be any seasonality or anything to work with).↩︎</p></li>
<li id="fn3"><p>If I were spending more time on this, I would explore any interactions, but I think we can get away with chucking all the potentially valuable features into the mixer here and saving some time.↩︎</p></li>
<li id="fn4"><p>I’d highly recommend Emil Hvitfeldt’s <a href="https://feaz-book.com/"><em>Feature Engineering A-Z</em></a>, a comprehensive resource on the endless possibilities of feature engineering.↩︎</p></li>
<li id="fn5"><p>I haven’t had much experience building custom transformers like this, so I needed a helping hand.↩︎</p></li>
<li id="fn6"><p>For an intuition into random forests (and, by extension, extra trees, too), I’d recommend <a href="https://mlu-explain.github.io/random-forest/">MLU-Explain</a>’s explainer.↩︎</p></li>
<li id="fn7"><p>For an intuition into gradient boosting (and all its variants), I’d recommend Terence Parr &amp; Jeremy Howard’s <a href="https://explained.ai/gradient-boosting/"><em>How to Explain Gradient Boosting</em></a>↩︎</p></li>
<li id="fn8"><p>There are other hyperparameter optimisation libraries, such as HyerOpt, and scikit-learn, which offers tuning functionality of its own, but Optuna is the most <a href="https://neptune.ai/blog/optuna-vs-hyperopt">feature-rich</a>. Perhaps the focus should be on <a href="https://trainindata.substack.com/p/choose-the-library-based-on-the-method">methods, not libraries</a>, but in my experience, Optuna’s methods also provide excellent performance.↩︎</p></li>
<li id="fn9"><p>A validation set or a more involved process like nested cross-validation would add some value. I don’t think we have enough data for a validation set, and I decided a fully nested pipeline was overkill, but I’m sure it would be beneficial.↩︎</p></li>
<li id="fn10"><p>Some simple preprocessing steps could improve the linear regression, potentially making it competitive with our final model. If I intended to put this into production, I’d be tempted to run the linear regression alongside the random forest to see if a simpler model would ultimately come out on top.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2025" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2025. <span>“Predicting Bob’s Burgers Episode
Ratings.”</span> February 7. <a href="https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/">https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/</a>.
</div></div></section></div> ]]></description>
  <category>Machine Learning</category>
  <category>Hyperparameter Optimisation</category>
  <category>Python</category>
  <guid>https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/</guid>
  <pubDate>Fri, 07 Feb 2025 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2025-02-07-predicting-bobs-burgers-ratings/burgers.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Resolutions for the Poster’s Reformation</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2025-01-10-resolutions-posters-reformation/</link>
  <description><![CDATA[ 





<p>The microblogging church has fractured. The dominant domain faces challenges from all corners as new groups offer salvation and prosperity to new followers. A familiar, smug order rises from the rubble amid the chaos. Fuelled by technological advances like <del>the printing press</del> Quarto, a Calvinist commitment to the content mines, and the rebellious act of drinking <a href="https://www.npr.org/sections/thesalt/2017/10/31/561117731/the-other-reformation-how-martin-luther-changed-our-beer-too">delicious, hopped-up beers</a><sup>1</sup>, a new age of blogger has rejected the opulence and ritualism of the old way, instead choosing to go back to basics.</p>
<p>If you’re feeling lost, you’re not alone. This joke started to get away from me several sentences ago, and now I’m adrift<sup>2</sup>. What I’m saying is Mark Thompson is correct - <a href="https://get-goalside-newsletter-archive.beehiiv.com/p/bloggings-cool-again">Blogging is Cool Again</a>.</p>
<p>The recent resurgence of the humble blog<sup>3</sup> is possibly a consequence of social media’s fragmentation. Shifting away from shorter-form content packed into threads is a dizzying new freedom. But too much freedom has consequences, as evidenced by all this slop. It’s nothing that can’t be fixed by some planning and a tiny shred of shame, though, and that’s why we’re here. If 2025 is the year of the blogsman, I intend to seize the moment and post my way to the moon. If I want to remain among the cool kids, I will need a plan of attack. Some goals for the new year. Resolutions, even. Hasn’t that worked out well?</p>
<section id="posting-my-way-to-happiness-in-2025" class="level2">
<h2 class="anchored" data-anchor-id="posting-my-way-to-happiness-in-2025">Posting My Way to Happiness in 2025</h2>
<p>I had much fun working on this blog over the last year. I wrote several pretty hefty posts that I’m still pleased to look back at now, and I learned plenty in the process. The dominant thread through the year was football analytics. Half of my blog posts this year were standalone football analytics projects. The intention isn’t that this should be the blog’s focus, but that’s how it shook out in 2024.</p>
<p>I enjoyed working on this blog over the last year and think it was worth my time. No one emailed me to tell me they were mad at me, so I’d call this a success!</p>
<section id="post-fast-post-often" class="level3">
<h3 class="anchored" data-anchor-id="post-fast-post-often">Post Fast, Post Often</h3>
<p>Like a child who left home to escape the tyranny of bedtime, this website is evidence of my living completely untethered from the shackles of a word count, refusing to admit I need adult supervision. Many of my posts last year were approximately the length of great works of Russian literature. Coming from academia, my natural instinct is to go long, but there are plenty of cases where this is unnecessary.</p>
<p>I do my best work in these extensive long-form analyses, but just like any writing, a quick analysis that does something interesting and doesn’t leave the reader with many unanswered questions is a learned skill. Over the next year, I want to practice this skill<sup>4</sup>.</p>
<p>Not all posts need to involve analysis either<sup>5</sup>. I would like to mix things up a bit, from sharing cool stuff I’ve found to writing about experiences in my career. I just want to spend 2025 keeping the haters guessing.</p>
</section>
<section id="be-good-not-perfect" class="level3">
<h3 class="anchored" data-anchor-id="be-good-not-perfect">Be Good, Not Perfect</h3>
<p>This one sounds incredibly self-satisfied, but that’s only because I couldn’t think of another subheading that doesn’t make me sound like a smug idiot. Nothing I’ve ever written is perfect, and some of it might not even be good, but the old adage, “perfect is the enemy of good,” is something I struggle with often in my posting. I frequently spend several days, weeks, or even months trying to get everything right. While that might be defensible in some cases (I think it was a worthwhile effort for the analysis of <a href="http://paulrjohnson.net/blog/analysing-money-in-football/">the effect of money in football</a>), it is usually just a case of completely overthinking things.</p>
<p>If anyone comes to this blog expecting perfection, that’s on them. The goal should be to do a good job and write something interesting and fun, at least for the kind of nerd who reads my posts. Julia Evans’ post dispelling common <a href="https://jvns.ca/blog/2023/06/05/some-blogging-myths/">blogging myths</a> is fantastic, and I would highly recommend anyone read it (I think it applies beyond the blogging context too). I would like to do a better job of following her advice this year<sup>6</sup>. Pursuing perfection is unrealistic and a little silly for what is ultimately just a fun little blog.</p>
</section>
<section id="keep-on-learning-and-sharing" class="level3">
<h3 class="anchored" data-anchor-id="keep-on-learning-and-sharing">Keep On Learning (and Sharing)</h3>
<p>My current role often involves serving as a generalist data scientist, giving me opportunities to learn new methods, tools, or skills. This keeps things interesting, and being comfortable picking up something new with minimal stress is a valuable skill. Still, there are downsides to being a generalist, so I balance this by keeping up some deeper study in areas of interest (which often tie in nicely as easy ideas for blog posts) in my own time.</p>
<p>Over the last year, some areas I focused on were the foundations of statistics and science (filling any gaps or misconceptions my smooth brain has retained), causal inference, and Bayesian statistics. This year, I intend to continue this learning, especially focusing on Bayesian statistics, where I have made gradual progress over several years. I also want to spend some time thinking about the broader data science process and workflow and how this stuff ties into decision-making, with books like Rohan Alexander’s <a href="https://tellingstorieswithdata.com"><em>Telling Stories With Data</em></a> and Allen Downey’s <a href="https://press.uchicago.edu/ucp/books/book/chicago/P/bo206532752.html"><em>Probably Overthinking It</em></a>. Finally, I am also hoping to find some time to read <a href="https://www.statlearning.com"><em>An Introduction to Statistical Learning</em></a><sup>7</sup>. Much of what I know about machine learning has come from learning by doing, and while that has worked well, there’s always something to be gained from reading the classics!</p>
</section>
</section>
<section id="undertaking-with-vigour-the-task-of-posting" class="level2">
<h2 class="anchored" data-anchor-id="undertaking-with-vigour-the-task-of-posting">Undertaking With Vigour The Task of Posting</h2>
<p>In the end, whether you are writing long wordy threads about football tactics on Twitter or Bluesky, or debating the specifics of political language deep in the Discord trenches, or you’re just a simple blogsman seeking salvation from such indulgences, we are all just posting<sup>8</sup>. It’s not my place to judge. I’m just focused on post-maximising.</p>
<p>I started this blog because it seemed like something I should be doing. These posts are all relevant to my professional development. I’m learning stuff that will benefit my career, and as silly as the blog’s tone often is, it’s still a portfolio of sorts. Nonetheless, the main reason I have kept the blog going is because I enjoy it, and the goal in 2025, above all else, is to keep enjoying it. If I can create something others find useful and avoid anyone emailing me telling me to log off, even better.</p>
</section>




<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Preview image by <a href="https://unsplash.com/@tomchill">Tom Hill</a> on <a href="https://unsplash.com/photos/fireworks-above-long-bridge-at-night-time-ZvvirfG75Ns">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>


</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>Listen, if I want to make my soul sad and weigh down my inner organs, that’s my business.↩︎</p></li>
<li id="fn2"><p>I haven’t studied the Reformation, but I assume it was just a bunch of lovely lads who travelled around Europe being <strong>very</strong> normal about Christianity.↩︎</p></li>
<li id="fn3"><p>Are Substacks blogs? From a content perspective, what’s really the difference between a newsletter and a blog? I think they’re the same. Is this a heathen’s take?↩︎</p></li>
<li id="fn4"><p>I suspect that writing quick, interesting analyses is as much about the setup as it is about the writing. Identifying questions interesting enough to bother answering but simple enough to tackle quickly is not easy!↩︎</p></li>
<li id="fn5"><p>I’ve heard posts don’t <strong>have</strong> to be about football, either, though I’ve yet to see any evidence to support this claim.↩︎</p></li>
<li id="fn6"><p>I am guilty of falling for all of the myths Julia mentions, several of them regularly.↩︎</p></li>
<li id="fn7"><p><em>An Introduction to Statistical Learning</em> is one of those books I’ve read a decent chunk of over the years but never start to finish.↩︎</p></li>
<li id="fn8"><p>Unless you are a LinkedIn person, in which case you are a demonic creature.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2025" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2025. <span>“Resolutions for the Poster’s
Reformation.”</span> January 10. <a href="https://paulrjohnson.net/blog/2025-01-10-resolutions-posters-reformation/">https://paulrjohnson.net/blog/2025-01-10-resolutions-posters-reformation/</a>.
</div></div></section></div> ]]></description>
  <category>Me Me Me</category>
  <category>Updates</category>
  <guid>https://paulrjohnson.net/blog/2025-01-10-resolutions-posters-reformation/</guid>
  <pubDate>Fri, 10 Jan 2025 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2025-01-10-resolutions-posters-reformation/fireworks.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Analysing Money’s Effect on Football Using Multilevel Regression</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/</link>
  <description><![CDATA[ 





<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>An earlier version of this post included a couple errors and insufficient detail in the section translating the model’s outputs into real-world findings. While I’ve fixed these issues, I won’t be as bold as to claim there are now zero errors in this post. There are fewer than before, though.</p>
</div>
</div>
<div class="cell">
<details class="code-fold">
<summary>Setup Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import packages</span></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">suppressPackageStartupMessages</span>({</span>
<span id="cb1-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(dplyr)</span>
<span id="cb1-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(lme4)</span>
<span id="cb1-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(gt)</span>
<span id="cb1-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ggplot2)</span>
<span id="cb1-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(marginaleffects)</span>
<span id="cb1-8">})</span>
<span id="cb1-9"></span>
<span id="cb1-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># setup fonts</span></span>
<span id="cb1-11">sysfonts<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">font_add_google</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>)</span>
<span id="cb1-12">sysfonts<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">font_add_google</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>)</span>
<span id="cb1-13">showtext<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">showtext_auto</span>()</span>
<span id="cb1-14"></span>
<span id="cb1-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set plot theme</span></span>
<span id="cb1-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># inspired by https://github.com/z3tt/TidyTuesday/blob/main/R/2020_31_PalmerPenguins.Rmd</span></span>
<span id="cb1-17"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_set</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_update</span>(</span>
<span id="cb1-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.major =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb1-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.minor =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb1-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.spacing.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">65</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">units =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cm"</span>),</span>
<span id="cb1-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.spacing.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">units =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cm"</span>),</span>
<span id="cb1-23">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.title.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-24">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>,</span>
<span id="cb1-25">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb1-26">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-27">    ),</span>
<span id="cb1-28">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.title.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-29">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>,</span>
<span id="cb1-30">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">r =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb1-31">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-32">    ),</span>
<span id="cb1-33">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey50"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb1-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">angle =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">vjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">75</span>),</span>
<span id="cb1-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb1-36">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks.length =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lines"</span>),</span>
<span id="cb1-37">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"top"</span>,</span>
<span id="cb1-38">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.title =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb1-39">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)),</span>
<span id="cb1-40">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.box.margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb1-41">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.key.width =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">units =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cm"</span>),</span>
<span id="cb1-42">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.title =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-43">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb1-44">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>,</span>
<span id="cb1-45">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>,</span>
<span id="cb1-46">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>),</span>
<span id="cb1-47">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-48">    ),</span>
<span id="cb1-49">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.subtitle =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-50">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb1-51">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>,</span>
<span id="cb1-52">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>,</span>
<span id="cb1-53">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lineheight =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>,</span>
<span id="cb1-54">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>),</span>
<span id="cb1-55">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb1-56">    ),</span>
<span id="cb1-57">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.title.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plot"</span>,</span>
<span id="cb1-58">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.caption =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-59">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey50"</span>,</span>
<span id="cb1-60">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>),</span>
<span id="cb1-61">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb1-62">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb1-63">    ),</span>
<span id="cb1-64">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.caption.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plot"</span>,</span>
<span id="cb1-65">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)),</span>
<span id="cb1-66">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">strip.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)),</span>
<span id="cb1-67">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">strip.clip =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"off"</span></span>
<span id="cb1-68">  )</span>
<span id="cb1-69"></span>
<span id="cb1-70"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set table theme</span></span>
<span id="cb1-71">tbl_theme <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-72">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alignment =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>) {</span>
<span id="cb1-73">    data <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-74">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_source_note</span>(</span>
<span id="cb1-75">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source_note =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Source: FBref &amp; Transfermarkt Via {worldfootballR}"</span></span>
<span id="cb1-76">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-77">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_options</span>(</span>
<span id="cb1-78">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">footnotes.marks =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"standard"</span>,</span>
<span id="cb1-79">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">footnotes.spec_ref =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^xb"</span>,</span>
<span id="cb1-80">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">footnotes.spec_ftr =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"(x)"</span>,</span>
<span id="cb1-81">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.width =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pct</span>(width),</span>
<span id="cb1-82">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.align =</span> alignment,</span>
<span id="cb1-83">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.font.names =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span></span>
<span id="cb1-84">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-85">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb1-86">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>),</span>
<span id="cb1-87">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_source_notes</span>(), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_footnotes</span>())</span>
<span id="cb1-88">      )</span>
<span id="cb1-89">  }</span>
<span id="cb1-90"></span>
<span id="cb1-91"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># load data</span></span>
<span id="cb1-92">club_resources <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-93">  readr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_rds</span>(</span>
<span id="cb1-94">    here<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">here</span>(</span>
<span id="cb1-95">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"blog"</span>,</span>
<span id="cb1-96">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2024-10-09-analysing-money-in-football"</span>,</span>
<span id="cb1-97">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span>,</span>
<span id="cb1-98">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"club_resources.rds"</span></span>
<span id="cb1-99">    )</span>
<span id="cb1-100">  )</span></code></pre></div></div>
</details>
</div>
<div class="cell">
<style type="text/css">
.rm-striping .gt_table tr.odd {
  --bs-table-striped-bg: transparent;
}
</style>
</div>
<p>Building a brand is essential in many professional fields. When we finally decide to gig economise all the jobs in an attempt to achieve the goal of implementing a perfectly awful capitalist hellscape, the first to go will be the folks that were too busy “being with their family”, “seeing the world”, or “living a rich and fulfilling life” to build their <strong>brand</strong>. While some people are blessed with names like <a href="https://adamlozer.github.io">Adam L. Ozer</a><sup>1</sup>, those of us who were given names so generic that we are never more than ten metres away from a namesake have to work harder to distinguish ourselves. I could wear a hat, but that is a lot of upkeep. I’d have to buy the hat, then I’d have to wear it, and I assume I’d have to wash it sometimes, too.</p>
<p>No.&nbsp;That won’t do. Building a brand around One Neat Trick is much easier. My One Neat Trick is multilevel models. I recommend them for most problems, usually long before I’m sure they are necessary. I assume that most problems will eventually reveal some multilevel data that justifies using a multilevel model. Once you’ve convinced yourself that this particular hammer <em>does</em> turn everything into a nail, it’s hard to roll that back. I’m fortunate that, in this case, I’m not far from the truth. It’s good that I didn’t pick Tobit regression<sup>2</sup>.</p>
<p>So when I was inspired to take a deeper look at the effect that financial resources have on outcomes in football because a <a href="https://x.com/SBienkowski/status/1561464135279329280">tweet</a> had me mad on the Internet<sup>3</sup>, I assumed it was probably going to be a multilevel model. I’m interested in understanding how much money impacts football and whether it all comes down to spending your way to the top. I have leveraged Transfermarkt’s squad values as a proxy for a club’s financial powers and used outcomes in Europe’s Big Five leagues from 2012/13 to 2023/24 to estimate the effects of resources on league performance. The results suggest that having money is good and that teams with lots of money tend to be better at football (breathtaking insight); there’s some relatively interesting nuance in there, too, so this blog post wasn’t a complete waste of time.</p>
<p>I’m still unsure if this blog post is more about multilevel regression or the money in football, but the beauty of running your own silly little blog is that you can write posts that meander aimlessly. If someone has the misfortune to read this, that’s on them.</p>
<section id="multilevel-models-for-multilevel-problems" class="level2">
<h2 class="anchored" data-anchor-id="multilevel-models-for-multilevel-problems">Multilevel Models for Multilevel Problems</h2>
<p>Multilevel models address problems caused by clustered (or multilevel) data in standard linear (and generalised linear) models, namely, the violation of the assumption of independence.</p>
<p>The independence assumption is a central tenet of regression modelling that states that all residuals in a model should be independent. When data is clustered, observations within clusters will be correlated, leading to residuals that are also correlated (and therefore not independent). Clustered data effectively inflates the sample size<sup>4</sup>, and a model that fails to account for this will underestimate the standard errors of parameter estimates. These smaller standard errors give the appearance of certainty where certainty does not exist.</p>
<p>Multilevel models handle clustered data and the correlation between observations within clusters by explicitly modelling the grouping structures in the data. Modelling the grouping structures allows us to fit models at the population level while accounting for the unexplained variance among the groups <span class="citation" data-cites="gelman2006">(Gelman 2006)</span>, which produces more appropriate standard errors.</p>
<p>So, when you encounter multilevel data, you need a multilevel model!</p>
<section id="the-prevalence-of-multilevel-data" class="level3">
<h3 class="anchored" data-anchor-id="the-prevalence-of-multilevel-data">The Prevalence of Multilevel Data</h3>
<p>My first exposure to multilevel data came when researching political parties and party systems during my Political Science PhD. Being able to say anything meaningful and generalisable about political parties requires studying parties in many countries. It turns out every country is a special snowflake. Finding the golden nuggets of generalisable insight requires combining the valuable information across countries while acknowledging what makes countries and parties unique. Depending on the nature of the question being studied, many other ways exist to group political party data, including time, region, and party family.</p>
<p>Multilevel data can come in various forms, but whenever you find clustering or groups in your data, this is a sign you’re working with multilevel data. If you think that your data could be organised into groups for which observations within-group will be more similar to each other than they are to the rest of the observations, you should be thinking about the problems that arise from clustered data and how you might account for the grouping structures in your data. That doesn’t necessarily have to mean a multilevel model, but multilevel models are certainly one of the best solutions.</p>
<p>Clustering is not just a quirk you occasionally observe in the real world. Multilevel data is ubiquitous. Many phenomena we might be interested in studying can be organised into groups. Multilevel data in the real world is so widespread that <span class="citation" data-cites="mcelreath2017">McElreath (2017)</span> argues that our starting assumption should be that any data has grouping structures that need to be accounted for and that multilevel regression should be our default choice.</p>
</section>
<section id="models-with-memory" class="level3">
<h3 class="anchored" data-anchor-id="models-with-memory">Models with Memory…</h3>
<p>The existence of clustering in your data complicates any attempts to model an outcome of interest at the population level, making it necessary to split the population-level variance (the variance across all observations without accounting for grouping structure) into two components - within-group variance (variance across observations within the same group) and between-group variance (variance across groups). The between-group variance estimates how much groups differ from each other, on average, and tells us how much group-level factors influence the outcome. In contrast, the within-group variance, the remainder of the population-level variance after group differences have been accounted for, estimates how much observations differ in a given group, telling us the population-level differences not explained by the group that observation belongs to.</p>
<p>I think the most intuitive way to understand how multilevel models work, at a conceptual level, is that put forward by Richard McElreath <span class="citation" data-cites="mcelreath2023">(2023)</span> in the multilevel models chapter of his Statistical Rethinking lectures<sup>5</sup> (embedded below). While the focus is on Bayesian methods, the early chapters of the video talk in general enough terms to apply to frequentist multilevel models, too.</p>
<div class="quarto-video ratio ratio-16x9"><iframe data-external="1" src="https://www.youtube.com/embed/iwVqiiXYeC4?si=YmR8plIeBkQ2ufi5" title="" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></div>
<p><span class="citation" data-cites="mcelreath2023">McElreath (2023)</span> describes multilevel models as “models within models”. You do not fit multiple models simultaneously, but it can be helpful to think about a multilevel model as bringing together the information from models of the different levels at which variance exists. The population-level model (again, a “model” from a conceptual but not technical perspective) estimates population-level effects, much like a single-level model. In contrast, group-level sub-models estimate the group-specific deviations from the population-level effects. The population model serves as a jumping-off point for each sub-model, and in this sense, the population model gives what McElreath describes as “a kind of memory” when fitting the sub-models.</p>
<section id="learn-faster" class="level4">
<h4 class="anchored" data-anchor-id="learn-faster">…Learn Faster</h4>
<p>When dealing with clustered data, a single-level model that controls for the grouping structure in the data leaves information on the table by treating each group as entirely independent of each other. To continue to riff off McElreath’s idea of model memory, a single-level model will forget everything it has learned whenever it switches clusters <span class="citation" data-cites="mcelreath2017">(McElreath 2017)</span>. However, clusters of the same type will have common features. For example, in a regression model that estimates how party members behave under certain conditions, party members will be clustered by the political party. While every political party will be different, there will also be inherent similarities that are very useful to factor into a model.</p>
<p>While single-level models leave a lot of information on the table, multilevel models retain information about other clusters by borrowing information from the overall population when estimating group-level effects in a process called “partial pooling” (more on this in the following section). This process causes multilevel models to learn “faster” and more efficiently by leveraging information from across all groups when modelling group-level differences, and it allows multilevel models to reach stable point estimates with less data because groups with smaller sample sizes can rely more heavily on the information borrowed from the population.</p>
<p>All this said, where no obvious clustering is observed in the data, a simpler model can be justified. Where you are not interested in quantifying the clustering effects and just want to account for them to avoid violating the independence assumption, a simpler model with robust standard errors can get you a lot of the way there.</p>
</section>
<section id="resist-overfitting" class="level4">
<h4 class="anchored" data-anchor-id="resist-overfitting">…Resist Overfitting</h4>
<p>Partial pooling makes multilevel models both efficient and flexible, but in addition to this, shrinking group-level estimates towards the overall population mean serves as a form of regularisation<sup>6</sup>, striking a balance between underfitting<sup>7</sup> and overfitting<sup>8</sup>.</p>
<p>This balance is a natural consequence of partial pooling, which is itself a compromise between complete and no pooling. Complete pooling models all observations together, not accounting for group effects, and fits a single global estimate. Complete pooling leads to underfitting because the model is not complex enough to effectively model the variation in the data, with the between-group variance being an essential part of the data-generating process but being ignored. On the other hand, models with no pooling treat groups as independent of each other, fitting separate models for each group. No pooling leads to overfitting, particularly with groups with limited data, because the model doesn’t use information from other groups that might help stabilise estimates. Without that additional context, the model will more likely treat the group-level noise as signal.</p>
<p>The partial pooling process is an “adaptive compromise that achieves regularisation” <span class="citation" data-cites="mcelreath2023">(McElreath 2023)</span>. It balances the risks of underfitting and overfitting by pooling information across the groups, shrinking all group-level estimates towards the overall population mean. The amount of shrinkage depends on how large a group’s sample is and how much variance there is in that group. Groups with less data or high variance will shrink towards the population mean more, meaning extreme group-level estimates are less likely unless the group has a large enough sample and small enough variance to make it justifiable.</p>
<p>While the motivation for moving away from single-level models when dealing with clustered data is the artificially small standard errors they will estimate, the reason to fall in love with multilevel models as the solution to clustered data is partial pooling. Partial pooling, which serves as a type of memory, makes multilevel models more efficient, faster, and less vulnerable to overfitting, and the consequence of all of this is better point estimates. So, clustered data is everywhere, and when dealing with clustered data, a multilevel model will produce more realistic uncertainty estimates and more accurate point estimates. If you’re not convinced by now, you’re a heathen.</p>
</section>
</section>
</section>
<section id="the-role-of-money-in-football" class="level2">
<h2 class="anchored" data-anchor-id="the-role-of-money-in-football">The Role of Money in Football</h2>
<p>I’m sure even readers not interested in football know that money makes the goals go around. What is less clear is exactly how much money can impact outcomes on the pitch. To try to answer this question, I will estimate the relationship between a club’s financial resources and league outcomes, primarily focusing on total league points but also considering goal and expected goal (xG) differences. Club resources will be captured using Transfermarkt player values, summed to total squad value, as a proxy for the financial strength of a team.</p>
<p>Transfermarkt’s values for each player are crowdsourced by the nerds that make up the Transfermarkt community, with the goal being that these values will approximate what a player would cost on the open market (not predicting a player’s transfer fee) <span class="citation" data-cites="transfermarkt2021">(Transfermarkt 2021)</span>. This process relies on the principle of the “wisdom of crowds” <span class="citation" data-cites="surowiecki2005">(Surowiecki 2005)</span>, which assumes that the crowd can work together to build an estimate of market value that is as good or better than a few experts <span class="citation" data-cites="muller2017">(Müller et al. 2017)</span>. Research has shown that Transfermarkt’s player values are a strong predictor of transfer fees <span class="citation" data-cites="herm2014 muller2017 coates2022">(Herm et al. 2014; Müller et al. 2017; Coates and Parshakov 2022)</span> and potentially even a reasonable proxy for player salaries <span class="citation" data-cites="prockl2018">(Prockl and Frick 2018)</span>, while reports suggest that these values are even used in the football industry to inform club decisionmaking <span class="citation" data-cites="smith2021 james2022">(Smith 2021; James 2022)</span>. These values are not without their issues, as they tend to underestimate the value of players, and the amount of bias varies between leagues <span class="citation" data-cites="muller2017 coates2022">(Müller et al. 2017; Coates and Parshakov 2022)</span>, but the bias across the Big Five leagues should be relatively small.</p>
<p>The goal is to understand how a club’s financial resources can impact their results on the pitch. The most important mechanism is investing in the squad (though there will be other factors - coaching and support staff, facilities, etc.). Build a better team, get better results! A reliable measure of squad value (and how it changes over time) should give some indication of how the club has invested. Treating squad values as a measure of resources assumes that every team spends, more or less, as much as their finances allow. We know that’s not entirely true, but I think it is an acceptable simplifying assumption. The interest in club resources is assuming they spend that money. It’s just a little catchier to talk about money rather than the spending of that money.</p>
<section id="exploring-footballs-multilevel-data" class="level3">
<h3 class="anchored" data-anchor-id="exploring-footballs-multilevel-data">Exploring Football’s Multilevel Data</h3>
<p>Football has some immediately apparent grouping structures. The promotion/relegation system explicitly organises teams hierarchically! I’m only looking at outcomes in the top divisions, but I am also looking at leagues in five different countries, which will also be a source of some clustering in the data. Since I am looking at outcomes over 12 seasons, the teams themselves will also be a considerable source of clustering because, inevitably, certain teams will do more with their money than others and regularly outperform others in the league.</p>
<section id="league-differences" class="level4">
<h4 class="anchored" data-anchor-id="league-differences">League Differences</h4>
<p>Not accounting for league differences will undervalue the resource advantage that teams like Bayern Munich, PSG, and Juventus have in their leagues while ignoring the significant riches of the Premier League.</p>
<p>These league differences become more apparent when we plot the median squad market values in the Big Five leagues over time.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">club_resources <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(league, season) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">squad_value =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">median</span>(squad_value)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(</span>
<span id="cb2-5">    forcats<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_factor</span>(season),</span>
<span id="cb2-6">    squad_value,</span>
<span id="cb2-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">group =</span> league,</span>
<span id="cb2-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> league</span>
<span id="cb2-9">  )) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb2-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_col</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dodge"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb2-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_hline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">yintercept =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb2-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_fill_manual</span>(</span>
<span id="cb2-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#7AB5CC"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#FFA600"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#D93649"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#8C3431"</span>)</span>
<span id="cb2-14">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb2-15">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_y_continuous</span>(</span>
<span id="cb2-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_number</span>(</span>
<span id="cb2-17">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale_cut =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cut_short_scale</span>(),</span>
<span id="cb2-18">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prefix =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"€"</span></span>
<span id="cb2-19">    )</span>
<span id="cb2-20">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb2-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb2-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value in the Big Five Leagues Over Time"</span>,</span>
<span id="cb2-23">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb2-24">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb2-25">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Median average Transfermarkt squad market values per season in each of the "</span>,</span>
<span id="cb2-26">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Big Five leagues in Europe from 2012/13 - 2023/24."</span></span>
<span id="cb2-27">      ),</span>
<span id="cb2-28">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">93</span></span>
<span id="cb2-29">    ),</span>
<span id="cb2-30">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb2-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value"</span>,</span>
<span id="cb2-32">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: Transfermarkt Via {worldfootballR}"</span></span>
<span id="cb2-33">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb2-34">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.key.width =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">units =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cm"</span>))</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/index_files/figure-html/value-by-league-1.png" class="img-fluid figure-img" alt="A barplot visualising the median average Transfermarkt squad values per season in the Big Five leagues from 2012/13 to 2023/24. All five leagues are relatively equal, at a median squad value of around €100m, in the 2012/13 season. While the median squad value increases significantly in every league during this period, the Premier League's growth dwarfs the other four leagues. By the 2023/24 season, the Premier League median squad value is around €500m, while the other four leagues are all around €200m. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>Plenty of Premier League teams have astronomical amounts of money when compared even against the rest of the Big Five leagues despite not coming close to mixing with the very richest teams in England. It’s important to account for league differences so that those teams are being compared against their league competition, where their gigantic pot of gold is only a moderately sized pot of gold.</p>
</section>
<section id="squad-values" class="level4">
<h4 class="anchored" data-anchor-id="squad-values">Squad Values</h4>
<p>Just being rich isn’t enough. What do rich clubs do with all that money? We expect rich teams to build more valuable squads and that teams valued higher by Transfermarkt will be more successful in the league. The plot below visualises how our three outcomes (points, goal difference, and xG difference) vary by squad market value, all split by league.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">club_resources <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-2">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(</span>
<span id="cb3-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(pts, xgd, gd),</span>
<span id="cb3-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outcome"</span>,</span>
<span id="cb3-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span></span>
<span id="cb3-6">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb3-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">outcome =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(</span>
<span id="cb3-9">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">case_when</span>(</span>
<span id="cb3-10">        outcome <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pts"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"League Points"</span>,</span>
<span id="cb3-11">        outcome <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xgd"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xG Difference"</span>,</span>
<span id="cb3-12">        outcome <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gd"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Difference"</span>,</span>
<span id="cb3-13">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.default =</span> outcome</span>
<span id="cb3-14">      ),</span>
<span id="cb3-15">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">levels =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"League Points"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Difference"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xG Difference"</span>)</span>
<span id="cb3-16">    )</span>
<span id="cb3-17">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(squad_value, value)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb3-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb3-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">formula =</span> y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(x),</span>
<span id="cb3-23">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>,</span>
<span id="cb3-24">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">se =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb3-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span></span>
<span id="cb3-26">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-27">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">facet_grid</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(outcome), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(league), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scales =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"free_y"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-28">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_continuous</span>(</span>
<span id="cb3-29">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_number</span>(</span>
<span id="cb3-30">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale_cut =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cut_short_scale</span>(),</span>
<span id="cb3-31">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prefix =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"€"</span></span>
<span id="cb3-32">    )</span>
<span id="cb3-33">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-34">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb3-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"League Outcomes by Squad Value in the Big Five Leagues"</span>,</span>
<span id="cb3-36">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb3-37">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb3-38">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Comparing the association between squad values and league outcomes - "</span>,</span>
<span id="cb3-39">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"points, goal difference, and xG difference - in the Big Five leagues "</span>,</span>
<span id="cb3-40">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"in Europe across the 2012/13 - 2023/24 seasons."</span></span>
<span id="cb3-41">      ),</span>
<span id="cb3-42">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">93</span></span>
<span id="cb3-43">    ),</span>
<span id="cb3-44">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value"</span>,</span>
<span id="cb3-45">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb3-46">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: FBref &amp; Transfermarkt Via {worldfootballR}"</span></span>
<span id="cb3-47">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-48">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span>(</span>
<span id="cb3-49">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.spacing.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">units =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cm"</span>),</span>
<span id="cb3-50">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">angle =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">vjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">75</span>)</span>
<span id="cb3-51">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/index_files/figure-html/value-by-outcome-1.png" class="img-fluid figure-img" alt="A regression plot visualising the association between squad market values and league outcomes. The data is subset by outcome (points, goal difference, and xG difference) and league, producing 15 plots fit. Each plot shows a positive association between squad values and outcomes. However, the association appears to be non-linear. The regression line fit to each subset of the data includes a log-transformed squad value as the predictor, which fits the data relatively well, though to varying degrees. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>The value of a team’s squad positively affects all three outcomes, though that relationship is non-linear. The regression line fit to the data is done using a log-transformed squad market value, and it does a reasonably good job of capturing the apparent diminishing returns as squad market values get way out in front of the rest of the league.</p>
<p>It is also worth noting that while the relationship between squad value and the outcomes is similar across all five leagues, there is some variance. This variance is most apparent at the top end of the value ranges. The highest squad values are much larger in some leagues than others, as are the highest total values of each outcome (especially the league points, since these are constrained by a maximum number of points that any team could win, which varies by league).</p>
</section>
<section id="season-differences" class="level4">
<h4 class="anchored" data-anchor-id="season-differences">Season Differences</h4>
<p>Finally, we can consider how these effects have changed over time, plotting the relationship between squad values and league points, split by time, below. The darker blue points are earlier seasons in the data, and the lighter grey points are the most recent seasons<sup>9</sup>.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">club_resources <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(squad_value, pts, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> season)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb4-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb4-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb4-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb4-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">formula =</span> y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(x),</span>
<span id="cb4-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">se =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb4-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb4-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span></span>
<span id="cb4-10">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb4-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_colour_manual</span>(</span>
<span id="cb4-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb4-13">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>,</span>
<span id="cb4-14">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#24779F"</span>,</span>
<span id="cb4-15">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#3881A6"</span>,</span>
<span id="cb4-16">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#498AAC"</span>,</span>
<span id="cb4-17">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#5993B2"</span>,</span>
<span id="cb4-18">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#699CB7"</span>,</span>
<span id="cb4-19">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#79A6BD"</span>,</span>
<span id="cb4-20">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#8AAFC2"</span>,</span>
<span id="cb4-21">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#9BB8C7"</span>,</span>
<span id="cb4-22">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#ACC1CB"</span>,</span>
<span id="cb4-23">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#BFCACF"</span>,</span>
<span id="cb4-24">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#D2D2D2"</span></span>
<span id="cb4-25">    ),</span>
<span id="cb4-26">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">guide =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb4-27">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb4-28">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_continuous</span>(</span>
<span id="cb4-29">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_number</span>(</span>
<span id="cb4-30">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale_cut =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cut_short_scale</span>(),</span>
<span id="cb4-31">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prefix =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"€"</span></span>
<span id="cb4-32">    )</span>
<span id="cb4-33">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb4-34">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb4-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"League Points by Squad Value Over Time"</span>,</span>
<span id="cb4-36">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb4-37">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Comparing the association between squad market values and total league "</span>,</span>
<span id="cb4-38">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"points across&lt;br&gt;the Big Five leagues in Europe, in each season from "</span>,</span>
<span id="cb4-39">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"&lt;b style='color:#00537C;'&gt;2012/13&lt;/b&gt; - &lt;b style='color:#D2D2D2;'&gt;2023/24&lt;/b&gt;."</span></span>
<span id="cb4-40">    ),</span>
<span id="cb4-41">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value"</span>,</span>
<span id="cb4-42">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"League Points"</span>,</span>
<span id="cb4-43">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: FBref &amp; Transfermarkt Via {worldfootballR}"</span></span>
<span id="cb4-44">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb4-45">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span>(</span>
<span id="cb4-46">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.subtitle =</span> ggtext<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_markdown</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lineheight =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>)</span>
<span id="cb4-47">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/index_files/figure-html/value-by-season-1.png" class="img-fluid figure-img" alt="A regression plot visualising the association between squad market values and league points across the Big Five leagues in each season from 2012/13 to 2023/24. The data is split by season, with a separate regression line fit to each season's data, including a log-transformed squad value as the predictor. While the association between squad value and points is positive throughout the period, the slopes appear to flatten with time, suggesting that increases in squad value are worth fewer league points in recent seasons than earlier in the data. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>There is a clear shift over time. Teams have to spend more to increase their points totals now, and the ceiling of squad values has also increased with time.</p>
</section>
</section>
<section id="estimating-squad-value-effects" class="level3">
<h3 class="anchored" data-anchor-id="estimating-squad-value-effects">Estimating Squad Value Effects</h3>
<div class="cell">
<details class="code-fold">
<summary>Helper Function Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1">fit_mlms <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb5-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data) {</span>
<span id="cb5-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lmer</span>(</span>
<span id="cb5-4">      value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span></span>
<span id="cb5-5">        <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-6">          demean_squad <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-7">          double_mean_club <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-8">          time <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-9">          (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> demean_squad <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> league <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> squad) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-10">          (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> season),</span>
<span id="cb5-11">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> data,</span>
<span id="cb5-12">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">REML =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,</span>
<span id="cb5-13">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">control =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lmerControl</span>(</span>
<span id="cb5-14">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">optimizer =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bobyqa"</span>,</span>
<span id="cb5-15">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">optCtrl =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">maxfun =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200000</span>)</span>
<span id="cb5-16">      )</span>
<span id="cb5-17">    )</span>
<span id="cb5-18">  }</span></code></pre></div></div>
</details>
</div>
<div class="cell">
<details class="code-fold">
<summary>Model Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">models <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb6-2">  club_resources <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb6-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">squad_value =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(squad_value),</span>
<span id="cb6-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mean_club =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(squad_value),</span>
<span id="cb6-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">demean_squad =</span> squad_value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> mean_club,</span>
<span id="cb6-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> squad</span>
<span id="cb6-8">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-9">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(</span>
<span id="cb6-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(pts, xgd, gd),</span>
<span id="cb6-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"outcome"</span>,</span>
<span id="cb6-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span></span>
<span id="cb6-13">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb6-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">double_mean_club =</span> mean_club <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(squad_value),</span>
<span id="cb6-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">value =</span> value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> mp,</span>
<span id="cb6-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">time =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(season) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb6-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">outcome =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">case_when</span>(</span>
<span id="cb6-19">      outcome <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pts"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>,</span>
<span id="cb6-20">      outcome <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gd"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Difference"</span>,</span>
<span id="cb6-21">      outcome <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xgd"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xG Difference"</span>,</span>
<span id="cb6-22">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.default =</span> outcome</span>
<span id="cb6-23">    )</span>
<span id="cb6-24">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-25">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(value)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-26">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nest</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(outcome)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-27">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb6-28">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">model =</span> purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(data, fit_mlms),</span>
<span id="cb6-29">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">summary =</span> purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(model, broom.mixed<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>glance),</span>
<span id="cb6-30">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coefs =</span> purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(model, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> broom.mixed<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tidy</span>(.x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">conf.int =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)),</span>
<span id="cb6-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">preds =</span> purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(model, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(.x))</span>
<span id="cb6-32">  )</span></code></pre></div></div>
</details>
</div>
<p>The previous section highlights multiple grouping structures that need to be accounted for in the data, which is fortunate because I’ve already spent a lot of time talking about multilevel models here, and that would have been a real waste of time. This exploratory work also identified that squad values appear to have a non-linear relationship with the three outcomes. The other detail that we can see from the variation within and between groups across the range of squad values is that not only does the mean value vary by league, but also the magnitude of squad value’s effect on the three outcomes varies. Multilevel models can handle both of these types of variation quite easily. When the mean difference is allowed to vary between groups, this is a varying intercepts model, and allowing the magnitude of the effect to vary by group is called a varying slopes model. When your model allows both, it is a varying intercepts &amp; slopes model, and this is the kind of model we will use here. We saw minor but clear differences at the league level, and we know that the most significant differences will occur at the club level (this just would have been a mess to visualise).</p>
<p>The regression models in Table&nbsp;1 are fit to the three outcomes - league points, goal difference, and xG difference - all have the same basic structure. All three outcomes have been transformed to a “Per Game” value in order to account for the shortened season in Ligue 1 during the COVID-19 pandemic. The model includes three population-level explanatory variables: squad value, club mean value, and time. Squad market value has been decomposed into two variables - group-mean centred squad value<sup>10</sup>, using clubs as the groups, and the club mean squad value, to effectively capture the within and between effects, respectively <span class="citation" data-cites="bafumi2007 bell2019 enders2007">(Bafumi and Gelman 2007; Bell et al. 2019; Enders and Tofighi 2007)</span>. Both squad value variables have been log-transformed to account for the decreasing gains in league outcomes as squad values increase. An additional variable for time, a continuous variable indexed at 0 (2012/13) and with a maximum of 11 (2023/24), is included. The time variable has been included to account for changes in the distribution of outcomes over time (for example, increasing disparities in outcomes between the best and worst teams). The grouping structures include teams nested within their league and a separate crossed-grouping variable for each season<sup>11</sup>.</p>
<p>While the model intercepts are allowed to vary according to each grouping structure, the squad value slopes are specified to vary by the nested league/team grouping. The varying slopes component means that the magnitude of squad values’ effect on outcomes is allowed to vary by league and team. We could have allowed the squad value effects to vary by season as well, given that there did appear to be some flattening of the curve of squad values association with league points over time, however, the differences were minor and allowing the intercepts to vary should be sufficient, without inviting unnecessary complexity. In contrast to the population-level time variable (which is intended to capture trends), the season grouping structure mostly captures the fact that outcomes are not independent of each other in a given season. There are a finite number of points in a season, so if Man City win them all, there’s none left for anyone else. Similarly, if Man City score 1000 goals, everyone else’s goal difference will be much worse.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1">cm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb7-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb7-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"(Intercept)"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"(Intercept)"</span>,</span>
<span id="cb7-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"demean_squad"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value"</span>,</span>
<span id="cb7-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"double_mean_club"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Club Mean Value"</span>,</span>
<span id="cb7-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"time"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Time (Seasons)"</span>,</span>
<span id="cb7-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SD (Intercept squadleague)"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Club_: Intercept Std. Dev."</span>,</span>
<span id="cb7-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SD (demean_squad squadleague)"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Club_: Slope Std. Dev."</span>,</span>
<span id="cb7-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SD (Intercept league)"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_League_: Intercept Std. Dev."</span>,</span>
<span id="cb7-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SD (demean_squad league)"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_League_: Slope Std. Dev."</span>,</span>
<span id="cb7-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SD (Intercept season)"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Season_: Intercept Std. Dev."</span>,</span>
<span id="cb7-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SD (Observations)"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Residual Std. Dev."</span></span>
<span id="cb7-13">  )</span>
<span id="cb7-14"></span>
<span id="cb7-15">gm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb7-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb7-17">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"raw"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"nobs"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"clean"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Num. Obs"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fmt"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb7-18">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"raw"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"r2.marginal"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"clean"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R&lt;sup&gt;2&lt;/sup&gt; Marginal"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fmt"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>),</span>
<span id="cb7-19">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb7-20">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"raw"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"r2.conditional"</span>,</span>
<span id="cb7-21">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"clean"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R&lt;sup&gt;2&lt;/sup&gt; Conditional"</span>,</span>
<span id="cb7-22">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fmt"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb7-23">    ),</span>
<span id="cb7-24">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"raw"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"icc"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"clean"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ICC"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fmt"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>),</span>
<span id="cb7-25">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"raw"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rmse"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"clean"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RMSE"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fmt"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb7-26">  )</span>
<span id="cb7-27"></span>
<span id="cb7-28">models <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-29">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pull</span>(model, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name =</span> outcome) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-30">  modelsummary<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">msummary</span>(</span>
<span id="cb7-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">statistic =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"conf.int"</span>,</span>
<span id="cb7-32">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">gof_map =</span> gm,</span>
<span id="cb7-33">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coef_map =</span> cm,</span>
<span id="cb7-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fmt =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb7-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">output =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gt"</span></span>
<span id="cb7-36">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-37">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_row_group</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">md</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"**Group-Level Effects**"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-38">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_row_group</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">md</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"**Population-Level Effects**"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-39">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_footnote</span>(</span>
<span id="cb7-40">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">footnote =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Integers 0-11 (2012/13 = 0; 2022/23 = 11)"</span>,</span>
<span id="cb7-41">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_body</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>)</span>
<span id="cb7-42">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-43">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_footnote</span>(</span>
<span id="cb7-44">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">footnote =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Log-transformed"</span>,</span>
<span id="cb7-45">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_body</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb7-46">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-47">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_footnote</span>(</span>
<span id="cb7-48">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">footnote =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Group mean centred"</span>,</span>
<span id="cb7-49">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_body</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb7-50">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-51">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_footnote</span>(</span>
<span id="cb7-52">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">footnote =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Grand mean centred"</span>,</span>
<span id="cb7-53">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_body</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb7-54">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-55">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_spanner</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Outcomes (Per Game)"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-56">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fmt_markdown</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">17</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-57">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb7-58">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"small"</span>),</span>
<span id="cb7-59">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_body</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>))</span>
<span id="cb7-60">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-61">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>()</span></code></pre></div></div>
</details>
<div id="tbl-model-summary" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-model-summary-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Multilevel Regressions of Squad Values’ Effect on Season Outcomes
</figcaption>
<div aria-describedby="tbl-model-summary-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="zsrzdlkrsd" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#zsrzdlkrsd table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#zsrzdlkrsd thead, #zsrzdlkrsd tbody, #zsrzdlkrsd tfoot, #zsrzdlkrsd tr, #zsrzdlkrsd td, #zsrzdlkrsd th {
  border-style: none;
}

#zsrzdlkrsd p {
  margin: 0;
  padding: 0;
}

#zsrzdlkrsd .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#zsrzdlkrsd .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#zsrzdlkrsd .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#zsrzdlkrsd .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#zsrzdlkrsd .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#zsrzdlkrsd .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#zsrzdlkrsd .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#zsrzdlkrsd .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#zsrzdlkrsd .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#zsrzdlkrsd .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#zsrzdlkrsd .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#zsrzdlkrsd .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#zsrzdlkrsd .gt_spanner_row {
  border-bottom-style: hidden;
}

#zsrzdlkrsd .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#zsrzdlkrsd .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#zsrzdlkrsd .gt_from_md > :first-child {
  margin-top: 0;
}

#zsrzdlkrsd .gt_from_md > :last-child {
  margin-bottom: 0;
}

#zsrzdlkrsd .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#zsrzdlkrsd .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#zsrzdlkrsd .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#zsrzdlkrsd .gt_row_group_first td {
  border-top-width: 2px;
}

#zsrzdlkrsd .gt_row_group_first th {
  border-top-width: 2px;
}

#zsrzdlkrsd .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#zsrzdlkrsd .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#zsrzdlkrsd .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#zsrzdlkrsd .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#zsrzdlkrsd .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#zsrzdlkrsd .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#zsrzdlkrsd .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#zsrzdlkrsd .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#zsrzdlkrsd .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#zsrzdlkrsd .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#zsrzdlkrsd .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#zsrzdlkrsd .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#zsrzdlkrsd .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#zsrzdlkrsd .gt_left {
  text-align: left;
}

#zsrzdlkrsd .gt_center {
  text-align: center;
}

#zsrzdlkrsd .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#zsrzdlkrsd .gt_font_normal {
  font-weight: normal;
}

#zsrzdlkrsd .gt_font_bold {
  font-weight: bold;
}

#zsrzdlkrsd .gt_font_italic {
  font-style: italic;
}

#zsrzdlkrsd .gt_super {
  font-size: 65%;
}

#zsrzdlkrsd .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#zsrzdlkrsd .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#zsrzdlkrsd .gt_indent_1 {
  text-indent: 5px;
}

#zsrzdlkrsd .gt_indent_2 {
  text-indent: 10px;
}

#zsrzdlkrsd .gt_indent_3 {
  text-indent: 15px;
}

#zsrzdlkrsd .gt_indent_4 {
  text-indent: 20px;
}

#zsrzdlkrsd .gt_indent_5 {
  text-indent: 25px;
}

#zsrzdlkrsd .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#zsrzdlkrsd div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>
<table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
  <thead>
    <tr class="gt_col_headings gt_spanner_row">
      <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="2" colspan="1" scope="col" id="a-"> </th>
      <th class="gt_center gt_columns_top_border gt_column_spanner_outer" rowspan="1" colspan="3" scope="colgroup" id="Outcomes (Per Game)">
        <div class="gt_column_spanner">Outcomes (Per Game)</div>
      </th>
    </tr>
    <tr class="gt_col_headings">
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="Points">Points</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="Goal-Difference">Goal Difference</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="xG-Difference">xG Difference</th>
    </tr>
  </thead>
  <tbody class="gt_table_body">
    <tr class="gt_group_heading_row">
      <th colspan="4" class="gt_group_heading" scope="colgroup" id="<span data-qmd-base64=&quot;KipQb3B1bGF0aW9uLUxldmVsIEVmZmVjdHMqKg==&quot;><span class='gt_from_md'><strong>Population-Level Effects</strong></span></span>"><span data-qmd-base64="KipQb3B1bGF0aW9uLUxldmVsIEVmZmVjdHMqKg=="><span class="gt_from_md"><strong>Population-Level Effects</strong></span></span></th>
    </tr>
    <tr class="gt_row_group_first"><td headers="**Population-Level Effects**   " class="gt_row gt_left">(Intercept)</td>
<td headers="**Population-Level Effects**  Points" class="gt_row gt_center">1.60</td>
<td headers="**Population-Level Effects**  Goal Difference" class="gt_row gt_center">0.37</td>
<td headers="**Population-Level Effects**  xG Difference" class="gt_row gt_center">0.06</td></tr>
    <tr><td headers="**Population-Level Effects**   " class="gt_row gt_left"></td>
<td headers="**Population-Level Effects**  Points" class="gt_row gt_center" style="font-size: small;">[1.42, 1.79]</td>
<td headers="**Population-Level Effects**  Goal Difference" class="gt_row gt_center" style="font-size: small;">[0.08, 0.67]</td>
<td headers="**Population-Level Effects**  xG Difference" class="gt_row gt_center" style="font-size: small;">[-0.19, 0.31]</td></tr>
    <tr><td headers="**Population-Level Effects**   " class="gt_row gt_left">Squad Value<span class="gt_footnote_marks" style="white-space:nowrap;font-style:normal;font-weight:bold;line-height:0;"><sup>*,†</sup></span></td>
<td headers="**Population-Level Effects**  Points" class="gt_row gt_center">0.39</td>
<td headers="**Population-Level Effects**  Goal Difference" class="gt_row gt_center">0.64</td>
<td headers="**Population-Level Effects**  xG Difference" class="gt_row gt_center">0.42</td></tr>
    <tr><td headers="**Population-Level Effects**   " class="gt_row gt_left"></td>
<td headers="**Population-Level Effects**  Points" class="gt_row gt_center" style="font-size: small;">[0.32, 0.47]</td>
<td headers="**Population-Level Effects**  Goal Difference" class="gt_row gt_center" style="font-size: small;">[0.52, 0.77]</td>
<td headers="**Population-Level Effects**  xG Difference" class="gt_row gt_center" style="font-size: small;">[0.25, 0.59]</td></tr>
    <tr><td headers="**Population-Level Effects**   " class="gt_row gt_left">Club Mean Value<span class="gt_footnote_marks" style="white-space:nowrap;font-style:normal;font-weight:bold;line-height:0;"><sup>*,‡</sup></span></td>
<td headers="**Population-Level Effects**  Points" class="gt_row gt_center">0.52</td>
<td headers="**Population-Level Effects**  Goal Difference" class="gt_row gt_center">0.81</td>
<td headers="**Population-Level Effects**  xG Difference" class="gt_row gt_center">0.58</td></tr>
    <tr><td headers="**Population-Level Effects**   " class="gt_row gt_left"></td>
<td headers="**Population-Level Effects**  Points" class="gt_row gt_center" style="font-size: small;">[0.49, 0.55]</td>
<td headers="**Population-Level Effects**  Goal Difference" class="gt_row gt_center" style="font-size: small;">[0.77, 0.85]</td>
<td headers="**Population-Level Effects**  xG Difference" class="gt_row gt_center" style="font-size: small;">[0.54, 0.63]</td></tr>
    <tr><td headers="**Population-Level Effects**   " class="gt_row gt_left">Time (Seasons)<span class="gt_footnote_marks" style="white-space:nowrap;font-style:normal;font-weight:bold;line-height:0;"><sup>§</sup></span></td>
<td headers="**Population-Level Effects**  Points" class="gt_row gt_center">-0.04</td>
<td headers="**Population-Level Effects**  Goal Difference" class="gt_row gt_center">-0.07</td>
<td headers="**Population-Level Effects**  xG Difference" class="gt_row gt_center">-0.02</td></tr>
    <tr><td headers="**Population-Level Effects**   " class="gt_row gt_left"></td>
<td headers="**Population-Level Effects**  Points" class="gt_row gt_center" style="font-size: small;">[-0.05, -0.03]</td>
<td headers="**Population-Level Effects**  Goal Difference" class="gt_row gt_center" style="font-size: small;">[-0.08, -0.05]</td>
<td headers="**Population-Level Effects**  xG Difference" class="gt_row gt_center" style="font-size: small;">[-0.04, -0.01]</td></tr>
    <tr class="gt_group_heading_row">
      <th colspan="4" class="gt_group_heading" scope="colgroup" id="<span data-qmd-base64=&quot;KipHcm91cC1MZXZlbCBFZmZlY3RzKio=&quot;><span class='gt_from_md'><strong>Group-Level Effects</strong></span></span>"><span data-qmd-base64="KipHcm91cC1MZXZlbCBFZmZlY3RzKio="><span class="gt_from_md"><strong>Group-Level Effects</strong></span></span></th>
    </tr>
    <tr class="gt_row_group_first"><td headers="**Group-Level Effects**   " class="gt_row gt_left"><span data-qmd-base64="X0NsdWJfOiBJbnRlcmNlcHQgU3RkLiBEZXYu"><span class="gt_from_md"><em>Club</em>: Intercept Std. Dev.</span></span></td>
<td headers="**Group-Level Effects**  Points" class="gt_row gt_center">0.09</td>
<td headers="**Group-Level Effects**  Goal Difference" class="gt_row gt_center">0.15</td>
<td headers="**Group-Level Effects**  xG Difference" class="gt_row gt_center">0.16</td></tr>
    <tr><td headers="**Group-Level Effects**   " class="gt_row gt_left"><span data-qmd-base64="X0NsdWJfOiBTbG9wZSBTdGQuIERldi4="><span class="gt_from_md"><em>Club</em>: Slope Std. Dev.</span></span></td>
<td headers="**Group-Level Effects**  Points" class="gt_row gt_center">0.15</td>
<td headers="**Group-Level Effects**  Goal Difference" class="gt_row gt_center">0.25</td>
<td headers="**Group-Level Effects**  xG Difference" class="gt_row gt_center">0.34</td></tr>
    <tr><td headers="**Group-Level Effects**   " class="gt_row gt_left"><span data-qmd-base64="X0xlYWd1ZV86IEludGVyY2VwdCBTdGQuIERldi4="><span class="gt_from_md"><em>League</em>: Intercept Std. Dev.</span></span></td>
<td headers="**Group-Level Effects**  Points" class="gt_row gt_center">0.20</td>
<td headers="**Group-Level Effects**  Goal Difference" class="gt_row gt_center">0.32</td>
<td headers="**Group-Level Effects**  xG Difference" class="gt_row gt_center">0.25</td></tr>
    <tr><td headers="**Group-Level Effects**   " class="gt_row gt_left"><span data-qmd-base64="X0xlYWd1ZV86IFNsb3BlIFN0ZC4gRGV2Lg=="><span class="gt_from_md"><em>League</em>: Slope Std. Dev.</span></span></td>
<td headers="**Group-Level Effects**  Points" class="gt_row gt_center">0.05</td>
<td headers="**Group-Level Effects**  Goal Difference" class="gt_row gt_center">0.10</td>
<td headers="**Group-Level Effects**  xG Difference" class="gt_row gt_center">0.15</td></tr>
    <tr><td headers="**Group-Level Effects**   " class="gt_row gt_left"><span data-qmd-base64="X1NlYXNvbl86IEludGVyY2VwdCBTdGQuIERldi4="><span class="gt_from_md"><em>Season</em>: Intercept Std. Dev.</span></span></td>
<td headers="**Group-Level Effects**  Points" class="gt_row gt_center">0.04</td>
<td headers="**Group-Level Effects**  Goal Difference" class="gt_row gt_center">0.07</td>
<td headers="**Group-Level Effects**  xG Difference" class="gt_row gt_center">0.03</td></tr>
    <tr><td headers="**Group-Level Effects**   " class="gt_row gt_left" style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000;"><span data-qmd-base64="UmVzaWR1YWwgU3RkLiBEZXYu"><span class="gt_from_md">Residual Std. Dev.</span></span></td>
<td headers="**Group-Level Effects**  Points" class="gt_row gt_center" style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000;">0.22</td>
<td headers="**Group-Level Effects**  Goal Difference" class="gt_row gt_center" style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000;">0.33</td>
<td headers="**Group-Level Effects**  xG Difference" class="gt_row gt_center" style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000;">0.24</td></tr>
    <tr class="gt_group_heading_row">
      <th colspan="4" class="gt_empty_group_heading" scope="colgroup"></th>
    </tr>
    <tr class="gt_row_group_first"><td headers="NA   " class="gt_row gt_left"><span data-qmd-base64="TnVtLiBPYnM="><span class="gt_from_md">Num. Obs</span></span></td>
<td headers="NA  Points" class="gt_row gt_center">1174</td>
<td headers="NA  Goal Difference" class="gt_row gt_center">1174</td>
<td headers="NA  xG Difference" class="gt_row gt_center">684</td></tr>
    <tr><td headers="NA   " class="gt_row gt_left"><span data-qmd-base64="UjxzdXA+Mjwvc3VwPiBNYXJnaW5hbA=="><span class="gt_from_md">R<sup>2</sup> Marginal</span></span></td>
<td headers="NA  Points" class="gt_row gt_center">0.63</td>
<td headers="NA  Goal Difference" class="gt_row gt_center">0.63</td>
<td headers="NA  xG Difference" class="gt_row gt_center">0.60</td></tr>
    <tr><td headers="NA   " class="gt_row gt_left"><span data-qmd-base64="UjxzdXA+Mjwvc3VwPiBDb25kaXRpb25hbA=="><span class="gt_from_md">R<sup>2</sup> Conditional</span></span></td>
<td headers="NA  Points" class="gt_row gt_center">0.82</td>
<td headers="NA  Goal Difference" class="gt_row gt_center">0.84</td>
<td headers="NA  xG Difference" class="gt_row gt_center">0.85</td></tr>
    <tr><td headers="NA   " class="gt_row gt_left">ICC</td>
<td headers="NA  Points" class="gt_row gt_center">0.52</td>
<td headers="NA  Goal Difference" class="gt_row gt_center">0.57</td>
<td headers="NA  xG Difference" class="gt_row gt_center">0.62</td></tr>
    <tr><td headers="NA   " class="gt_row gt_left">RMSE</td>
<td headers="NA  Points" class="gt_row gt_center">0.21</td>
<td headers="NA  Goal Difference" class="gt_row gt_center">0.30</td>
<td headers="NA  xG Difference" class="gt_row gt_center">0.21</td></tr>
  </tbody>
  <tfoot class="gt_sourcenotes">
    <tr>
      <td class="gt_sourcenote" style="text-align: left;" colspan="4">Source: FBref &amp; Transfermarkt Via {worldfootballR}</td>
    </tr>
  </tfoot>
  <tfoot class="gt_footnotes">
    <tr>
      <td class="gt_footnote" style="text-align: left;" colspan="4"><span style="white-space:nowrap;font-style:normal;font-weight:normal;line-height:0;">(*)</span> Log-transformed</td>
    </tr>
    <tr>
      <td class="gt_footnote" style="text-align: left;" colspan="4"><span style="white-space:nowrap;font-style:normal;font-weight:normal;line-height:0;">(†)</span> Group mean centred</td>
    </tr>
    <tr>
      <td class="gt_footnote" style="text-align: left;" colspan="4"><span style="white-space:nowrap;font-style:normal;font-weight:normal;line-height:0;">(‡)</span> Grand mean centred</td>
    </tr>
    <tr>
      <td class="gt_footnote" style="text-align: left;" colspan="4"><span style="white-space:nowrap;font-style:normal;font-weight:normal;line-height:0;">(§)</span> Integers 0-11 (2012/13 = 0; 2022/23 = 11)</td>
    </tr>
  </tfoot>
</table>
</div>
</div>
</div>
</figure>
</div>
</div>
<section id="population-level-effects" class="level4">
<h4 class="anchored" data-anchor-id="population-level-effects">Population-Level Effects</h4>
<p>The intercept values for each model in Table&nbsp;1 represent the predicted value for each outcome in the 2012/13 season<sup>12</sup> for a club with a squad value that is equal to their mean squad value across all seasons and with a mean squad value that is equal to the grand mean squad value. The Squad Value coefficient represents the within-club effect, while the Club Mean Value coefficient is the between-club effect. The within-club effect estimates how increases in any given club’s squad value, relative to their average squad value, impact their outcomes on the pitch. In contrast, the between-club effect estimates how much a difference in a club’s average squad value, relative to the grand mean squad value, impacts outcomes. The Club Mean Value coefficient helps us quantify how differences in the average squad value between clubs affect differences in their outcomes.</p>
<p>Both of these coefficients are log-transformed, which means they are not directly interpretable beyond the direction of the effect. However, we can translate both coefficients to a real-world value. Using the formula <img src="https://latex.codecogs.com/png.latex?38%20%5Ctimes%20%5Cbeta%20%5Ctimes%20%5Ctext%7Blog%7D(1.10)">, where <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> represents the Squad Value or Club Mean Value coefficients, we can estimate how a 10% increase in a club’s squad value<sup>13</sup> (for the average club, this is an increase of ~€24m<sup>14</sup>) impacts outcomes over a 38-game season. Every 10% increase in the value of a club’s squad, the within-club effect, boosts points by an average of ~1.4 points over 38 games, while it also leads to a ~1.5 increase in xG difference and ~2.3 in goal difference. Transforming the between-club effect, on the other hand, estimates the difference in outcomes over a 38-game season between two clubs where one has a 10% higher average squad value across the dataset than the other. The model estimates that a club with a 10% greater mean average squad value over multiple seasons will win an average of ~1.9 more points in any given 38-game season, while their xG and goal differences will be ~2.1 and ~2.9 greater, respectively.</p>
<p>Finally, using the formula <img src="https://latex.codecogs.com/png.latex?%5Cleft(e%5E%7B%5Cfrac%7B3%7D%7B38%20%5Ctimes%20%5Cbeta%7D%7D%20-%201%5Cright)%20%5Ctimes%20100">, we can estimate the percentage increase in a club’s squad value that is required to win three additional points, on average, over a 38-game season. The model predicts an increase of ~22.4% in a club’s squad value is, on average, equivalent to an extra win.</p>
</section>
<section id="group-level-effects" class="level4">
<h4 class="anchored" data-anchor-id="group-level-effects">Group-Level Effects</h4>
<p>Group-level effects estimate the amount that group means vary around the grand mean. At a club level, intercept and slope effects effectively capture two distinct sources of over/underperformance.</p>
<p>Club-level intercept estimates capture variability in baseline performance between clubs. This highlights structural differences at the club level independent of squad value and persistent across time. One standard deviation around the points intercept is worth 0.09 points per game, which amounts to <img src="https://latex.codecogs.com/png.latex?%5Cpm"> 3.42 points over a 38-game season. The largest club-specific intercepts belong to Manchester City and Liverpool, but various clubs perform well. The strongest performers include some of the world’s biggest teams, but Union Berlin also come in third, and VfL Bochum and Bastia are in the top 10. This suggests that money does not explain structural advantages (at least not entirely). It could be institutional knowledge, better facilities (training ground, medical staff, analytics), or manager effects. Perhaps teams are paying the refs off (especially when they are playing your team). Rich clubs will have more money to invest in these areas, but well-run clubs may have opportunities to make efficient gains. I imagine paying off a referee costs less than buying a world-class striker.</p>
<p>On the other hand, club-level slope estimates capture variability in the effect of squad value changes on performance across clubs. Positive club-specific estimates suggest a club has more effectively turned increases in the value of their squad into improvements in outcomes on the pitch<sup>15</sup>. The standard deviation around the points slope (0.15) indicates that a club could gain as much as 5.7 additional points in a 38-game season if they are smart when building their squad. Inter Milan have the largest club-specific slope, followed by Man City and Liverpool, while Stuttgart and Lens round out the top five. In this case, the strongest performers are even more mixed, indicating that it’s not about how much money a team spends but how effectively they spend it<sup>16</sup>.</p>
<p>Finally, league-level effects capture structural differences primarily caused by financial disparities between the Big Five leagues. League intercept effects represent variability driven by the fact that a squad of average value would be more or less competitive depending on the league. In contrast, the league slope effects capture differences in the impact that increases in squad values have between leagues. Ligue 1 has the largest positive intercept, indicating that a squad of average value would be expected to win more points in France. Serie A has the largest positive slope, indicating that increases in squad values can go further in Italy. In contrast, the Premier League has the largest negative slope and intercept because money doesn’t go as far in England’s top flight!</p>
</section>
</section>
<section id="predicting-league-points" class="level3">
<h3 class="anchored" data-anchor-id="predicting-league-points">Predicting League Points</h3>
<p>While it’s useful (and hopefully interesting) to understand how squad values, decomposed into within- and between-club effects, impact outcomes, and how these effects vary at a club- and league-level, I think it’s a little difficult to piece all this together conceptually and develop a complete picture of the effect that financial resources (with squad value used as a proxy) have on outcomes. This is an inevitable difficulty with complex model structures. It becomes increasingly difficult to translate the many moving parts into a simple, intuitive understanding of the effect. Computing predictions using the fitted multilevel model will tell us more. I will focus on league points because I think that’s a little more interesting than looking at goal or xG difference<sup>17</sup>.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/arrested-development.jpg" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:60.0%" alt="The 'It's One Banana Michael' meme from Arrested Development, with Lucille Bluth saying 'I mean, it's one point, Michael? What could it cost? 100 million dollars?'"></p>
</figure>
</div>
<p>We can start by looking at the predicted league points across all of the leagues by squad values over the last three seasons.</p>
<div class="cell">
<details class="code-fold">
<summary>Helper Function Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1">overall_preds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb8-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data) {</span>
<span id="cb8-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predictions</span>(</span>
<span id="cb8-4">      data,</span>
<span id="cb8-5">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">re.form =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>,</span>
<span id="cb8-6">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">variables =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb8-7">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"time"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>,</span>
<span id="cb8-8">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">season =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2021/22"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2022/23"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2023/24"</span>)</span>
<span id="cb8-9">      )</span>
<span id="cb8-10">    )</span>
<span id="cb8-11">  }</span></code></pre></div></div>
</details>
</div>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1">models <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(outcome <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(model) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rowwise</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">preds =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">overall_preds</span>(model))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-6">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unnest</span>(preds) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb9-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(double_mean_club, demean_squad), <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.character</span>(.x))),</span>
<span id="cb9-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">double_mean_club =</span> double_mean_club <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(club_resources<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>squad_value)),</span>
<span id="cb9-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">squad_value =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">exp</span>(demean_squad <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> double_mean_club),</span>
<span id="cb9-11">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(estimate, conf.low, conf.high), <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> .x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">38</span>)</span>
<span id="cb9-12">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(squad_value, estimate)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb9-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb9-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">formula =</span> y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(x),</span>
<span id="cb9-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">se =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb9-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb9-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span></span>
<span id="cb9-20">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb9-22">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> conf.low),</span>
<span id="cb9-23">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb9-24">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">formula =</span> y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(x),</span>
<span id="cb9-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">se =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb9-26">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>,</span>
<span id="cb9-27">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>,</span>
<span id="cb9-28">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linetype =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dashed"</span></span>
<span id="cb9-29">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-30">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb9-31">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> conf.high),</span>
<span id="cb9-32">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb9-33">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">formula =</span> y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(x),</span>
<span id="cb9-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">se =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb9-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>,</span>
<span id="cb9-36">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>,</span>
<span id="cb9-37">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linetype =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dashed"</span></span>
<span id="cb9-38">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-39">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_continuous</span>(</span>
<span id="cb9-40">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_number</span>(</span>
<span id="cb9-41">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale_cut =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cut_short_scale</span>(),</span>
<span id="cb9-42">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prefix =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"€"</span></span>
<span id="cb9-43">    )</span>
<span id="cb9-44">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-45">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb9-46">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicted Points by Squad Value Across the Big Five Leagues"</span>,</span>
<span id="cb9-47">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb9-48">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb9-49">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Conditional adjusted predicted league points by squad market values, "</span>,</span>
<span id="cb9-50">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"across the Big Five leagues in Europe, from 2021/22 - 2023/24. Predicted "</span>,</span>
<span id="cb9-51">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"points calculated by multiplying points per game by 38 to reflect the "</span>,</span>
<span id="cb9-52">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"total points for a 38-game season."</span></span>
<span id="cb9-53">      ),</span>
<span id="cb9-54">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb9-55">    ),</span>
<span id="cb9-56">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value"</span>,</span>
<span id="cb9-57">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicted Points"</span>,</span>
<span id="cb9-58">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: FBref &amp; Transfermarkt Via {worldfootballR}"</span></span>
<span id="cb9-59">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/index_files/figure-html/overall-preds-1.png" class="img-fluid figure-img" alt="A regression plot visualising the relationship between squad market values and the model's predicted points across the Big Five leagues in the last three seasons (2021/22 - 2023/24). The plot includes a fitted regression line and 95% confidence intervals, showing that increases in the lowest squad values lead to exponential gains in predicted points, with squad values up to around €200m leading to predicted points increasing from close to zero up to around 50 points. While further increases in squad value lead to higher predicted points totals, it takes squad values of over €750m to reach 75 points. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>The marginal gains for increases in squad value are the largest at the lower end of the values, appearing to start flattening out somewhere around the €200m point. There is a ton of value to be had in increasing squad value at the lower end of the leagues, but once a team pushes for 50+ points, further spending becomes less efficient.</p>
<p>We can also compare how increases in squad value increase predicted points conditional on the leagues. We will use marginal predictions, which calculate the effect of increases in squad values averaged within each league, plotted below.</p>
<div class="cell">
<details class="code-fold">
<summary>Helper Function Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1">league_preds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb10-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data) {</span>
<span id="cb10-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predictions</span>(</span>
<span id="cb10-4">      data,</span>
<span id="cb10-5">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"demean_squad"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"double_mean_club"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"league"</span>),</span>
<span id="cb10-6">    )</span>
<span id="cb10-7">  }</span></code></pre></div></div>
</details>
</div>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1">models <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(outcome <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(data, model) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rowwise</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">preds =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">league_preds</span>(model))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-6">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unnest</span>(preds) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb11-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(double_mean_club, demean_squad), <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.character</span>(.x))),</span>
<span id="cb11-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">double_mean_club =</span> double_mean_club <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(club_resources<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>squad_value)),</span>
<span id="cb11-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">squad_value =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">exp</span>(demean_squad <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> double_mean_club),</span>
<span id="cb11-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">estimate =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">case_when</span>(</span>
<span id="cb11-12">      league <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bundesliga"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ligue 1"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> estimate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">34</span>,</span>
<span id="cb11-13">      league <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Premier League"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"La Liga"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Serie A"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> estimate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">38</span></span>
<span id="cb11-14">    )</span>
<span id="cb11-15">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(squad_value, estimate, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> league)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-17">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb11-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb11-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">formula =</span> y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(x),</span>
<span id="cb11-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">se =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb11-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>,</span>
<span id="cb11-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb11-23">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-24">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_colour_manual</span>(</span>
<span id="cb11-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#7AB5CC"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#FFA600"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#D93649"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#8C3431"</span>)</span>
<span id="cb11-26">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-27">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_continuous</span>(</span>
<span id="cb11-28">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_number</span>(</span>
<span id="cb11-29">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale_cut =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cut_short_scale</span>(),</span>
<span id="cb11-30">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prefix =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"€"</span></span>
<span id="cb11-31">    )</span>
<span id="cb11-32">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-33">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb11-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicted Points by Squad Value in the Big Five Leagues"</span>,</span>
<span id="cb11-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb11-36">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb11-37">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Marginal adjusted predicted league points, averaged over squad "</span>,</span>
<span id="cb11-38">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"market values in each of the Big Five leagues in Europe from 2012/13 "</span>,</span>
<span id="cb11-39">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"- 2023/24. Predicted points calculated by multiplying points per game "</span>,</span>
<span id="cb11-40">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"by the total games in each league's season."</span></span>
<span id="cb11-41">      ),</span>
<span id="cb11-42">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb11-43">    ),</span>
<span id="cb11-44">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad Value"</span>,</span>
<span id="cb11-45">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicted Points"</span>,</span>
<span id="cb11-46">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: FBref &amp; Transfermarkt Via {worldfootballR}"</span></span>
<span id="cb11-47">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/index_files/figure-html/league-preds-1.png" class="img-fluid figure-img" alt="A regression plot visualising the relationship between squad market values and the model's predicted points in the Big Five leagues from 2012/13 - 2023/24. The plot includes fitted regression lines for each league. The five regression lines are similar in shape. However, the Premier League slope is more gradual with a smaller intercept, suggesting that Premier League teams need more expensive squads to compete and increases in squad value are worth fewer points. The Premier League line also extends further on the x-axis because the most expensive squads in the Premier League are worth significantly more than the rest of the leagues. The intercepts for the other four leagues are very similar, but the Bundesliga and Ligue 1 tail off as squad value increases due to playing fewer games in a season and, therefore, having fewer available points that the increases in squad value could gain. Finally, La Liga and Serie A have similar slopes. The endpoint of the La Liga line is further along the x-axis due to the significantly larger Real Madrid and Barcelona squad values. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>The predicted points lines for each league are relatively similar (accounting for the four fewer games per season in the Bundesliga &amp; Ligue 1). These lines represent the group mean variance around the grand mean intercept and slope (which is effectively what the previous plot shows).</p>
<p>However, there are some interesting details around the margins. The Premier League intercept is a little lower than the other four leagues, which is to be expected because the average value is much higher and, therefore, the base level required to win any points at all is higher. While the Premier League’s predicted points line catches up with the Bundesliga and Ligue 1, this is only due to the fewer available total points in those two leagues per season. The Premier League slope is not as steep, and once all the predicted points lines flatten out, the Premier League remains more or less parallel to the other 38-game-season leagues.</p>
<section id="identifying-performance-abovebelow-expectations" class="level4">
<h4 class="anchored" data-anchor-id="identifying-performance-abovebelow-expectations">Identifying Performance Above/Below Expectations</h4>
<p>All this is very interesting, but the real question is, “How can I use this against my enemies?” Well, we can compute the predicted points for each team and compare these predictions against their actual points totals each season. If your enemies are big dumb idiots, they should be underperforming their predicted points consistently. If all your enemies are King Curtis, maybe you’re the problem…</p>
<p>Performances above/below the model’s expectations for the Premier League’s “top six” from 2012/13 to 2023/24 are plotted below.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">models <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(outcome <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-3">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unnest</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(data, preds)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb12-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">value =</span> value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> mp,</span>
<span id="cb12-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">preds =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(preds <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> mp)</span>
<span id="cb12-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-8">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(</span>
<span id="cb12-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(value, preds),</span>
<span id="cb12-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"type"</span>,</span>
<span id="cb12-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"points"</span></span>
<span id="cb12-12">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb12-14">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">case_when</span>(</span>
<span id="cb12-15">      type <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Total Points"</span>,</span>
<span id="cb12-16">      type <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"preds"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicted Points"</span>,</span>
<span id="cb12-17">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.default =</span> type</span>
<span id="cb12-18">    )</span>
<span id="cb12-19">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(</span>
<span id="cb12-21">    squad <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span></span>
<span id="cb12-22">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb12-23">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Manchester City"</span>,</span>
<span id="cb12-24">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Manchester Utd"</span>,</span>
<span id="cb12-25">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Liverpool"</span>,</span>
<span id="cb12-26">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Arsenal"</span>,</span>
<span id="cb12-27">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Chelsea"</span>,</span>
<span id="cb12-28">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Tottenham"</span></span>
<span id="cb12-29">      )</span>
<span id="cb12-30">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-31">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(season, points, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">group =</span> type, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linetype =</span> type)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-32">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb12-33">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb12-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">formula =</span> y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> splines<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ns</span>(x, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb12-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>,</span>
<span id="cb12-36">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">se =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb12-37">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span></span>
<span id="cb12-38">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-39">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> type), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">shape =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">21</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stroke =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-40">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">guides</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">guide_legend</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">override.aes =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-41">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_fill_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-42">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_linetype_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dashed"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"solid"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-43">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_discrete</span>(</span>
<span id="cb12-44">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">expand =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>),</span>
<span id="cb12-45">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">breaks =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2013/14"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2015/16"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2017/18"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2019/20"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2021/22"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2023/24"</span>)</span>
<span id="cb12-46">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-47">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">facet_wrap</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">facets =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(squad), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nrow =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb12-48">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb12-49">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Premier League Top Six's Performances Above/Below Expectations"</span>,</span>
<span id="cb12-50">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb12-51">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb12-52">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Comparing Arsenal, Chelsea, Liverpool, Man City, Man Utd, &amp; Spurs's "</span>,</span>
<span id="cb12-53">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"total and predicted points in the Premier League from 2012/13 to "</span>,</span>
<span id="cb12-54">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2023/24, conditional on squad market values per season."</span></span>
<span id="cb12-55">      ),</span>
<span id="cb12-56">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb12-57">    ),</span>
<span id="cb12-58">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb12-59">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb12-60">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: FBref &amp; Transfermarkt Via {worldfootballR}"</span></span>
<span id="cb12-61">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/index_files/figure-html/top-six-1.png" class="img-fluid figure-img" alt="A time-series plot visualising Arsenal, Chelsea, Liverpool, Man City, Man United, and Spurs's total and predicted points each season from 2012/13 to 2023/24, including a fitted line that visualises the trends in predicted and total points. Arsenal significantly underperformed expectations midway through the period but in recent seasons have experienced similarly significant overperformances, while Liverpool and Arsenal have consistently overperformed expectations recently. Manchester United and Tottenham have performed above expectations in earlier seasons but have otherwise met expectations. Finally, Chelsea have the largest swings, with massive overperformances in the early seasons and similarly significant underperformances in other seasons. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>These results seem to align with what I would have expected, for the most part (though Chelsea’s early years are pretty chaotic). The exception is Manchester United, who have, miraculously, performed close to expectations over the period. Any model that doesn’t paint United as a gang of dumb idiots in the post-Fergie years is getting at least one thing wrong.</p>
<p>I think this highlights a flaw in the methodology used here, particularly around the operationalisation of “squad market values” as a proxy for the club’s financial clout. A critical assumption underpinning the use of squad values in this model is that teams are approximately smart enough to spend their money on the best players they can afford. The intelligent teams will get the better deals, and the dummies will overspend, but the spending will at least appear reasonable enough to reflect in the value of the squad. Over and underperformance can then be assumed to represent the teams that have been smart versus those that have misspent (though, in reality, it will be a function of other factors, too). In Manchester United’s case, they are not performing significantly above or below expectations based on their squad value, but this is likely due to the fact their squad building has been so poor that the Transfermarkt squad values don’t capture the amount they’ve spent on new players because the valuations are so misaligned with the fees United paid.</p>
<section id="the-biggest-over-underperformers" class="level5">
<h5 class="anchored" data-anchor-id="the-biggest-over-underperformers">The Biggest Over &amp; Underperformers</h5>
<p>Finally, let’s sort the penny-wise from the (billion) pound foolish. Table&nbsp;2 and Table&nbsp;3 include the top three teams in each league regarding overperformance and underperformance, calculating each team’s total predicted points as a percentage above or below their total points, respectively.</p>
<div class="cell">
<details class="code-fold">
<summary>Function Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1">performance_table <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb13-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(min_max) {</span>
<span id="cb13-3">    models <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-4">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(outcome <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-5">      tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unnest</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(data, preds)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-6">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> squad) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-7">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb13-8">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">value =</span> value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> mp,</span>
<span id="cb13-9">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">preds =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(preds <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> mp)</span>
<span id="cb13-10">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-11">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(</span>
<span id="cb13-12">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mp =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(mp),</span>
<span id="cb13-13">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">avg_ppg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(value) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> mp,</span>
<span id="cb13-14">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pred_ppg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(preds) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> mp,</span>
<span id="cb13-15">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pct_diff =</span> (avg_ppg <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> pred_ppg) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb13-16">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(squad, league)</span>
<span id="cb13-17">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-18">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">min_max</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">order_by =</span> pct_diff, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> league) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-19">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(squad, league, avg_ppg, pred_ppg, pct_diff) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-20">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">groupname_col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"league"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rowname_col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"squad"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-21">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_label</span>(</span>
<span id="cb13-22">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">avg_ppg =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Average"</span>,</span>
<span id="cb13-23">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pred_ppg =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicted"</span>,</span>
<span id="cb13-24">        pct_diff <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Over/Under"</span></span>
<span id="cb13-25">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-26">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_spanner</span>(</span>
<span id="cb13-27">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points Per Game"</span>,</span>
<span id="cb13-28">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(avg_ppg, pred_ppg)</span>
<span id="cb13-29">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-30">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fmt_number</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(avg_ppg, pred_ppg, pct_diff), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">decimals =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-31">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fmt_percent</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> pct_diff) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-32">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_align</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(avg_ppg, pred_ppg, pct_diff)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-33">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb13-34">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">weight =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bold"</span>),</span>
<span id="cb13-35">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_row_groups</span>()</span>
<span id="cb13-36">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-37">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>()</span>
<span id="cb13-38">  }</span></code></pre></div></div>
</details>
</div>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true" href="">Overperformers</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false" href="">Underperformers</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">performance_table</span>(slice_max)</span></code></pre></div></div>
</details>
<div id="tbl-overperformers" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-overperformers-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;2: The Biggest Overperformers in the Big Five Leagues
</figcaption>
<div aria-describedby="tbl-overperformers-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="frxpwpqopz" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#frxpwpqopz table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#frxpwpqopz thead, #frxpwpqopz tbody, #frxpwpqopz tfoot, #frxpwpqopz tr, #frxpwpqopz td, #frxpwpqopz th {
  border-style: none;
}

#frxpwpqopz p {
  margin: 0;
  padding: 0;
}

#frxpwpqopz .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#frxpwpqopz .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#frxpwpqopz .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#frxpwpqopz .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#frxpwpqopz .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#frxpwpqopz .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#frxpwpqopz .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#frxpwpqopz .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#frxpwpqopz .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#frxpwpqopz .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#frxpwpqopz .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#frxpwpqopz .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#frxpwpqopz .gt_spanner_row {
  border-bottom-style: hidden;
}

#frxpwpqopz .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#frxpwpqopz .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#frxpwpqopz .gt_from_md > :first-child {
  margin-top: 0;
}

#frxpwpqopz .gt_from_md > :last-child {
  margin-bottom: 0;
}

#frxpwpqopz .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#frxpwpqopz .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#frxpwpqopz .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#frxpwpqopz .gt_row_group_first td {
  border-top-width: 2px;
}

#frxpwpqopz .gt_row_group_first th {
  border-top-width: 2px;
}

#frxpwpqopz .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#frxpwpqopz .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#frxpwpqopz .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#frxpwpqopz .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#frxpwpqopz .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#frxpwpqopz .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#frxpwpqopz .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#frxpwpqopz .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#frxpwpqopz .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#frxpwpqopz .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#frxpwpqopz .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#frxpwpqopz .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#frxpwpqopz .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#frxpwpqopz .gt_left {
  text-align: left;
}

#frxpwpqopz .gt_center {
  text-align: center;
}

#frxpwpqopz .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#frxpwpqopz .gt_font_normal {
  font-weight: normal;
}

#frxpwpqopz .gt_font_bold {
  font-weight: bold;
}

#frxpwpqopz .gt_font_italic {
  font-style: italic;
}

#frxpwpqopz .gt_super {
  font-size: 65%;
}

#frxpwpqopz .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#frxpwpqopz .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#frxpwpqopz .gt_indent_1 {
  text-indent: 5px;
}

#frxpwpqopz .gt_indent_2 {
  text-indent: 10px;
}

#frxpwpqopz .gt_indent_3 {
  text-indent: 15px;
}

#frxpwpqopz .gt_indent_4 {
  text-indent: 20px;
}

#frxpwpqopz .gt_indent_5 {
  text-indent: 25px;
}

#frxpwpqopz .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#frxpwpqopz div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<colgroup>
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
</colgroup>
<thead>
<tr class="gt_col_headings gt_spanner_row header">
<th rowspan="2" id="a::stub" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col"></th>
<th colspan="2" id="Points Per Game" class="gt_center gt_columns_top_border gt_column_spanner_outer" data-quarto-table-cell-role="th" scope="colgroup"><div class="gt_column_spanner">
Points Per Game
</div></th>
<th rowspan="2" id="pct_diff" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Over/Under</th>
</tr>
<tr class="gt_col_headings even">
<th id="avg_ppg" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Average</th>
<th id="pred_ppg" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Predicted</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="gt_group_heading_row odd">
<th colspan="4" id="Premier League" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">Premier League</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_1" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Manchester City</th>
<td class="gt_row gt_center" headers="Premier League stub_1_1 avg_ppg">2.25</td>
<td class="gt_row gt_center" headers="Premier League stub_1_1 pred_ppg">2.14</td>
<td class="gt_row gt_center" headers="Premier League stub_1_1 pct_diff">5.02%</td>
</tr>
<tr class="odd">
<th id="stub_1_2" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Burnley</th>
<td class="gt_row gt_center" headers="Premier League stub_1_2 avg_ppg">1.05</td>
<td class="gt_row gt_center" headers="Premier League stub_1_2 pred_ppg">1.00</td>
<td class="gt_row gt_center" headers="Premier League stub_1_2 pct_diff">4.59%</td>
</tr>
<tr class="even">
<th id="stub_1_3" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Stoke City</th>
<td class="gt_row gt_center" headers="Premier League stub_1_3 avg_ppg">1.20</td>
<td class="gt_row gt_center" headers="Premier League stub_1_3 pred_ppg">1.15</td>
<td class="gt_row gt_center" headers="Premier League stub_1_3 pct_diff">4.18%</td>
</tr>
<tr class="gt_group_heading_row odd">
<th colspan="4" id="La Liga" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">La Liga</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_4" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Cádiz</th>
<td class="gt_row gt_center" headers="La Liga stub_1_4 avg_ppg">1.04</td>
<td class="gt_row gt_center" headers="La Liga stub_1_4 pred_ppg">0.88</td>
<td class="gt_row gt_center" headers="La Liga stub_1_4 pct_diff">18.80%</td>
</tr>
<tr class="odd">
<th id="stub_1_5" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Girona</th>
<td class="gt_row gt_center" headers="La Liga stub_1_5 avg_ppg">1.43</td>
<td class="gt_row gt_center" headers="La Liga stub_1_5 pred_ppg">1.32</td>
<td class="gt_row gt_center" headers="La Liga stub_1_5 pct_diff">8.46%</td>
</tr>
<tr class="even">
<th id="stub_1_6" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Eibar</th>
<td class="gt_row gt_center" headers="La Liga stub_1_6 avg_ppg">1.14</td>
<td class="gt_row gt_center" headers="La Liga stub_1_6 pred_ppg">1.05</td>
<td class="gt_row gt_center" headers="La Liga stub_1_6 pct_diff">7.86%</td>
</tr>
<tr class="gt_group_heading_row odd">
<th colspan="4" id="Ligue 1" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">Ligue 1</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_7" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Bastia</th>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_7 avg_ppg">1.19</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_7 pred_ppg">1.06</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_7 pct_diff">12.94%</td>
</tr>
<tr class="odd">
<th id="stub_1_8" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Guingamp</th>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_8 avg_ppg">1.14</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_8 pred_ppg">1.04</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_8 pct_diff">9.28%</td>
</tr>
<tr class="even">
<th id="stub_1_9" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Lens</th>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_9 avg_ppg">1.52</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_9 pred_ppg">1.43</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_9 pct_diff">6.39%</td>
</tr>
<tr class="gt_group_heading_row odd">
<th colspan="4" id="Bundesliga" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">Bundesliga</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_10" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Union Berlin</th>
<td class="gt_row gt_center" headers="Bundesliga stub_1_10 avg_ppg">1.43</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_10 pred_ppg">1.21</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_10 pct_diff">17.96%</td>
</tr>
<tr class="odd">
<th id="stub_1_11" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Bayern Munich</th>
<td class="gt_row gt_center" headers="Bundesliga stub_1_11 avg_ppg">2.38</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_11 pred_ppg">2.32</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_11 pct_diff">2.64%</td>
</tr>
<tr class="even">
<th id="stub_1_12" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Augsburg</th>
<td class="gt_row gt_center" headers="Bundesliga stub_1_12 avg_ppg">1.14</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_12 pred_ppg">1.12</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_12 pct_diff">1.97%</td>
</tr>
<tr class="gt_group_heading_row odd">
<th colspan="4" id="Serie A" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">Serie A</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_13" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Chievo</th>
<td class="gt_row gt_center" headers="Serie A stub_1_13 avg_ppg">1.03</td>
<td class="gt_row gt_center" headers="Serie A stub_1_13 pred_ppg">0.96</td>
<td class="gt_row gt_center" headers="Serie A stub_1_13 pct_diff">7.03%</td>
</tr>
<tr class="odd">
<th id="stub_1_14" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Juventus</th>
<td class="gt_row gt_center" headers="Serie A stub_1_14 avg_ppg">2.21</td>
<td class="gt_row gt_center" headers="Serie A stub_1_14 pred_ppg">2.12</td>
<td class="gt_row gt_center" headers="Serie A stub_1_14 pct_diff">4.14%</td>
</tr>
<tr class="even">
<th id="stub_1_15" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Lazio</th>
<td class="gt_row gt_center" headers="Serie A stub_1_15 avg_ppg">1.72</td>
<td class="gt_row gt_center" headers="Serie A stub_1_15 pred_ppg">1.67</td>
<td class="gt_row gt_center" headers="Serie A stub_1_15 pct_diff">3.01%</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="4" class="gt_sourcenote" style="text-align: left;">Source: FBref &amp; Transfermarkt Via {worldfootballR}</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">performance_table</span>(slice_min)</span></code></pre></div></div>
</details>
<div id="tbl-underperformers" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-underperformers-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;3: The Biggest Underperformers in the Big Five Leagues
</figcaption>
<div aria-describedby="tbl-underperformers-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="esiedncwxh" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#esiedncwxh table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#esiedncwxh thead, #esiedncwxh tbody, #esiedncwxh tfoot, #esiedncwxh tr, #esiedncwxh td, #esiedncwxh th {
  border-style: none;
}

#esiedncwxh p {
  margin: 0;
  padding: 0;
}

#esiedncwxh .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#esiedncwxh .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#esiedncwxh .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#esiedncwxh .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#esiedncwxh .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#esiedncwxh .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#esiedncwxh .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#esiedncwxh .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#esiedncwxh .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#esiedncwxh .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#esiedncwxh .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#esiedncwxh .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#esiedncwxh .gt_spanner_row {
  border-bottom-style: hidden;
}

#esiedncwxh .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#esiedncwxh .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#esiedncwxh .gt_from_md > :first-child {
  margin-top: 0;
}

#esiedncwxh .gt_from_md > :last-child {
  margin-bottom: 0;
}

#esiedncwxh .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#esiedncwxh .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#esiedncwxh .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#esiedncwxh .gt_row_group_first td {
  border-top-width: 2px;
}

#esiedncwxh .gt_row_group_first th {
  border-top-width: 2px;
}

#esiedncwxh .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#esiedncwxh .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#esiedncwxh .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#esiedncwxh .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#esiedncwxh .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#esiedncwxh .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#esiedncwxh .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#esiedncwxh .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#esiedncwxh .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#esiedncwxh .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#esiedncwxh .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#esiedncwxh .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#esiedncwxh .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#esiedncwxh .gt_left {
  text-align: left;
}

#esiedncwxh .gt_center {
  text-align: center;
}

#esiedncwxh .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#esiedncwxh .gt_font_normal {
  font-weight: normal;
}

#esiedncwxh .gt_font_bold {
  font-weight: bold;
}

#esiedncwxh .gt_font_italic {
  font-style: italic;
}

#esiedncwxh .gt_super {
  font-size: 65%;
}

#esiedncwxh .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#esiedncwxh .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#esiedncwxh .gt_indent_1 {
  text-indent: 5px;
}

#esiedncwxh .gt_indent_2 {
  text-indent: 10px;
}

#esiedncwxh .gt_indent_3 {
  text-indent: 15px;
}

#esiedncwxh .gt_indent_4 {
  text-indent: 20px;
}

#esiedncwxh .gt_indent_5 {
  text-indent: 25px;
}

#esiedncwxh .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#esiedncwxh div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<colgroup>
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
</colgroup>
<thead>
<tr class="gt_col_headings gt_spanner_row header">
<th rowspan="2" id="a::stub" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col"></th>
<th colspan="2" id="Points Per Game" class="gt_center gt_columns_top_border gt_column_spanner_outer" data-quarto-table-cell-role="th" scope="colgroup"><div class="gt_column_spanner">
Points Per Game
</div></th>
<th rowspan="2" id="pct_diff" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Over/Under</th>
</tr>
<tr class="gt_col_headings even">
<th id="avg_ppg" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Average</th>
<th id="pred_ppg" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Predicted</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="gt_group_heading_row odd">
<th colspan="4" id="Premier League" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">Premier League</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_1" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Fulham</th>
<td class="gt_row gt_center" headers="Premier League stub_1_1 avg_ppg">1.00</td>
<td class="gt_row gt_center" headers="Premier League stub_1_1 pred_ppg">1.09</td>
<td class="gt_row gt_center" headers="Premier League stub_1_1 pct_diff">−8.43%</td>
</tr>
<tr class="odd">
<th id="stub_1_2" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Sunderland</th>
<td class="gt_row gt_center" headers="Premier League stub_1_2 avg_ppg">0.94</td>
<td class="gt_row gt_center" headers="Premier League stub_1_2 pred_ppg">1.01</td>
<td class="gt_row gt_center" headers="Premier League stub_1_2 pct_diff">−7.29%</td>
</tr>
<tr class="even">
<th id="stub_1_3" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Norwich City</th>
<td class="gt_row gt_center" headers="Premier League stub_1_3 avg_ppg">0.81</td>
<td class="gt_row gt_center" headers="Premier League stub_1_3 pred_ppg">0.87</td>
<td class="gt_row gt_center" headers="Premier League stub_1_3 pct_diff">−7.23%</td>
</tr>
<tr class="gt_group_heading_row odd">
<th colspan="4" id="La Liga" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">La Liga</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_4" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Deportivo de La Coruña</th>
<td class="gt_row gt_center" headers="La Liga stub_1_4 avg_ppg">0.93</td>
<td class="gt_row gt_center" headers="La Liga stub_1_4 pred_ppg">1.01</td>
<td class="gt_row gt_center" headers="La Liga stub_1_4 pct_diff">−7.33%</td>
</tr>
<tr class="odd">
<th id="stub_1_5" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Valencia</th>
<td class="gt_row gt_center" headers="La Liga stub_1_5 avg_ppg">1.43</td>
<td class="gt_row gt_center" headers="La Liga stub_1_5 pred_ppg">1.52</td>
<td class="gt_row gt_center" headers="La Liga stub_1_5 pct_diff">−6.20%</td>
</tr>
<tr class="even">
<th id="stub_1_6" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Almería</th>
<td class="gt_row gt_center" headers="La Liga stub_1_6 avg_ppg">0.86</td>
<td class="gt_row gt_center" headers="La Liga stub_1_6 pred_ppg">0.91</td>
<td class="gt_row gt_center" headers="La Liga stub_1_6 pct_diff">−5.76%</td>
</tr>
<tr class="gt_group_heading_row odd">
<th colspan="4" id="Ligue 1" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">Ligue 1</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_7" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Troyes</th>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_7 avg_ppg">0.79</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_7 pred_ppg">0.87</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_7 pct_diff">−9.09%</td>
</tr>
<tr class="odd">
<th id="stub_1_8" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Toulouse</th>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_8 avg_ppg">1.11</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_8 pred_ppg">1.17</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_8 pct_diff">−5.15%</td>
</tr>
<tr class="even">
<th id="stub_1_9" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Metz</th>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_9 avg_ppg">0.95</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_9 pred_ppg">1.00</td>
<td class="gt_row gt_center" headers="Ligue 1 stub_1_9 pct_diff">−4.38%</td>
</tr>
<tr class="gt_group_heading_row odd">
<th colspan="4" id="Bundesliga" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">Bundesliga</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_10" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Schalke</th>
<td class="gt_row gt_center" headers="Bundesliga stub_1_10 avg_ppg">1.31</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_10 pred_ppg">1.41</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_10 pct_diff">−7.11%</td>
</tr>
<tr class="odd">
<th id="stub_1_11" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Hannover 96</th>
<td class="gt_row gt_center" headers="Bundesliga stub_1_11 avg_ppg">1.02</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_11 pred_ppg">1.10</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_11 pct_diff">−7.11%</td>
</tr>
<tr class="even">
<th id="stub_1_12" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Hamburger SV</th>
<td class="gt_row gt_center" headers="Bundesliga stub_1_12 avg_ppg">1.08</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_12 pred_ppg">1.15</td>
<td class="gt_row gt_center" headers="Bundesliga stub_1_12 pct_diff">−5.98%</td>
</tr>
<tr class="gt_group_heading_row odd">
<th colspan="4" id="Serie A" class="gt_group_heading" data-quarto-table-cell-role="th" style="font-weight: bold" scope="colgroup">Serie A</th>
</tr>
<tr class="gt_row_group_first even">
<th id="stub_1_13" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Palermo</th>
<td class="gt_row gt_center" headers="Serie A stub_1_13 avg_ppg">0.96</td>
<td class="gt_row gt_center" headers="Serie A stub_1_13 pred_ppg">1.02</td>
<td class="gt_row gt_center" headers="Serie A stub_1_13 pct_diff">−5.81%</td>
</tr>
<tr class="odd">
<th id="stub_1_14" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Parma</th>
<td class="gt_row gt_center" headers="Serie A stub_1_14 avg_ppg">1.04</td>
<td class="gt_row gt_center" headers="Serie A stub_1_14 pred_ppg">1.09</td>
<td class="gt_row gt_center" headers="Serie A stub_1_14 pct_diff">−4.84%</td>
</tr>
<tr class="even">
<th id="stub_1_15" class="gt_row gt_left gt_stub" data-quarto-table-cell-role="th" scope="row">Genoa</th>
<td class="gt_row gt_center" headers="Serie A stub_1_15 avg_ppg">1.10</td>
<td class="gt_row gt_center" headers="Serie A stub_1_15 pred_ppg">1.15</td>
<td class="gt_row gt_center" headers="Serie A stub_1_15 pct_diff">−4.37%</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="4" class="gt_sourcenote" style="text-align: left;">Source: FBref &amp; Transfermarkt Via {worldfootballR}</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
</div>
</div>
</div>
<p>The biggest overperformers across all five leagues are Cádiz (18.8%), Union Berlin (17.96%), and Bastia (12.94%). Interestingly, there is a decent mix of teams in Table&nbsp;2. While the biggest overperformers have been promoted and defied the odds, Manchester City, Juventus, and Bayern Munich show there are a few different ways to beat the model!</p>
<p>On the other side, the biggest underperformers are a little less dramatic, with Troyes (-9.09%), Fulham (-8.43%), and Deportivo de La Coruña (-7.33%) edging out the competition to top the table. Unlike Table&nbsp;2, the vast majority of the teams in Table&nbsp;3 are expected to struggle in the league but end up underperforming their already low expectations according to their squad values<sup>18</sup>. The only exceptions are Valencia and Schalke, who both fell on hard times financially despite being big hitters in their respective leagues.</p>
<p>The best and worst of the bunch are plotted below to illustrate what the largest over and underperformances look like (though I’ve selected the two underperformers I found most interesting since it was so close and I’m a real selfish guy).</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1">models <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb16-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(outcome <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Points"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb16-3">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unnest</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(data, preds)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb16-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb16-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">value =</span> value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> mp,</span>
<span id="cb16-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">preds =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(preds <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> mp)</span>
<span id="cb16-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb16-8">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(</span>
<span id="cb16-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(value, preds),</span>
<span id="cb16-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"type"</span>,</span>
<span id="cb16-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"points"</span></span>
<span id="cb16-12">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb16-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb16-14">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">case_when</span>(</span>
<span id="cb16-15">      type <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Total Points"</span>,</span>
<span id="cb16-16">      type <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"preds"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicted Points"</span>,</span>
<span id="cb16-17">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.default =</span> type</span>
<span id="cb16-18">    )</span>
<span id="cb16-19">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb16-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(</span>
<span id="cb16-21">    squad <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span></span>
<span id="cb16-22">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb16-23">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Valencia"</span>,</span>
<span id="cb16-24">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Schalke"</span>,</span>
<span id="cb16-25">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Union Berlin"</span>,</span>
<span id="cb16-26">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cádiz"</span></span>
<span id="cb16-27">      )</span>
<span id="cb16-28">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb16-29">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(season, points, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">group =</span> type, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linetype =</span> type)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-30">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb16-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb16-32">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">formula =</span> y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> splines<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ns</span>(x, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb16-33">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>,</span>
<span id="cb16-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">se =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb16-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span></span>
<span id="cb16-36">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-37">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> type), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">shape =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">21</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stroke =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-38">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">guides</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">guide_legend</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">override.aes =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-39">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_fill_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343a40"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-40">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_linetype_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dashed"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"solid"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-41">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_discrete</span>(</span>
<span id="cb16-42">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">expand =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>),</span>
<span id="cb16-43">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">breaks =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2013/14"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2015/16"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2017/18"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2019/20"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2021/22"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2023/24"</span>)</span>
<span id="cb16-44">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-45">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">facet_wrap</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">facets =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(squad), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nrow =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scales =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"free_x"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-46">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb16-47">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Significant Over/Underperformers Across the Big Five Leagues"</span>,</span>
<span id="cb16-48">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb16-49">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb16-50">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Comparing Cádiz, Schalke, Union Berlin, and Valencia's total and "</span>,</span>
<span id="cb16-51">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"predicted points in their respective leagues from 2012/13 to "</span>,</span>
<span id="cb16-52">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2023/24, conditional on squad market values per season."</span></span>
<span id="cb16-53">      ),</span>
<span id="cb16-54">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb16-55">    ),</span>
<span id="cb16-56">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb16-57">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb16-58">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson | Data: FBref &amp; Transfermarkt Via {worldfootballR}"</span></span>
<span id="cb16-59">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/index_files/figure-html/best-and-worst-1.png" class="img-fluid figure-img" alt="A time-series plot visualising Cádiz, Schalke, Union Berlin, and Valencia's total and predicted points each season from 2012/13 to 2023/24, including a fitted line that visualises the trends in predicted and total points. Cádiz were promoted in 2020/21 and overperformed their predicted points every season until being relegated last season, while Union Berlin have had a similar experience, being promoted in 2019/20 and massively overperforming expectations until a signficant underperformance last season (though they avoided relegation). Schalke and Valencia, on the other hand, have consistently underperformed while also seeing a significant decline in their predicted points. " width="672"></p>
</figure>
</div>
</div>
</div>
</section>
</section>
</section>
</section>
<section id="wrapping-up" class="level2">
<h2 class="anchored" data-anchor-id="wrapping-up">Wrapping Up</h2>
<p>Several thousand words later, we can conclude that the rich stay winning. Don’t worry, though. The evidence also shows that success isn’t <strong>all</strong> about money. It’s possible to overperform expectations, even at the top of the table, and some clubs manage this consistently. Like the rest of the world, football is a meritocracy, after all. If you’re rich and stupid, you only consistently finish above everyone else except those who are both rich and not dumb as rocks. It’s heartwarming stuff.</p>
<p>I started this blog post wondering whether I was writing a multilevel regression tutorial using football data as an example or an analysis of the money in football using a multilevel model. I still don’t know which it is. Maybe this is a Choose Your Own Adventure blog post for nerds? Whichever adventure you chose, I hope you enjoyed it. And if you didn’t, please don’t write mean things about me on the Internet.</p>
<p>In the interest of overpromising and underdelivering, I have the lofty goals of a follow-up blog post that recreates some of this and potentially builds on it further, using Bayesian methods. I may build a Bayesian multilevel model that looks at changes in squad value from season to season. It remains to be seen if it will take me two years to finish like this one.</p>
</section>




<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Many thanks to Camilo Alvarez and Adam Ozer for their helpful feedback during the development of this blog post. I greatly appreciate anyone who helps me be just a little less stupid.</p>
<p>Preview image by <a href="https://unsplash.com/@diesektion">Robert Anasch</a> on <a href="https://unsplash.com/photos/100-banknote-lot-Wnp7qnhHtyw">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>



</div></section><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-bafumi2007" class="csl-entry">
Bafumi, Joseph, and Andrew Gelman. 2007. <span>“Fitting Multilevel Models When Predictors and Group Effects Correlate.”</span> <em>Available at SSRN 1010095</em>.
</div>
<div id="ref-bell2019" class="csl-entry">
Bell, Andrew, Malcolm Fairbrother, and Kelvyn Jones. 2019. <span>“Fixed and Random Effects Models: Making an Informed Choice.”</span> <em>Quality &amp; Quantity</em> 53: 1051–74.
</div>
<div id="ref-coates2022" class="csl-entry">
Coates, Dennis, and Petr Parshakov. 2022. <span>“The Wisdom of Crowds and Transfer Market Values.”</span> <em>European Journal of Operational Research</em> 301 (2): 523–34.
</div>
<div id="ref-enders2007" class="csl-entry">
Enders, Craig K, and Davood Tofighi. 2007. <span>“Centering Predictor Variables in Cross-Sectional Multilevel Models: A New Look at an Old Issue.”</span> <em>Psychological Methods</em> 12 (2): 121.
</div>
<div id="ref-gelman2006" class="csl-entry">
Gelman, Andrew. 2006. <span>“Multilevel (Hierarchical) Modeling: What It Can and Cannot Do.”</span> <em>Technometrics</em> 48 (3): 432–35. <a href="http://www.stat.columbia.edu/~gelman/research/published/multi2.pdf">http://www.stat.columbia.edu/~gelman/research/published/multi2.pdf</a>.
</div>
<div id="ref-herm2014" class="csl-entry">
Herm, Steffen, Hans-Markus Callsen-Bracker, and Henning Kreis. 2014. <span>“When the Crowd Evaluates Soccer Players’ Market Values: Accuracy and Evaluation Attributes of an Online Community.”</span> <em>Sport Management Review</em> 17 (4): 484–92. <a href="https://www.sciencedirect.com/science/article/abs/pii/S144135231300096X">https://www.sciencedirect.com/science/article/abs/pii/S144135231300096X</a>.
</div>
<div id="ref-james2022" class="csl-entry">
James, Stuart. 2022. <span>“How Do You Value a Player?”</span> <em>The Athletic</em>. <a href="https://www.nytimes.com/athletic/3085749/2022/01/27/premier-league-how-do-you-value-a-player/">https://www.nytimes.com/athletic/3085749/2022/01/27/premier-league-how-do-you-value-a-player/</a>.
</div>
<div id="ref-mcelreath2017" class="csl-entry">
McElreath, Richard. 2017. <em>Multilevel Regression as Default</em>. <a href="https://elevanth.org/blog/2017/08/24/multilevel-regression-as-default/">https://elevanth.org/blog/2017/08/24/multilevel-regression-as-default/</a>.
</div>
<div id="ref-mcelreath2018" class="csl-entry">
McElreath, Richard. 2018. <em>Statistical Rethinking: A Bayesian Course with Examples in <span>R</span> and Stan</em>. Chapman; Hall/CRC.
</div>
<div id="ref-mcelreath2023" class="csl-entry">
McElreath, Richard. 2023. <em>Statistical Rethinking 2023 - 12 - Multilevel Models</em>. YouTube. <a href="https://youtu.be/iwVqiiXYeC4?si=YL4re2wbpJHR9Aft">https://youtu.be/iwVqiiXYeC4?si=YL4re2wbpJHR9Aft</a>.
</div>
<div id="ref-muller2017" class="csl-entry">
Müller, Oliver, Alexander Simons, and Markus Weinmann. 2017. <span>“Beyond Crowd Judgments: Data-Driven Estimation of Market Value in Association Football.”</span> <em>European Journal of Operational Research</em> 263 (2): 611–24. <a href="https://www.sciencedirect.com/science/article/pii/S0377221717304332">https://www.sciencedirect.com/science/article/pii/S0377221717304332</a>.
</div>
<div id="ref-prockl2018" class="csl-entry">
Prockl, Franziska, and Bernd Frick. 2018. <span>“Information Precision in Online Communities: Player Valuations on <span class="nocase">www.transfermarkt.de</span>.”</span> <em>International Journal of Sport Finance</em> 13 (4): 319–35. <a href="https://d-nb.info/124512143X/34">https://d-nb.info/124512143X/34</a>.
</div>
<div id="ref-smith2021" class="csl-entry">
Smith, Rory. 2021. <span>“How Transfermarkt Helps Determine the Value of Soccer Players.”</span> <em>New York Times</em>. <a href="https://www.nytimes.com/2021/08/12/sports/soccer/soccer-football-transfermarkt.html">https://www.nytimes.com/2021/08/12/sports/soccer/soccer-football-transfermarkt.html</a>.
</div>
<div id="ref-surowiecki2005" class="csl-entry">
Surowiecki, James. 2005. <em>The Wisdom of Crowds</em>. Random House.
</div>
<div id="ref-transfermarkt2021" class="csl-entry">
Transfermarkt. 2021. <em>Transfermarkt Market Value Board - Market Value Definition</em>. Transfermarkt.com. <a href="https://www.transfermarkt.com/market-value-definition/thread/forum/357/thread_id/3433">https://www.transfermarkt.com/market-value-definition/thread/forum/357/thread_id/3433</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>His name is Adam <strong>LOSER</strong>.↩︎</p></li>
<li id="fn2"><p>Please don’t @ me if you use Tobits all the time. <del>You’re probably incredibly dull.</del> It’s just a silly joke.↩︎</p></li>
<li id="fn3"><p>The eagle-eyed among you will notice that the tweet is over two years old. I haven’t spent the last two years so seething with rage that I cannot concentrate on building my silly little model that would prove Stefan wrong. I’ve just been kicking this idea around for a couple of years and have finally gotten around to finishing it off.↩︎</p></li>
<li id="fn4"><p>Each observation is assumed to contribute equally independent information. Clustered data points, however, will be partially dependent, which makes some of the information contributed by each point redundant. While the data may contain 100 observations, the information contributed will be equivalent to fewer independent observations.↩︎</p></li>
<li id="fn5"><p>I will borrow heavily from McElreath’s approach to explaining multilevel models from Statistical Rethinking <span class="citation" data-cites="mcelreath2018 mcelreath2023">(2018, 2023)</span> because any attempt by me to improve it will probably be a complete mess. If you find yourself thirsty for knowledge (about statistical modelling, including multilevel models), having read this blog post, Statistical Rethinking (in either book or video form) is an excellent place to start.↩︎</p></li>
<li id="fn6"><p>Regularisation deliberately constrains model parameters to discourage the model from fitting to the noise in the data and make the model more generalisable.↩︎</p></li>
<li id="fn7"><p>Underfitting describes a situation where a model is too simple and cannot capture the data’s true underlying structure.↩︎</p></li>
<li id="fn8"><p>Overfitting, as you may have guessed, is the opposite of underfitting. It describes a situation where a model is too complex and captures the observed data structure in detail but, in the process, also captures the noise and quirks of the sample data.↩︎</p></li>
<li id="fn9"><p>I know I probably should have used a legend here, but seasons are discrete values and 12 different values in a legend is silly. All you really need to see is the shifting of the regression lines over time.↩︎</p></li>
<li id="fn10"><p>Group-mean centring takes the average value of the variable for each group at the relevant level (in this case, clubs) and subtracts this value from the population values to “centre” them around the group mean. In this instance, the heterogeneity bias is sufficiently negated by group-mean centring at the club level because this is the primary source of the variance in squad values at the group level.↩︎</p></li>
<li id="fn11"><p>Nested and crossed grouping structures are another example of the flexibility and complexity that can be specified in a multilevel model. They describe how grouping structures relate to each other when the data has three or more hierarchical levels. Grouping structures are nested when a lower-level grouping is entirely contained within another higher-level grouping, meaning that each of the lower-level groups belongs to only one of the higher-level groups. For example, the clubs in our data are entirely nested within their league. Manchester United have never broken out of their containment and run loose in the Bundesliga (and while teams can be relegated, the lower tiers are not included in this data). Grouping structures are crossed, on the other hand, when the lower-level grouping is only partially contained within the higher-level grouping. The lower-level groups can belong to any higher-level groups (and multiple groups) when crossed. Seasons are crossed with leagues and teams because both can belong to every one of the seasons (and in the case of the leagues, they <strong>do</strong> belong to each season).↩︎</p></li>
<li id="fn12"><p>I chose not to centre time because I don’t think this would make the intercept easier to interpret. Consequently, all three models’ intercepts are high because the average club’s average squad value will be high by 2012/13 standards.↩︎</p></li>
<li id="fn13"><p>It’s worth noting that this is a net increase in squad values, so what matters is how much more the incoming players are worth than those who are outgoing.↩︎</p></li>
<li id="fn14"><p>I used 10% increases in squad values over 1% because this seems more meaningful. A 1% increase for a club with an average squad value is an increase of ~€2.4m.↩︎</p></li>
<li id="fn15"><p>I have lumped manager effects in as a structural advantage on the assumption that better managers raise a club’s baseline outcomes regardless of squad value. However, manager effects may influence the club-level slope, too, as a better manager gets more out of investments in the squad. We also know that manager effects will bleed into Transfermarkt’s squad values - better managers improving players, leading to those players being given higher values - which will bias the population-level estimates (especially the within-effect). This points to a limitation of the model and use of squad values. Football is a complex, dynamic system with many moving parts, all of which can affect outcomes on the pitch. Limitations are okay.↩︎</p></li>
<li id="fn16"><p>Luck will also be a factor. A team running hot over multiple seasons will look like meaningful overperformance, and a dip in performances caused by a debilitating injury crisis will, at least partially, be attributed to mistakes made by the club’s decision-makers. While the model should, by design, handle this sort of variance well, football is highly random. Some of this randomness will inevitably bleed into some of the model’s estimates, and I suspect this will show up most at the club level.↩︎</p></li>
<li id="fn17"><p>Watch the games, spreadsheet nerds!↩︎</p></li>
<li id="fn18"><p>I also checked the numbers for the predicted xG differences and the same trend seems to apply, with the biggest overperformers being a bit of a mix and the underperformers being almost exclusively teams for whom the floor seems to have dropped out during the season.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2024" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2024. <span>“Analysing Money’s Effect on Football Using
Multilevel Regression.”</span> October 9. <a href="https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/">https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/</a>.
</div></div></section></div> ]]></description>
  <category>Multilevel Regression</category>
  <category>Statistics</category>
  <category>Football Analytics</category>
  <category>R</category>
  <guid>https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/</guid>
  <pubDate>Wed, 09 Oct 2024 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2024-10-09-analysing-money-in-football/money.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Calculating a Football Team’s Strength of Schedule</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2024-04-02-calculating-strength-of-schedule-football/</link>
  <description><![CDATA[ 





<div class="cell">
<details class="code-fold">
<summary>Setup Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import packages</span></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">suppressPackageStartupMessages</span>({</span>
<span id="cb1-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(dplyr)</span>
<span id="cb1-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(gt)</span>
<span id="cb1-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ggplot2)</span>
<span id="cb1-6">})</span>
<span id="cb1-7"></span>
<span id="cb1-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># setup fonts</span></span>
<span id="cb1-9">sysfonts<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">font_add_google</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>)</span>
<span id="cb1-10">sysfonts<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">font_add_google</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>)</span>
<span id="cb1-11">showtext<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">showtext_auto</span>()</span>
<span id="cb1-12"></span>
<span id="cb1-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set plot theme</span></span>
<span id="cb1-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># inspired by https://github.com/z3tt/TidyTuesday/blob/main/R/2020_31_PalmerPenguins.Rmd</span></span>
<span id="cb1-15"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_set</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_update</span>(</span>
<span id="cb1-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.major =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb1-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.minor =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb1-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.title.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-20">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-21">    ),</span>
<span id="cb1-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.title.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-23">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">r =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-24">    ),</span>
<span id="cb1-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey50"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb1-26">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-27">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.15</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lineheight =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb1-28">      ),</span>
<span id="cb1-29">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb1-30">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb1-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks.length =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lines"</span>),</span>
<span id="cb1-32">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"top"</span>,</span>
<span id="cb1-33">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.title =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb1-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb1-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.title =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-36">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>,</span>
<span id="cb1-37">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-38">    ),</span>
<span id="cb1-39">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.subtitle =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-40">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>,</span>
<span id="cb1-41">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lineheight =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>),</span>
<span id="cb1-42">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb1-43">    ),</span>
<span id="cb1-44">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.title.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plot"</span>,</span>
<span id="cb1-45">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.caption =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-46">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey50"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb1-47">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb1-48">    ),</span>
<span id="cb1-49">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.caption.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plot"</span>,</span>
<span id="cb1-50">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb1-51">  )</span>
<span id="cb1-52"></span>
<span id="cb1-53"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set gt theme</span></span>
<span id="cb1-54">tbl_theme <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> </span>
<span id="cb1-55">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"num"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pct"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.round =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, ...) {</span>
<span id="cb1-56">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (type <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"num"</span>) {</span>
<span id="cb1-57">      data <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-58">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_align</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> is.numeric, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-59">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fmt_number</span>(</span>
<span id="cb1-60">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> is.numeric, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">decimals =</span> .round, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">drop_trailing_zeros =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb1-61">        ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb1-62">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_source_note</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source_note =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Source: FBref Via {worldfootballR}"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-63">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_options</span>(</span>
<span id="cb1-64">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.width =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pct</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>),</span>
<span id="cb1-65">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.font.names =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>,</span>
<span id="cb1-66">          ...</span>
<span id="cb1-67">        ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-68">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb1-69">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>),</span>
<span id="cb1-70">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_source_notes</span>(), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_footnotes</span>())</span>
<span id="cb1-71">        )</span>
<span id="cb1-72">    } <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (type <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pct"</span>) {</span>
<span id="cb1-73">      data <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-74">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_align</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> is.numeric, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-75">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fmt_percent</span>(</span>
<span id="cb1-76">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> is.numeric, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">decimals =</span> .round, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">drop_trailing_zeros =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb1-77">        ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb1-78">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_source_note</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source_note =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Source: FBref Via {worldfootballR}"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-79">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_options</span>(</span>
<span id="cb1-80">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.width =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pct</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>),</span>
<span id="cb1-81">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.font.names =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>,</span>
<span id="cb1-82">          ...</span>
<span id="cb1-83">        ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-84">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb1-85">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>),</span>
<span id="cb1-86">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_source_notes</span>(), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_footnotes</span>())</span>
<span id="cb1-87">        )</span>
<span id="cb1-88">    } <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> {</span>
<span id="cb1-89">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">stop</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"type must equal `num` or `pct`"</span>)</span>
<span id="cb1-90">    }</span>
<span id="cb1-91">  }</span></code></pre></div></div>
</details>
</div>
<p>American sports fans love numbers. Europeans are all vibes. Fighting and vibes. The American Soccer<sup>1</sup> Revolution of the late ’00s and early ’10s brought a sea of nerds armed with calculators, ready to formalise the sport with mathematical proofs. So came the birth of a new era of football, where we rid ourselves of the shackles of <em>Actually Watching Games</em> and studied the sport in its purest form, the spreadsheet.</p>
<p>Analytics has become a permanent fixture in football, with every club having teams of analysts to scout players and opponents and measure performance. Metrics like expected goals (xG) are increasingly common in football media coverage. America’s finest nerds have spent years devising ways to explain this silly little sport to the unwashed European masses, including leaning on existing concepts and ideas in American sports to build metrics that help explain football in valuable ways.</p>
<p>However, a standard metric that has remained relatively untouched is the strength of schedule (SOS). SOS measures the quality of the opponents a team has faced or will face to account for the difficulty of a team’s schedule when judging past performances or predicting future outcomes.</p>
<p>While SOS is less useful in European sports, where leagues are generally structured so that every team has an equal schedule, it can still be helpful when trying to say meaningful things about what has or will happen, both in domestic leagues and continental (and international) knockout tournaments.</p>
<p>I will develop a simple method for measuring SOS that can be easily implemented and interpreted. I hope my ideas become pervasive like the American Soccer Nerds all around us.</p>
<section id="sec-methodology" class="level2">
<h2 class="anchored" data-anchor-id="sec-methodology">A Simple Approach to Measuring Schedule Strength</h2>
<p>My goal with developing an SOS metric for football is to create something relatively simple but still does a solid job of capturing schedule difficulty. I’m sure there will be more precise ways to get at this, but I want to maximise the precision while maintaining simplicity in both implementation and interpretation. For something like this, a decent metric that is really easy to use is much better than a really accurate metric that is particularly complex for anyone looking to use or understand it.</p>
<p>The simplest approach to measuring schedule difficulty is to use the winning record of a team’s opponents to capture how well the team’s opponents have been doing in the league that season. For example, the <a href="https://en.wikipedia.org/wiki/Strength_of_schedule">Wikipedia entry</a> for Strength of Schedule lists the following formula:</p>
<p><img src="https://latex.codecogs.com/png.latex?SOS%20=%20%5Cfrac%7B2(OR)%20+%20(OOR)%7D%7B3%7D"> where OR is the opponents’ winning record, and OOR is the opponents’ opponents winning record. There are many variants to this, some more complex than others<sup>2</sup>, but the fundamental issue with this approach is that wins and losses are all counted equally. A win over some garbage team (for example, Portsmouth FC) means just the same as a way against a heavyweight (for instance, Southampton FC). I like the approach to capturing the inequality in the quality of the teams that a team’s opponents have played, but the issues with using winning records are insurmountable.</p>
<section id="sec-ratings-methodology" class="level3">
<h3 class="anchored" data-anchor-id="sec-ratings-methodology">Calculating Baseline Team Ratings</h3>
<p>Instead, measuring the difficulty of a team’s schedule should start with making at least a half-decent effort to quantify each opponent’s strength. I will calculate a relatively crude measure of baseline team ratings using non-penalty goal difference per 90 (npG/90) and non-penalty expected goal difference per 90 (npxGD/90)<sup>3</sup>.</p>
<p>I will take a weighted combination of npxGD/90 (70%) and npGD/90 (30%) because previous work suggests this is the optimal way to combine the two <span class="citation" data-cites="torvaney2021xg">(Torvaney 2021a)</span>.</p>
<details>
<summary>
Notation<sup>4</sup> (Click to Expand)
</summary>
<p><img src="https://latex.codecogs.com/png.latex?%20R_i%20=%20(0.7%20%5Ccdot%20%5Ctext%7BnpxG%7D_%7Bi_%7B%5Ctext%7B/90%7D%7D%7D)%20+%20(0.3%20%5Ccdot%20%5Ctext%7BnpG%7D_%7Bi_%7B%5Ctext%7B/90%7D%7D%7D)%0A"></p>
</details>
<p>This approach benefits from conceptual simplicity, making for a relatively straightforward interpretation.</p>
</section>
<section id="estimating-home-advantage" class="level3">
<h3 class="anchored" data-anchor-id="estimating-home-advantage">Estimating Home Advantage</h3>
<p>Rather than making wild assumptions about home advantage, I decided to do the responsible thing: measure the average home advantage across the big five leagues in recent seasons and use that number to weight home games.</p>
<p>I used the excellent <a href="https://jaseziv.github.io/worldfootballR"><strong>worldfootballR</strong></a> package to grab match results data in the big five leagues from 2017/18 to 2022/23 from <a href="https://FBref.com/">FBref</a> focusing on actual and expected goals (because penalties are relevant when measuring home advantage). I have also dropped any rows where attendance is NA, assuming that NAs represent empty stadiums, particularly during the COVID-19 pandemic.</p>
<div class="cell">
<details class="code-fold">
<summary>Data Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">home_and_away <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb2-2">  worldfootballR<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fb_match_results</span>(</span>
<span id="cb2-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">country =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ENG"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"FRA"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ESP"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GER"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ITA"</span>),</span>
<span id="cb2-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">season_end_year =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2018</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2023</span>,</span>
<span id="cb2-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">gender =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"M"</span></span>
<span id="cb2-6">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-7">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>(</span>
<span id="cb2-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xG"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xg"</span>)</span>
<span id="cb2-9">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb2-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">league =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">case_when</span>(</span>
<span id="cb2-12">      competition_name <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Fußball-Bundesliga"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bundesliga"</span>,</span>
<span id="cb2-13">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.default =</span> competition_name</span>
<span id="cb2-14">    )</span>
<span id="cb2-15">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(league, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ends_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_goals"</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ends_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_xg"</span>), attendance) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-17">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">drop_na</span>()</span></code></pre></div></div>
</details>
</div>
<p>Table&nbsp;1 shows the league average percentage difference in goals scored by home teams compared with away teams, and the average for the big five leagues is calculated, too.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">home_and_away <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-2">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">drop_na</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bind_rows</span>(</span>
<span id="cb3-4">    home_and_away <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-5">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(</span>
<span id="cb3-6">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ends_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_goals"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ends_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_xg"</span>), mean)</span>
<span id="cb3-7">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-8">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"league"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Big Five Leagues"</span>)</span>
<span id="cb3-9">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(</span>
<span id="cb3-11">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ends_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_goals"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ends_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_xg"</span>), mean),</span>
<span id="cb3-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(league)</span>
<span id="cb3-13">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb3-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">goal_diff =</span> (home_goals <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> away_goals) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> away_goals,</span>
<span id="cb3-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xg_diff =</span> (home_xg <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> away_xg) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> away_xg</span>
<span id="cb3-17">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(league, goal_diff, xg_diff) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(</span>
<span id="cb3-20">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"League"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"league"</span>,</span>
<span id="cb3-21">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goals"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"goal_diff"</span>,</span>
<span id="cb3-22">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Expected Goals"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xg_diff"</span></span>
<span id="cb3-23">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-24">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-25">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_spanner</span>(</span>
<span id="cb3-26">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Difference (Home vs Away)"</span>,</span>
<span id="cb3-27">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span></span>
<span id="cb3-28">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-29">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_footnote</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Excluding games played without fans in attendance."</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-30">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb3-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">weight =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bold"</span>)),</span>
<span id="cb3-32">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_body</span>(</span>
<span id="cb3-33">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">everything</span>(),</span>
<span id="cb3-34">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> League <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Big Five Leagues"</span></span>
<span id="cb3-35">    )</span>
<span id="cb3-36">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb3-37">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pct"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.round =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span></code></pre></div></div>
</details>
<div id="tbl-home-advantage" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-home-advantage-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Average Home Advantage in the Big Five Leagues 2017/18 - 2022/23
</figcaption>
<div aria-describedby="tbl-home-advantage-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="xhbnzyqtfl" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#xhbnzyqtfl table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#xhbnzyqtfl thead, #xhbnzyqtfl tbody, #xhbnzyqtfl tfoot, #xhbnzyqtfl tr, #xhbnzyqtfl td, #xhbnzyqtfl th {
  border-style: none;
}

#xhbnzyqtfl p {
  margin: 0;
  padding: 0;
}

#xhbnzyqtfl .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#xhbnzyqtfl .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#xhbnzyqtfl .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#xhbnzyqtfl .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#xhbnzyqtfl .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#xhbnzyqtfl .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#xhbnzyqtfl .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#xhbnzyqtfl .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#xhbnzyqtfl .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#xhbnzyqtfl .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#xhbnzyqtfl .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#xhbnzyqtfl .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#xhbnzyqtfl .gt_spanner_row {
  border-bottom-style: hidden;
}

#xhbnzyqtfl .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#xhbnzyqtfl .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#xhbnzyqtfl .gt_from_md > :first-child {
  margin-top: 0;
}

#xhbnzyqtfl .gt_from_md > :last-child {
  margin-bottom: 0;
}

#xhbnzyqtfl .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#xhbnzyqtfl .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#xhbnzyqtfl .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#xhbnzyqtfl .gt_row_group_first td {
  border-top-width: 2px;
}

#xhbnzyqtfl .gt_row_group_first th {
  border-top-width: 2px;
}

#xhbnzyqtfl .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#xhbnzyqtfl .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#xhbnzyqtfl .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#xhbnzyqtfl .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#xhbnzyqtfl .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#xhbnzyqtfl .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#xhbnzyqtfl .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#xhbnzyqtfl .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#xhbnzyqtfl .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#xhbnzyqtfl .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#xhbnzyqtfl .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#xhbnzyqtfl .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#xhbnzyqtfl .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#xhbnzyqtfl .gt_left {
  text-align: left;
}

#xhbnzyqtfl .gt_center {
  text-align: center;
}

#xhbnzyqtfl .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#xhbnzyqtfl .gt_font_normal {
  font-weight: normal;
}

#xhbnzyqtfl .gt_font_bold {
  font-weight: bold;
}

#xhbnzyqtfl .gt_font_italic {
  font-style: italic;
}

#xhbnzyqtfl .gt_super {
  font-size: 65%;
}

#xhbnzyqtfl .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#xhbnzyqtfl .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#xhbnzyqtfl .gt_indent_1 {
  text-indent: 5px;
}

#xhbnzyqtfl .gt_indent_2 {
  text-indent: 10px;
}

#xhbnzyqtfl .gt_indent_3 {
  text-indent: 15px;
}

#xhbnzyqtfl .gt_indent_4 {
  text-indent: 20px;
}

#xhbnzyqtfl .gt_indent_5 {
  text-indent: 25px;
}

#xhbnzyqtfl .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#xhbnzyqtfl div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>
<table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
  <thead>
    <tr class="gt_col_headings gt_spanner_row">
      <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="2" colspan="1" scope="col" id="League">League</th>
      <th class="gt_center gt_columns_top_border gt_column_spanner_outer" rowspan="1" colspan="2" scope="colgroup" id="Difference (Home vs Away)">
        <span class="gt_column_spanner">Difference (Home vs Away)</span>
      </th>
    </tr>
    <tr class="gt_col_headings">
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="Goals">Goals</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="Expected Goals">Expected Goals</th>
    </tr>
  </thead>
  <tbody class="gt_table_body">
    <tr><td headers="League" class="gt_row gt_left">Premier League</td>
<td headers="Goals" class="gt_row gt_center">26.6%</td>
<td headers="Expected Goals" class="gt_row gt_center">24.3%</td></tr>
    <tr><td headers="League" class="gt_row gt_left">La Liga</td>
<td headers="Goals" class="gt_row gt_center">35.1%</td>
<td headers="Expected Goals" class="gt_row gt_center">34.8%</td></tr>
    <tr><td headers="League" class="gt_row gt_left">Ligue 1</td>
<td headers="Goals" class="gt_row gt_center">28.7%</td>
<td headers="Expected Goals" class="gt_row gt_center">24.9%</td></tr>
    <tr><td headers="League" class="gt_row gt_left">Bundesliga</td>
<td headers="Goals" class="gt_row gt_center">30.2%</td>
<td headers="Expected Goals" class="gt_row gt_center">24.6%</td></tr>
    <tr><td headers="League" class="gt_row gt_left">Serie A</td>
<td headers="Goals" class="gt_row gt_center">17.8%</td>
<td headers="Expected Goals" class="gt_row gt_center">18.7%</td></tr>
    <tr><td headers="League" class="gt_row gt_left" style="font-weight: bold;">Big Five Leagues</td>
<td headers="Goals" class="gt_row gt_center" style="font-weight: bold;">27.4%</td>
<td headers="Expected Goals" class="gt_row gt_center" style="font-weight: bold;">25.3%</td></tr>
  </tbody>
  <tfoot class="gt_sourcenotes">
    <tr>
      <td class="gt_sourcenote" style="text-align: left;" colspan="3">Source: FBref Via {worldfootballR}</td>
    </tr>
  </tfoot>
  <tfoot class="gt_footnotes">
    <tr>
      <td class="gt_footnote" style="text-align: left;" colspan="3"> Excluding games played without fans in attendance.</td>
    </tr>
  </tfoot>
</table>
</div>
</div>
</div>
</figure>
</div>
</div>
<p>The variance in the percentage difference in both goals and expected goals in Table&nbsp;1 is pretty high, though that does appear to be driven by Serie A and La Liga being at the extreme ends. The Premier League, Bundesliga, and Ligue 1 variance is significantly lower. This is interesting, but I will avoid going down this specific rabbit hole right now because rabbit hole inception is a step too far.</p>
<p>I’m doing my duty as a Brexit-era Englishman focusing only on English leagues and pretending that football does not exist outside these fair shores. Taking the average across the big five leagues is acceptable for these purposes. Although the average is just above 25% for both goals and expected goals, I’m not going to be an insufferable bore<sup>5</sup>. I will treat the home advantage as 25% to keep things simple.</p>
<p>Team ratings will be weighted by home advantage by adding 25% of the team rating’s absolute value to the rating.</p>
<details>
<summary>
Notation (Click to Expand)
</summary>
<p><img src="https://latex.codecogs.com/png.latex?%0AR_%7Bij%7D%20=%20%5C%5C%0A%5Cbegin%7Bcases%7D%0A%20%20R_j%20+%20%7CR_j%7C%20%5Ccdot%20H%20&amp;%20%5Ctext%7Bif%20game%20is%20at%20opponent's%20home%7D%20%5C%5C%0A%20%20R_j%20&amp;%20%5Ctext%7Botherwise%7D%0A%5Cend%7Bcases%7D%0A"> where <img src="https://latex.codecogs.com/png.latex?R_%7Bij%7D"> is the opponent team’s rating, <img src="https://latex.codecogs.com/png.latex?R_j"> is their baseline rating (with <img src="https://latex.codecogs.com/png.latex?%7CR_j%7C"> representing the absolute value of the opponent’s baseline rating), and <img src="https://latex.codecogs.com/png.latex?H"> is the home advantage weighting.</p>
</details>
</section>
<section id="sec-sos-methodology" class="level3">
<h3 class="anchored" data-anchor-id="sec-sos-methodology">Putting it All Together</h3>
<p>We should now be able to assemble everything to create an SOS model.</p>
<p>The first step is to calculate the opponents’ ratings (OR) and the opponents’ opponents’ ratings (OOR)<sup>6</sup>. I will do this by first calculating the weighted team rating for each fixture, meaning that when a team plays away from home OR will be 25% higher and when they are at home, OOR is 25% higher. I will then take the mean value of OR and OOR. This second value is more involved, but it is conceptually the same as the mean value of OR.</p>
<details>
<summary>
Notation (Click to Expand)
</summary>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Chat%7BOR%7D_i%20=%20%5Cfrac%7B1%7D%7Bn%7D%20%5Csum_%7Bj=1%7D%5En%20%7B%20R_%7Bij%7D%5E%5Cprime%20%7D%20"> where <img src="https://latex.codecogs.com/png.latex?%5Chat%7BOR%7D_i"> is the mean average opponents’ ratings for team <img src="https://latex.codecogs.com/png.latex?i">, <img src="https://latex.codecogs.com/png.latex?n"> is the total number of opponents that team <img src="https://latex.codecogs.com/png.latex?i"> faces, and <img src="https://latex.codecogs.com/png.latex?R_%7Bij%7D%5E%5Cprime"> denotes the adjusted rating of opponent <img src="https://latex.codecogs.com/png.latex?j"> when playing against team <img src="https://latex.codecogs.com/png.latex?i">, accounting for the home advantage.</p>
<p>A similar process can also be carried out to calculate team <img src="https://latex.codecogs.com/png.latex?i">’s OOR (<img src="https://latex.codecogs.com/png.latex?OOR_i">). However, you have to calculate the ratings for each of team <img src="https://latex.codecogs.com/png.latex?i">’s opponents’ opponents, then take the mean average value for each opponent’s schedule, and then the mean average for all of team <img src="https://latex.codecogs.com/png.latex?i">’s opponents.</p>
<p><img src="https://latex.codecogs.com/png.latex?%20%20%7B%20%5Chat%7BOOR%7D_i%20=%20%5Cfrac%7B1%7D%7Bn%7D%20%5Csum_%7Bj=1%7D%5E%7Bn%7D%20%5Cleft(%20%5Cfrac%7B1%7D%7Bm_j%7D%20%5Csum_%7Bk=1%7D%5E%7Bm_j%7D%20R_%7Bjk%7D%5E%5Cprime%20%5Cright)%20%7D%20"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?%5Chat%7BOOR%7D_i"> represents the mean value of team <img src="https://latex.codecogs.com/png.latex?i">’s OOR, <img src="https://latex.codecogs.com/png.latex?n"> is the total opponents, <img src="https://latex.codecogs.com/png.latex?m_j"> is the total number of opponents for opponent <img src="https://latex.codecogs.com/png.latex?j"> of team <img src="https://latex.codecogs.com/png.latex?i">, and <img src="https://latex.codecogs.com/png.latex?R_%7Bjk%7D%5E%5Cprime"> is the rating of opponent <img src="https://latex.codecogs.com/png.latex?k"> when playing against opponent <img src="https://latex.codecogs.com/png.latex?j"> of team <img src="https://latex.codecogs.com/png.latex?i">.</p>
<p>The outer sum iterates over each opponent of team <img src="https://latex.codecogs.com/png.latex?i">, and for each opponent <img src="https://latex.codecogs.com/png.latex?j">, while the inner sum calculates the mean rating of their opponents (opponents of opponent <img src="https://latex.codecogs.com/png.latex?j">). Finally, the outer sum computes the mean value of these mean ratings over all opponents of team <img src="https://latex.codecogs.com/png.latex?i">.</p>
</details>
<p>The average value of a team’s OR and OOR play slightly different roles in the model. OR is the model’s primary parameter, and OOR provides additional context, allowing us to weight OR by the quality of the opponents’ opposition.</p>
<p>I will take a weighted average of OR (66.6%) and OOR (33.3%) and sum the two values.</p>
<details>
<summary>
Notation (Click to Expand)
</summary>
<p>Using the values <img src="https://latex.codecogs.com/png.latex?OR_i"> and <img src="https://latex.codecogs.com/png.latex?OOR_i">, we can calculate the strength of schedule for team <img src="https://latex.codecogs.com/png.latex?i"> by weighting the two ratings.</p>
<img src="https://latex.codecogs.com/png.latex?%20SOS_i%20=%20(%5Cfrac%7B2%7D%7B3%7D%20%5Ccdot%20OR_i)%20+%20(%5Cfrac%7B1%7D%7B3%7D%20%5Ccdot%20OOR_i)">
</details>
<p>While this approach yields a defensible SOS metric, the interpretability of the results may be limited. I have concerns about the practical significance of SOS values measured on the same scale as goals per 90. What does it mean for a team to have a one-goal-per-90 advantage in SOS? Are unit increases and decreases in SOS linear across the range of values? I think using the same scale as goals per 90 may lead to oversimplification and potential misinterpretation of SOS values<sup>7</sup>.</p>
<p>Instead, transforming SOS onto a standard scale, such as z-scores, offers a solution. Z-scores provide a standardised measure that facilitates precise comparative analysis across teams or seasons. This approach makes the results easier to interpret and allows for more meaningful comparisons within the league context.</p>
<p>SOS z-scores are calculated by taking the mean average and standard deviation of SOS for the entire league. For each unstandardised value of SOS, we subtract the mean and divide the result by the standard deviation.</p>
<details>
<summary>
Notation (Click to Expand)
</summary>
<p><img src="https://latex.codecogs.com/png.latex?%20SOS_i%5E%5Cprime%20=%20%5Cfrac%7BSOS_i%20-%20%5Cmu_%7BSOS%7D%7D%20%7B%5Csigma_%7BSOS%7D%7D%20"> where <img src="https://latex.codecogs.com/png.latex?SOS_i%5E%5Cprime"> is the standardised SOS z-score for team <img src="https://latex.codecogs.com/png.latex?i">, while <img src="https://latex.codecogs.com/png.latex?%5Cmu_%7BSOS%7D"> is the mean value of all SOS and <img src="https://latex.codecogs.com/png.latex?%5Csigma_%7BSOS%7D"> is the standard deviation of all SOS.</p>
</details>
<p>An SOS that equals zero is a league-average schedule; scores greater than zero are harder than the league average, and scores less than zero are easier than the league average. If a team’s SOS z-score is +1, their SOS is one standard deviation above the average SOS for all teams. Similarly, a z-score of -1 indicates that the SOS is one standard deviation below the average. Z-scores allow us to compare different teams’ SOS values on a standard scale, making it easier to interpret and analyse their relative strengths of schedule.</p>
</section>
</section>
<section id="premier-league-strength-of-schedule" class="level2">
<h2 class="anchored" data-anchor-id="premier-league-strength-of-schedule">Premier League Strength of Schedule</h2>
<p>The upside of Sunday’s dull 0-0 draw between Man City and Arsenal is that this was the ideal result for extending this incredible three-way title race in the Premier League. This is precisely the situation where a quantitative measure of the difficulty of each team’s schedule down the stretch would be valuable. Sounds like the perfect way to test this metric! I grabbed team-level goals and expected goals data and match results for the 2023/24 season in the Premier League from FBref via <strong>worldfootballR</strong>.</p>
<div class="cell">
<details class="code-fold">
<summary>Data Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">match_results_raw <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb4-2">  worldfootballR<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fb_match_results</span>(</span>
<span id="cb4-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">country =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ENG"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">gender =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"M"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">season_end_year =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2024</span></span>
<span id="cb4-4">  )</span>
<span id="cb4-5"></span>
<span id="cb4-6">team_stats_raw <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb4-7">  worldfootballR<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fb_season_team_stats</span>(</span>
<span id="cb4-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">country =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ENG"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">gender =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"M"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">season_end_year =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2024</span>,</span>
<span id="cb4-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stat_type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"standard"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tier =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1st"</span></span>
<span id="cb4-10">  )</span></code></pre></div></div>
</details>
</div>
<p>I have also turned all of this into an R package, <a href="https://paulj1989.github.io/fitba/"><strong>fitba</strong></a><sup>8</sup>. This should also make it easier for anyone to use this code and build on the method.</p>
<section id="remaining-schedule" class="level3">
<h3 class="anchored" data-anchor-id="remaining-schedule">Remaining Schedule</h3>
<p>The first step is to filter the match results data to only include the remaining games we want to work with. We can leverage that <strong>worldfootballR</strong>’s <code>fb_match_results()</code> function also includes future games with undetermined details about the match, like home and away goals, set to NA.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1">remaining_games <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb5-2">  match_results_raw <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-3">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb5-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(home_goals) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(away_goals)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb5-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">team =</span> home,</span>
<span id="cb5-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">opponent =</span> away,</span>
<span id="cb5-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">home_or_away =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Home"</span></span>
<span id="cb5-9">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bind_rows</span>(</span>
<span id="cb5-11">    match_results_raw <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-12">      janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb5-13">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(home_goals) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(away_goals)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-14">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb5-15">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">team =</span> away,</span>
<span id="cb5-16">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">opponent =</span> home,</span>
<span id="cb5-17">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">home_or_away =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Away"</span></span>
<span id="cb5-18">      )</span>
<span id="cb5-19">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(team, home_or_away, opponent)</span></code></pre></div></div>
</div>
<p>This creates a dataframe with every remaining fixture in the 2023/24 Premier League season repeated twice, with each team listed once in the <code>team</code> and <code>opponent</code> columns. Table&nbsp;2, below, shows a sample of the data.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">remaining_games <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb6-2">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">case =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb6-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">slice_sample</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb6-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb6-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"num"</span>)</span></code></pre></div></div>
</details>
<div id="tbl-schedule" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-schedule-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;2: Sample of Remaining Premier League Fixtures
</figcaption>
<div aria-describedby="tbl-schedule-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="nvcmjfvnke" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#nvcmjfvnke table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#nvcmjfvnke thead, #nvcmjfvnke tbody, #nvcmjfvnke tfoot, #nvcmjfvnke tr, #nvcmjfvnke td, #nvcmjfvnke th {
  border-style: none;
}

#nvcmjfvnke p {
  margin: 0;
  padding: 0;
}

#nvcmjfvnke .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#nvcmjfvnke .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#nvcmjfvnke .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#nvcmjfvnke .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#nvcmjfvnke .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#nvcmjfvnke .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#nvcmjfvnke .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#nvcmjfvnke .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#nvcmjfvnke .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#nvcmjfvnke .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#nvcmjfvnke .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#nvcmjfvnke .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#nvcmjfvnke .gt_spanner_row {
  border-bottom-style: hidden;
}

#nvcmjfvnke .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#nvcmjfvnke .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#nvcmjfvnke .gt_from_md > :first-child {
  margin-top: 0;
}

#nvcmjfvnke .gt_from_md > :last-child {
  margin-bottom: 0;
}

#nvcmjfvnke .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#nvcmjfvnke .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#nvcmjfvnke .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#nvcmjfvnke .gt_row_group_first td {
  border-top-width: 2px;
}

#nvcmjfvnke .gt_row_group_first th {
  border-top-width: 2px;
}

#nvcmjfvnke .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#nvcmjfvnke .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#nvcmjfvnke .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#nvcmjfvnke .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#nvcmjfvnke .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#nvcmjfvnke .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#nvcmjfvnke .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#nvcmjfvnke .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#nvcmjfvnke .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#nvcmjfvnke .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#nvcmjfvnke .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#nvcmjfvnke .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#nvcmjfvnke .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#nvcmjfvnke .gt_left {
  text-align: left;
}

#nvcmjfvnke .gt_center {
  text-align: center;
}

#nvcmjfvnke .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#nvcmjfvnke .gt_font_normal {
  font-weight: normal;
}

#nvcmjfvnke .gt_font_bold {
  font-weight: bold;
}

#nvcmjfvnke .gt_font_italic {
  font-style: italic;
}

#nvcmjfvnke .gt_super {
  font-size: 65%;
}

#nvcmjfvnke .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#nvcmjfvnke .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#nvcmjfvnke .gt_indent_1 {
  text-indent: 5px;
}

#nvcmjfvnke .gt_indent_2 {
  text-indent: 10px;
}

#nvcmjfvnke .gt_indent_3 {
  text-indent: 15px;
}

#nvcmjfvnke .gt_indent_4 {
  text-indent: 20px;
}

#nvcmjfvnke .gt_indent_5 {
  text-indent: 25px;
}

#nvcmjfvnke .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#nvcmjfvnke div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="Team" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Team</th>
<th id="Home or Away" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Home or Away</th>
<th id="Opponent" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Opponent</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Manchester Utd</td>
<td class="gt_row gt_left" headers="Home or Away">Home</td>
<td class="gt_row gt_left" headers="Opponent">Liverpool</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Bournemouth</td>
<td class="gt_row gt_left" headers="Home or Away">Home</td>
<td class="gt_row gt_left" headers="Opponent">Crystal Palace</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Manchester City</td>
<td class="gt_row gt_left" headers="Home or Away">Away</td>
<td class="gt_row gt_left" headers="Opponent">Tottenham</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Brentford</td>
<td class="gt_row gt_left" headers="Home or Away">Away</td>
<td class="gt_row gt_left" headers="Opponent">Aston Villa</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Crystal Palace</td>
<td class="gt_row gt_left" headers="Home or Away">Home</td>
<td class="gt_row gt_left" headers="Opponent">Newcastle Utd</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Everton</td>
<td class="gt_row gt_left" headers="Home or Away">Home</td>
<td class="gt_row gt_left" headers="Opponent">Nott'ham Forest</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Manchester City</td>
<td class="gt_row gt_left" headers="Home or Away">Away</td>
<td class="gt_row gt_left" headers="Opponent">Brighton</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Luton Town</td>
<td class="gt_row gt_left" headers="Home or Away">Home</td>
<td class="gt_row gt_left" headers="Opponent">Fulham</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Nott'ham Forest</td>
<td class="gt_row gt_left" headers="Home or Away">Home</td>
<td class="gt_row gt_left" headers="Opponent">Manchester City</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Liverpool</td>
<td class="gt_row gt_left" headers="Home or Away">Home</td>
<td class="gt_row gt_left" headers="Opponent">Tottenham</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="3" class="gt_sourcenote" style="text-align: left;">Source: FBref Via {worldfootballR}</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>To me, this seems like the obvious way to structure the data, but it’s important to remember that I am an idiot, so there may well be a better way.</p>
</section>
<section id="sec-team-ratings" class="level3">
<h3 class="anchored" data-anchor-id="sec-team-ratings">Baseline Team Ratings</h3>
<p>The next step is to create the baseline ratings for each Premier League team using their npxGD/90 and npGD/90. As discussed in Section&nbsp;1, calculating the team ratings is very simple. They are just a weighted average of npxGD/90 (70%) and npGD/90 (30%).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1">ratings <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb7-2">  team_stats_raw <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-3">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>(</span>
<span id="cb7-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb7-5">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Squad"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"team"</span>,</span>
<span id="cb7-6">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Expected"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>,</span>
<span id="cb7-7">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"G_minus_PK"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"npg"</span>,</span>
<span id="cb7-8">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"npxG"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"npxg"</span>,</span>
<span id="cb7-9">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Per_Minutes"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"90"</span></span>
<span id="cb7-10">    )</span>
<span id="cb7-11">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(team, team_or_opponent, npxg90, npg90) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">team =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_remove</span>(team, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vs "</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-14">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_wider</span>(</span>
<span id="cb7-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_from =</span> team_or_opponent,</span>
<span id="cb7-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_from =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(npg90, npxg90),</span>
<span id="cb7-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_glue =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"{team_or_opponent}_{.value}"</span></span>
<span id="cb7-18">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(</span>
<span id="cb7-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">npxgd90 =</span> team_npxg90 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> opponent_npxg90,</span>
<span id="cb7-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">npgd90 =</span> team_npg90 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> opponent_npg90,</span>
<span id="cb7-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rating =</span> (npxgd90 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (npgd90 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>),</span>
<span id="cb7-23">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> team</span>
<span id="cb7-24">  )</span></code></pre></div></div>
</div>
<p>The ratings in Table&nbsp;3 show each Premier League team’s npxGD/90, npGD/90, and baseline ratings, arranged from highest to lowest.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1">ratings <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb8-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">desc</span>(rating)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb8-3">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">case =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb8-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(</span>
<span id="cb8-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"npxGD/90"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> Npxgd90,</span>
<span id="cb8-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"npGD/90"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> Npgd90</span>
<span id="cb8-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb8-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb8-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"num"</span>)</span></code></pre></div></div>
</details>
<div id="tbl-team-ratings" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-team-ratings-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;3: Baseline Team Ratings in the Premier League
</figcaption>
<div aria-describedby="tbl-team-ratings-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="ugkpdbjxgn" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#ugkpdbjxgn table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#ugkpdbjxgn thead, #ugkpdbjxgn tbody, #ugkpdbjxgn tfoot, #ugkpdbjxgn tr, #ugkpdbjxgn td, #ugkpdbjxgn th {
  border-style: none;
}

#ugkpdbjxgn p {
  margin: 0;
  padding: 0;
}

#ugkpdbjxgn .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#ugkpdbjxgn .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#ugkpdbjxgn .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#ugkpdbjxgn .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#ugkpdbjxgn .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#ugkpdbjxgn .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#ugkpdbjxgn .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#ugkpdbjxgn .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#ugkpdbjxgn .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#ugkpdbjxgn .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#ugkpdbjxgn .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#ugkpdbjxgn .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#ugkpdbjxgn .gt_spanner_row {
  border-bottom-style: hidden;
}

#ugkpdbjxgn .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#ugkpdbjxgn .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#ugkpdbjxgn .gt_from_md > :first-child {
  margin-top: 0;
}

#ugkpdbjxgn .gt_from_md > :last-child {
  margin-bottom: 0;
}

#ugkpdbjxgn .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#ugkpdbjxgn .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#ugkpdbjxgn .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#ugkpdbjxgn .gt_row_group_first td {
  border-top-width: 2px;
}

#ugkpdbjxgn .gt_row_group_first th {
  border-top-width: 2px;
}

#ugkpdbjxgn .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#ugkpdbjxgn .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#ugkpdbjxgn .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#ugkpdbjxgn .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#ugkpdbjxgn .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#ugkpdbjxgn .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#ugkpdbjxgn .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#ugkpdbjxgn .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#ugkpdbjxgn .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#ugkpdbjxgn .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#ugkpdbjxgn .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#ugkpdbjxgn .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#ugkpdbjxgn .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#ugkpdbjxgn .gt_left {
  text-align: left;
}

#ugkpdbjxgn .gt_center {
  text-align: center;
}

#ugkpdbjxgn .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#ugkpdbjxgn .gt_font_normal {
  font-weight: normal;
}

#ugkpdbjxgn .gt_font_bold {
  font-weight: bold;
}

#ugkpdbjxgn .gt_font_italic {
  font-style: italic;
}

#ugkpdbjxgn .gt_super {
  font-size: 65%;
}

#ugkpdbjxgn .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#ugkpdbjxgn .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#ugkpdbjxgn .gt_indent_1 {
  text-indent: 5px;
}

#ugkpdbjxgn .gt_indent_2 {
  text-indent: 10px;
}

#ugkpdbjxgn .gt_indent_3 {
  text-indent: 15px;
}

#ugkpdbjxgn .gt_indent_4 {
  text-indent: 20px;
}

#ugkpdbjxgn .gt_indent_5 {
  text-indent: 25px;
}

#ugkpdbjxgn .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#ugkpdbjxgn div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="Team" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Team</th>
<th id="npxGD/90" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">npxGD/90</th>
<th id="npGD/90" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">npGD/90</th>
<th id="Rating" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Rating</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Arsenal</td>
<td class="gt_row gt_center" headers="npxGD/90">1.12</td>
<td class="gt_row gt_center" headers="npGD/90">1.27</td>
<td class="gt_row gt_center" headers="Rating">1.17</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Manchester City</td>
<td class="gt_row gt_center" headers="npxGD/90">0.97</td>
<td class="gt_row gt_center" headers="npGD/90">1.17</td>
<td class="gt_row gt_center" headers="Rating">1.03</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Liverpool</td>
<td class="gt_row gt_center" headers="npxGD/90">0.85</td>
<td class="gt_row gt_center" headers="npGD/90">1.14</td>
<td class="gt_row gt_center" headers="Rating">0.94</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Tottenham</td>
<td class="gt_row gt_center" headers="npxGD/90">0.3</td>
<td class="gt_row gt_center" headers="npGD/90">0.72</td>
<td class="gt_row gt_center" headers="Rating">0.43</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Aston Villa</td>
<td class="gt_row gt_center" headers="npxGD/90">0.21</td>
<td class="gt_row gt_center" headers="npGD/90">0.53</td>
<td class="gt_row gt_center" headers="Rating">0.31</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Chelsea</td>
<td class="gt_row gt_center" headers="npxGD/90">0.34</td>
<td class="gt_row gt_center" headers="npGD/90">−0.11</td>
<td class="gt_row gt_center" headers="Rating">0.2</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Brighton</td>
<td class="gt_row gt_center" headers="npxGD/90">0.17</td>
<td class="gt_row gt_center" headers="npGD/90">0.11</td>
<td class="gt_row gt_center" headers="Rating">0.15</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Everton</td>
<td class="gt_row gt_center" headers="npxGD/90">0.23</td>
<td class="gt_row gt_center" headers="npGD/90">−0.04</td>
<td class="gt_row gt_center" headers="Rating">0.15</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Newcastle Utd</td>
<td class="gt_row gt_center" headers="npxGD/90">0.08</td>
<td class="gt_row gt_center" headers="npGD/90">0.28</td>
<td class="gt_row gt_center" headers="Rating">0.14</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Bournemouth</td>
<td class="gt_row gt_center" headers="npxGD/90">0.02</td>
<td class="gt_row gt_center" headers="npGD/90">−0.25</td>
<td class="gt_row gt_center" headers="Rating">−0.06</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Brentford</td>
<td class="gt_row gt_center" headers="npxGD/90">0.07</td>
<td class="gt_row gt_center" headers="npGD/90">−0.5</td>
<td class="gt_row gt_center" headers="Rating">−0.1</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Fulham</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.27</td>
<td class="gt_row gt_center" headers="npGD/90">0.2</td>
<td class="gt_row gt_center" headers="Rating">−0.13</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Manchester Utd</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.29</td>
<td class="gt_row gt_center" headers="npGD/90">0</td>
<td class="gt_row gt_center" headers="Rating">−0.2</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">West Ham</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.29</td>
<td class="gt_row gt_center" headers="npGD/90">0</td>
<td class="gt_row gt_center" headers="Rating">−0.2</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Nott'ham Forest</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.14</td>
<td class="gt_row gt_center" headers="npGD/90">−0.43</td>
<td class="gt_row gt_center" headers="Rating">−0.23</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Wolves</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.28</td>
<td class="gt_row gt_center" headers="npGD/90">−0.14</td>
<td class="gt_row gt_center" headers="Rating">−0.24</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Crystal Palace</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.26</td>
<td class="gt_row gt_center" headers="npGD/90">−0.52</td>
<td class="gt_row gt_center" headers="Rating">−0.34</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Burnley</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.72</td>
<td class="gt_row gt_center" headers="npGD/90">−0.97</td>
<td class="gt_row gt_center" headers="Rating">−0.79</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Luton Town</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.95</td>
<td class="gt_row gt_center" headers="npGD/90">−0.73</td>
<td class="gt_row gt_center" headers="Rating">−0.88</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Sheffield Utd</td>
<td class="gt_row gt_center" headers="npxGD/90">−1.05</td>
<td class="gt_row gt_center" headers="npGD/90">−1.69</td>
<td class="gt_row gt_center" headers="Rating">−1.24</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="4" class="gt_sourcenote" style="text-align: left;">Source: FBref Via {worldfootballR}</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>According to Table&nbsp;3, Arsenal are the best team in the league, which seems about right, followed by Manchester City and Liverpool, and then a giant chasm before we reach the rest of the league (which is topped by Tottenham). I am not compelled to argue with these ratings, but if you’re a Manchester United fan who doesn’t have the capacity for shame, you might?</p>
<p>We then have to calculate the mean rating for a team’s OR and OOR from these baseline ratings. The process for calculating each of these is similar. However, the home advantage weighting is reversed for the OOR, and a little extra work is required to get the opponents that a team’s opponents will face.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1">opponent_ratings <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb9-2">  remaining_games <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">left_join</span>(ratings, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">join_by</span>(opponent <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> team)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb9-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rating =</span></span>
<span id="cb9-6">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">if_else</span>(home_or_away <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Away"</span>, rating <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abs</span>(rating) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>), rating)</span>
<span id="cb9-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">opponent_rating =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(rating), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> team)</span>
<span id="cb9-9"></span>
<span id="cb9-10">opponent_opponent_ratings <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb9-11">  remaining_games <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">left_join</span>(ratings, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">join_by</span>(team)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb9-14">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rating =</span></span>
<span id="cb9-15">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">if_else</span>(home_or_away <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Home"</span>, rating <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abs</span>(rating) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>), rating)</span>
<span id="cb9-16">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-17">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rating =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(rating), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> opponent) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">full_join</span>(remaining_games) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">opponent_opponent_rating =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(rating), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> team)</span></code></pre></div></div>
</div>
<p>Table&nbsp;4 shows the two sets of ratings joined by their corresponding team, which hopefully helps make sense of what is happening here. This part of the process is a little confusing because the steps are kind of stacked on top of each other. Fingers crossed, this makes it easier to follow.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1">remaining_games <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">distinct</span>(team) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(team) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb10-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">left_join</span>(opponent_ratings, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">join_by</span>(team)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">left_join</span>(opponent_opponent_ratings, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">join_by</span>(team)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb10-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(</span>
<span id="cb10-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Team"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> team,</span>
<span id="cb10-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Opponents' Rating"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> opponent_rating,</span>
<span id="cb10-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Opponents' Oppponents Rating"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> opponent_opponent_rating,</span>
<span id="cb10-10">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb10-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb10-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"num"</span>)</span></code></pre></div></div>
</details>
<div id="tbl-opponent-ratings" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-opponent-ratings-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;4: Team Opponents’ &amp; Opponents’ Oppponents Ratings
</figcaption>
<div aria-describedby="tbl-opponent-ratings-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="jdcmppfnio" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#jdcmppfnio table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#jdcmppfnio thead, #jdcmppfnio tbody, #jdcmppfnio tfoot, #jdcmppfnio tr, #jdcmppfnio td, #jdcmppfnio th {
  border-style: none;
}

#jdcmppfnio p {
  margin: 0;
  padding: 0;
}

#jdcmppfnio .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#jdcmppfnio .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#jdcmppfnio .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#jdcmppfnio .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#jdcmppfnio .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#jdcmppfnio .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#jdcmppfnio .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#jdcmppfnio .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#jdcmppfnio .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#jdcmppfnio .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#jdcmppfnio .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#jdcmppfnio .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#jdcmppfnio .gt_spanner_row {
  border-bottom-style: hidden;
}

#jdcmppfnio .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#jdcmppfnio .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#jdcmppfnio .gt_from_md > :first-child {
  margin-top: 0;
}

#jdcmppfnio .gt_from_md > :last-child {
  margin-bottom: 0;
}

#jdcmppfnio .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#jdcmppfnio .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#jdcmppfnio .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#jdcmppfnio .gt_row_group_first td {
  border-top-width: 2px;
}

#jdcmppfnio .gt_row_group_first th {
  border-top-width: 2px;
}

#jdcmppfnio .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#jdcmppfnio .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#jdcmppfnio .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#jdcmppfnio .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#jdcmppfnio .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#jdcmppfnio .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#jdcmppfnio .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#jdcmppfnio .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#jdcmppfnio .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#jdcmppfnio .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#jdcmppfnio .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#jdcmppfnio .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#jdcmppfnio .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#jdcmppfnio .gt_left {
  text-align: left;
}

#jdcmppfnio .gt_center {
  text-align: center;
}

#jdcmppfnio .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#jdcmppfnio .gt_font_normal {
  font-weight: normal;
}

#jdcmppfnio .gt_font_bold {
  font-weight: bold;
}

#jdcmppfnio .gt_font_italic {
  font-style: italic;
}

#jdcmppfnio .gt_super {
  font-size: 65%;
}

#jdcmppfnio .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#jdcmppfnio .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#jdcmppfnio .gt_indent_1 {
  text-indent: 5px;
}

#jdcmppfnio .gt_indent_2 {
  text-indent: 10px;
}

#jdcmppfnio .gt_indent_3 {
  text-indent: 15px;
}

#jdcmppfnio .gt_indent_4 {
  text-indent: 20px;
}

#jdcmppfnio .gt_indent_5 {
  text-indent: 25px;
}

#jdcmppfnio .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#jdcmppfnio div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="Team" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Team</th>
<th id="Opponents' Rating" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Opponents' Rating</th>
<th id="Opponents' Oppponents Rating" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Opponents' Oppponents Rating</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Arsenal</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.01</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.17</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Aston Villa</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.46</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.03</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Bournemouth</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.08</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.15</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Brentford</td>
<td class="gt_row gt_center" headers="Opponents' Rating">−0.15</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.13</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Brighton</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.22</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.02</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Burnley</td>
<td class="gt_row gt_center" headers="Opponents' Rating">−0.07</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.06</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Chelsea</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.1</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.13</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Crystal Palace</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.21</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.07</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Everton</td>
<td class="gt_row gt_center" headers="Opponents' Rating">−0.02</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Fulham</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.09</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.02</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Liverpool</td>
<td class="gt_row gt_center" headers="Opponents' Rating">−0.14</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.16</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Luton Town</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.28</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.03</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Manchester City</td>
<td class="gt_row gt_center" headers="Opponents' Rating">−0.09</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.2</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Manchester Utd</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.04</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.04</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Newcastle Utd</td>
<td class="gt_row gt_center" headers="Opponents' Rating">−0.19</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.07</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Nott'ham Forest</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.01</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.06</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Sheffield Utd</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.1</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">−0.03</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Tottenham</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.19</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">−0.01</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">West Ham</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.18</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.1</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Wolves</td>
<td class="gt_row gt_center" headers="Opponents' Rating">0.15</td>
<td class="gt_row gt_center" headers="Opponents' Oppponents Rating">0.05</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="3" class="gt_sourcenote" style="text-align: left;">Source: FBref Via {worldfootballR}</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
</section>
<section id="strength-of-schedule" class="level3">
<h3 class="anchored" data-anchor-id="strength-of-schedule">Strength of Schedule</h3>
<p>Having created all the components needed, we must piece it together like a dullard’s jigsaw puzzle.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1">strength_of_schedule <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb11-2">  remaining_games <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">distinct</span>(team) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">left_join</span>(opponent_ratings, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">join_by</span>(team)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">left_join</span>(opponent_opponent_ratings, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">join_by</span>(team)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb11-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">unstandardized =</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> opponent_rating) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> opponent_opponent_rating),</span>
<span id="cb11-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sos =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale</span>(unstandardized)</span>
<span id="cb11-9">  )</span></code></pre></div></div>
</div>
<p>We can start by looking at the Premier League title race, comparing Arsenal, Manchester City, and Liverpool’s schedules. Table&nbsp;5 shows the results.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">strength_of_schedule <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(team, sos) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb12-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(team <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Arsenal"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Manchester City"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Liverpool"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb12-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(sos) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb12-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(</span>
<span id="cb12-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Team"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> team,</span>
<span id="cb12-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Strength of Schedule (Z-Score)"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> sos</span>
<span id="cb12-8">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb12-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb12-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_footnote</span>(</span>
<span id="cb12-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">footnote =</span> </span>
<span id="cb12-12">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"z &lt; 0 = Easier than league average; z &gt; 0 = Harder than league average"</span></span>
<span id="cb12-13">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb12-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"num"</span>)</span></code></pre></div></div>
</details>
<div id="tbl-strength-of-schedule" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-strength-of-schedule-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;5: Premier League Title Race’s Strength of Schedule
</figcaption>
<div aria-describedby="tbl-strength-of-schedule-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="yadeaxhmob" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#yadeaxhmob table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#yadeaxhmob thead, #yadeaxhmob tbody, #yadeaxhmob tfoot, #yadeaxhmob tr, #yadeaxhmob td, #yadeaxhmob th {
  border-style: none;
}

#yadeaxhmob p {
  margin: 0;
  padding: 0;
}

#yadeaxhmob .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#yadeaxhmob .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#yadeaxhmob .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#yadeaxhmob .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#yadeaxhmob .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#yadeaxhmob .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#yadeaxhmob .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#yadeaxhmob .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#yadeaxhmob .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#yadeaxhmob .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#yadeaxhmob .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#yadeaxhmob .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#yadeaxhmob .gt_spanner_row {
  border-bottom-style: hidden;
}

#yadeaxhmob .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#yadeaxhmob .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#yadeaxhmob .gt_from_md > :first-child {
  margin-top: 0;
}

#yadeaxhmob .gt_from_md > :last-child {
  margin-bottom: 0;
}

#yadeaxhmob .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#yadeaxhmob .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#yadeaxhmob .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#yadeaxhmob .gt_row_group_first td {
  border-top-width: 2px;
}

#yadeaxhmob .gt_row_group_first th {
  border-top-width: 2px;
}

#yadeaxhmob .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#yadeaxhmob .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#yadeaxhmob .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#yadeaxhmob .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#yadeaxhmob .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#yadeaxhmob .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#yadeaxhmob .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#yadeaxhmob .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#yadeaxhmob .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#yadeaxhmob .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#yadeaxhmob .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#yadeaxhmob .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#yadeaxhmob .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#yadeaxhmob .gt_left {
  text-align: left;
}

#yadeaxhmob .gt_center {
  text-align: center;
}

#yadeaxhmob .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#yadeaxhmob .gt_font_normal {
  font-weight: normal;
}

#yadeaxhmob .gt_font_bold {
  font-weight: bold;
}

#yadeaxhmob .gt_font_italic {
  font-style: italic;
}

#yadeaxhmob .gt_super {
  font-size: 65%;
}

#yadeaxhmob .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#yadeaxhmob .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#yadeaxhmob .gt_indent_1 {
  text-indent: 5px;
}

#yadeaxhmob .gt_indent_2 {
  text-indent: 10px;
}

#yadeaxhmob .gt_indent_3 {
  text-indent: 15px;
}

#yadeaxhmob .gt_indent_4 {
  text-indent: 20px;
}

#yadeaxhmob .gt_indent_5 {
  text-indent: 25px;
}

#yadeaxhmob .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#yadeaxhmob div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>
<table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
  <thead>
    <tr class="gt_col_headings">
      <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Team">Team</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="Strength of Schedule (Z-Score)">Strength of Schedule (Z-Score)</th>
    </tr>
  </thead>
  <tbody class="gt_table_body">
    <tr><td headers="Team" class="gt_row gt_left">Liverpool</td>
<td headers="Strength of Schedule (Z-Score)" class="gt_row gt_center">−1.12</td></tr>
    <tr><td headers="Team" class="gt_row gt_left">Manchester City</td>
<td headers="Strength of Schedule (Z-Score)" class="gt_row gt_center">−0.67</td></tr>
    <tr><td headers="Team" class="gt_row gt_left">Arsenal</td>
<td headers="Strength of Schedule (Z-Score)" class="gt_row gt_center">−0.09</td></tr>
  </tbody>
  <tfoot class="gt_sourcenotes">
    <tr>
      <td class="gt_sourcenote" style="text-align: left;" colspan="2">Source: FBref Via {worldfootballR}</td>
    </tr>
  </tfoot>
  <tfoot class="gt_footnotes">
    <tr>
      <td class="gt_footnote" style="text-align: left;" colspan="2"> z &lt; 0 = Easier than league average; z &gt; 0 = Harder than league average</td>
    </tr>
  </tfoot>
</table>
</div>
</div>
</div>
</figure>
</div>
</div>
<p>As discussed in Section&nbsp;1.3, z-scores are a measure of standard deviation from the mean. A z-score of -1.12 means that Liverpool’s schedule is 1.12 standard deviations lower than the mean league schedule.</p>
<p>All three teams’ schedules are easier than the league average, which is unsurprising because they have played each other, and many teams still have to play them. However, there is plenty of variance in schedule strength between the three title contenders. Arsenal’s schedule is very close to the league average, while Liverpool’s remaining schedule is one of the easiest in the Premier League.</p>
<p>Finally, we can plot the Strength of Schedule Z-Scores for all Premier League teams’ remaining games this season. The plot below orders teams by SOS, from the hardest schedules to the easiest.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1">strength_of_schedule <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">team =</span> forcats<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct_reorder</span>(team, sos)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb13-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> team, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> sos, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> sos <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_col</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_hline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">yintercept =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_text</span>(</span>
<span id="cb13-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(</span>
<span id="cb13-8">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(sos, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>),</span>
<span id="cb13-9">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">between</span>(sos, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>),</span>
<span id="cb13-10">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">case_when</span>(</span>
<span id="cb13-11">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">between</span>(sos, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>,</span>
<span id="cb13-12">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">between</span>(sos, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>,</span>
<span id="cb13-13">        sos <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>,</span>
<span id="cb13-14">        sos <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span></span>
<span id="cb13-15">        )</span>
<span id="cb13-16">      ),</span>
<span id="cb13-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fontface =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bold"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span></span>
<span id="cb13-18">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coord_flip</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_fill_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#D93649"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">guide =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"none"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_colour_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">guide =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"none"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-22">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb13-23">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Premier League Teams' Strength of Schedule for Remaining Games"</span>,</span>
<span id="cb13-24">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span></span>
<span id="cb13-25">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb13-26">        glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb13-27">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Remaining schedule difficulty in the Premier League, represented as "</span>,</span>
<span id="cb13-28">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z-Scores. Scores above zero are harder than league average, below "</span>,</span>
<span id="cb13-29">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"easier. Z-Scores are the standard deviation distance from the mean "</span>,</span>
<span id="cb13-30">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"(i.e, scores of +1 (or -1) are 1 SD above (or below) mean)."</span></span>
<span id="cb13-31">          ),</span>
<span id="cb13-32">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb13-33">        ),</span>
<span id="cb13-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Strength of Schedule (Z-Score)"</span>,</span>
<span id="cb13-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson  |  Data: FBref Via {worldfootballR}"</span></span>
<span id="cb13-36">    )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-04-02-calculating-strength-of-schedule-football/index_files/figure-html/sos-plot-1.png" class="img-fluid figure-img" alt="A barplot visualising the strength of remaining schedules for every team in the Premier League. Positive scores indicate harder than league average schedules, and negative scores indicate easier than league average scores. The hardest remaining schedules are Aston Villa (2.42), Luton (1.27), and Crystal Palace (0.91), while the easiest schedules are Newcastle (-1.76), Brentford (-1.32), and Liverpool (-1.12). " width="672"></p>
</figure>
</div>
</div>
</div>
<p>Aston Villa and Luton have much left to play for, so this is not great news for either side. Meanwhile, Newcastle doesn’t have to face any of the top three but still have to play Sheffield United and Burnley. Their schedule includes only three teams ranked in the top ten in the baseline team ratings, two of which they will face at St James’ Park. Awful slackers.</p>
</section>
</section>
<section id="sec-champ" class="level2">
<h2 class="anchored" data-anchor-id="sec-champ">Championship Strength of Schedule</h2>
<p>We can take another look at this SOS model and how the <strong>fitba</strong> package I’ve put together works, using the race for automatic promotion in the Championship. As a Southampton fan, I am presenting this as a four-way race that includes Saints, despite their loss to Ipswich on Monday. This choice might seem a little unrealistic. However, I spent four years in a PhD program, so I’m excellent at convincing myself that everything is going great despite the crushing weight of evidence suggesting otherwise.</p>
<div class="cell">
<details class="code-fold">
<summary>Data &amp; Model Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1">champ_games <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb14-2">  worldfootballR<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fb_match_results</span>(</span>
<span id="cb14-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">country =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ENG"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">gender =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"M"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">season_end_year =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2024</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tier =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2nd"</span></span>
<span id="cb14-4">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb14-5">  fitba<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_fixtures</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">remaining =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb14-6"></span>
<span id="cb14-7">champ_ratings <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb14-8">  worldfootballR<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fb_season_team_stats</span>(</span>
<span id="cb14-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">country =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ENG"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">gender =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"M"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">season_end_year =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2024</span>,</span>
<span id="cb14-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stat_type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"standard"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tier =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2nd"</span></span>
<span id="cb14-11">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb14-12">  fitba<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">calculate_team_ratings</span>()</span>
<span id="cb14-13"></span>
<span id="cb14-14">champ_sos <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> champ_ratings <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> fitba<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">calculate_sos</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">schedule =</span> champ_games)</span></code></pre></div></div>
</details>
</div>
<p>Thanks to the silly little package I put together, significantly less code is required to put all this together.</p>
<p>Table&nbsp;6 shows the Championship ratings for the 2023/24 season, highlighting how absurd the top four teams have been<sup>9</sup>.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1">champ_ratings <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb15-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">desc</span>(rating)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb15-3">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">case =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"title"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb15-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(</span>
<span id="cb15-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"npxGD/90"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> Npxgd90,</span>
<span id="cb15-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"npGD/90"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> Npgd90</span>
<span id="cb15-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb15-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb15-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"num"</span>)</span></code></pre></div></div>
</details>
<div id="tbl-champ-ratings" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-champ-ratings-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;6: Baseline Team Ratings in the Championship
</figcaption>
<div aria-describedby="tbl-champ-ratings-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="uxnawvkmix" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#uxnawvkmix table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#uxnawvkmix thead, #uxnawvkmix tbody, #uxnawvkmix tfoot, #uxnawvkmix tr, #uxnawvkmix td, #uxnawvkmix th {
  border-style: none;
}

#uxnawvkmix p {
  margin: 0;
  padding: 0;
}

#uxnawvkmix .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#uxnawvkmix .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#uxnawvkmix .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#uxnawvkmix .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#uxnawvkmix .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#uxnawvkmix .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#uxnawvkmix .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#uxnawvkmix .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#uxnawvkmix .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#uxnawvkmix .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#uxnawvkmix .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#uxnawvkmix .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#uxnawvkmix .gt_spanner_row {
  border-bottom-style: hidden;
}

#uxnawvkmix .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#uxnawvkmix .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#uxnawvkmix .gt_from_md > :first-child {
  margin-top: 0;
}

#uxnawvkmix .gt_from_md > :last-child {
  margin-bottom: 0;
}

#uxnawvkmix .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#uxnawvkmix .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#uxnawvkmix .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#uxnawvkmix .gt_row_group_first td {
  border-top-width: 2px;
}

#uxnawvkmix .gt_row_group_first th {
  border-top-width: 2px;
}

#uxnawvkmix .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#uxnawvkmix .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#uxnawvkmix .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#uxnawvkmix .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#uxnawvkmix .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#uxnawvkmix .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#uxnawvkmix .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#uxnawvkmix .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#uxnawvkmix .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#uxnawvkmix .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#uxnawvkmix .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#uxnawvkmix .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#uxnawvkmix .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#uxnawvkmix .gt_left {
  text-align: left;
}

#uxnawvkmix .gt_center {
  text-align: center;
}

#uxnawvkmix .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#uxnawvkmix .gt_font_normal {
  font-weight: normal;
}

#uxnawvkmix .gt_font_bold {
  font-weight: bold;
}

#uxnawvkmix .gt_font_italic {
  font-style: italic;
}

#uxnawvkmix .gt_super {
  font-size: 65%;
}

#uxnawvkmix .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#uxnawvkmix .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#uxnawvkmix .gt_indent_1 {
  text-indent: 5px;
}

#uxnawvkmix .gt_indent_2 {
  text-indent: 10px;
}

#uxnawvkmix .gt_indent_3 {
  text-indent: 15px;
}

#uxnawvkmix .gt_indent_4 {
  text-indent: 20px;
}

#uxnawvkmix .gt_indent_5 {
  text-indent: 25px;
}

#uxnawvkmix .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#uxnawvkmix div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="Team" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Team</th>
<th id="npxGD/90" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">npxGD/90</th>
<th id="npGD/90" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">npGD/90</th>
<th id="Rating" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Rating</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Leeds United</td>
<td class="gt_row gt_center" headers="npxGD/90">0.82</td>
<td class="gt_row gt_center" headers="npGD/90">0.95</td>
<td class="gt_row gt_center" headers="Rating">0.86</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Leicester City</td>
<td class="gt_row gt_center" headers="npxGD/90">0.67</td>
<td class="gt_row gt_center" headers="npGD/90">0.77</td>
<td class="gt_row gt_center" headers="Rating">0.7</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Ipswich Town</td>
<td class="gt_row gt_center" headers="npxGD/90">0.6</td>
<td class="gt_row gt_center" headers="npGD/90">0.88</td>
<td class="gt_row gt_center" headers="Rating">0.68</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Southampton</td>
<td class="gt_row gt_center" headers="npxGD/90">0.69</td>
<td class="gt_row gt_center" headers="npGD/90">0.55</td>
<td class="gt_row gt_center" headers="Rating">0.65</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">West Brom</td>
<td class="gt_row gt_center" headers="npxGD/90">0.19</td>
<td class="gt_row gt_center" headers="npGD/90">0.52</td>
<td class="gt_row gt_center" headers="Rating">0.29</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Coventry City</td>
<td class="gt_row gt_center" headers="npxGD/90">0.24</td>
<td class="gt_row gt_center" headers="npGD/90">0.39</td>
<td class="gt_row gt_center" headers="Rating">0.28</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Middlesbrough</td>
<td class="gt_row gt_center" headers="npxGD/90">0.3</td>
<td class="gt_row gt_center" headers="npGD/90">0.08</td>
<td class="gt_row gt_center" headers="Rating">0.23</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Watford</td>
<td class="gt_row gt_center" headers="npxGD/90">0.14</td>
<td class="gt_row gt_center" headers="npGD/90">0.18</td>
<td class="gt_row gt_center" headers="Rating">0.15</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Norwich City</td>
<td class="gt_row gt_center" headers="npxGD/90">0.02</td>
<td class="gt_row gt_center" headers="npGD/90">0.37</td>
<td class="gt_row gt_center" headers="Rating">0.12</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Sunderland</td>
<td class="gt_row gt_center" headers="npxGD/90">0.16</td>
<td class="gt_row gt_center" headers="npGD/90">−0.07</td>
<td class="gt_row gt_center" headers="Rating">0.09</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Hull City</td>
<td class="gt_row gt_center" headers="npxGD/90">0.03</td>
<td class="gt_row gt_center" headers="npGD/90">0.08</td>
<td class="gt_row gt_center" headers="Rating">0.05</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Bristol City</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.09</td>
<td class="gt_row gt_center" headers="npGD/90">0.03</td>
<td class="gt_row gt_center" headers="Rating">−0.05</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Blackburn</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.01</td>
<td class="gt_row gt_center" headers="npGD/90">−0.18</td>
<td class="gt_row gt_center" headers="Rating">−0.06</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Stoke City</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.08</td>
<td class="gt_row gt_center" headers="npGD/90">−0.37</td>
<td class="gt_row gt_center" headers="Rating">−0.17</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Millwall</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.19</td>
<td class="gt_row gt_center" headers="npGD/90">−0.23</td>
<td class="gt_row gt_center" headers="Rating">−0.2</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Preston</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.3</td>
<td class="gt_row gt_center" headers="npGD/90">−0.07</td>
<td class="gt_row gt_center" headers="Rating">−0.23</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Swansea City</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.26</td>
<td class="gt_row gt_center" headers="npGD/90">−0.17</td>
<td class="gt_row gt_center" headers="Rating">−0.23</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">QPR</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.23</td>
<td class="gt_row gt_center" headers="npGD/90">−0.38</td>
<td class="gt_row gt_center" headers="Rating">−0.28</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Sheffield Weds</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.13</td>
<td class="gt_row gt_center" headers="npGD/90">−0.63</td>
<td class="gt_row gt_center" headers="Rating">−0.28</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Huddersfield</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.23</td>
<td class="gt_row gt_center" headers="npGD/90">−0.53</td>
<td class="gt_row gt_center" headers="Rating">−0.32</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Plymouth Argyle</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.41</td>
<td class="gt_row gt_center" headers="npGD/90">−0.12</td>
<td class="gt_row gt_center" headers="Rating">−0.32</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Birmingham City</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.37</td>
<td class="gt_row gt_center" headers="npGD/90">−0.45</td>
<td class="gt_row gt_center" headers="Rating">−0.39</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Team">Cardiff City</td>
<td class="gt_row gt_center" headers="npxGD/90">−0.55</td>
<td class="gt_row gt_center" headers="npGD/90">−0.35</td>
<td class="gt_row gt_center" headers="Rating">−0.49</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Team">Rotherham Utd</td>
<td class="gt_row gt_center" headers="npxGD/90">−1</td>
<td class="gt_row gt_center" headers="npGD/90">−1.18</td>
<td class="gt_row gt_center" headers="Rating">−1.05</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="4" class="gt_sourcenote" style="text-align: left;">Source: FBref Via {worldfootballR}</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>However, it is regrettable that my ratings are trying to convince me that Ipswich are good. Sure, they beat Southampton 3-2 on Monday. Still, Southampton were the (slightly) better team, and I watched Cardiff City dominate them earlier in the season, so I am convinced they are frauds that are going to Splendid Vibes their way to the Premier League<sup>10</sup>. Ipswich should be illegal.</p>
<p>Having calculated the (clearly wrong, disrespectful) team ratings, we can examine the schedules for the four teams left in the race for the automatic promotion spots. Table&nbsp;7 shows the SOS for the Championship’s top four teams.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1">champ_sos <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb16-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(team <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ipswich Town"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Leeds United"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Leicester City"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Southampton"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb16-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(sos) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb16-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(</span>
<span id="cb16-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Team"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> team,</span>
<span id="cb16-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Strength of Schedule (Z-Score)"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> sos</span>
<span id="cb16-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb16-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb16-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_footnote</span>(</span>
<span id="cb16-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">footnote =</span> </span>
<span id="cb16-11">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"z &lt; 0 = Easier than league average; z &gt; 0 = Harder than league average"</span></span>
<span id="cb16-12">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb16-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"num"</span>)</span></code></pre></div></div>
</details>
<div id="tbl-champ-sos" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-champ-sos-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;7: Championship Promotion Race’s Strength of Schedule
</figcaption>
<div aria-describedby="tbl-champ-sos-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="yjotqkofka" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#yjotqkofka table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#yjotqkofka thead, #yjotqkofka tbody, #yjotqkofka tfoot, #yjotqkofka tr, #yjotqkofka td, #yjotqkofka th {
  border-style: none;
}

#yjotqkofka p {
  margin: 0;
  padding: 0;
}

#yjotqkofka .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#yjotqkofka .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#yjotqkofka .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#yjotqkofka .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#yjotqkofka .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#yjotqkofka .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#yjotqkofka .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#yjotqkofka .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#yjotqkofka .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#yjotqkofka .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#yjotqkofka .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#yjotqkofka .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#yjotqkofka .gt_spanner_row {
  border-bottom-style: hidden;
}

#yjotqkofka .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#yjotqkofka .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#yjotqkofka .gt_from_md > :first-child {
  margin-top: 0;
}

#yjotqkofka .gt_from_md > :last-child {
  margin-bottom: 0;
}

#yjotqkofka .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#yjotqkofka .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#yjotqkofka .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#yjotqkofka .gt_row_group_first td {
  border-top-width: 2px;
}

#yjotqkofka .gt_row_group_first th {
  border-top-width: 2px;
}

#yjotqkofka .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#yjotqkofka .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#yjotqkofka .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#yjotqkofka .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#yjotqkofka .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#yjotqkofka .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#yjotqkofka .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#yjotqkofka .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#yjotqkofka .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#yjotqkofka .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#yjotqkofka .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#yjotqkofka .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#yjotqkofka .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#yjotqkofka .gt_left {
  text-align: left;
}

#yjotqkofka .gt_center {
  text-align: center;
}

#yjotqkofka .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#yjotqkofka .gt_font_normal {
  font-weight: normal;
}

#yjotqkofka .gt_font_bold {
  font-weight: bold;
}

#yjotqkofka .gt_font_italic {
  font-style: italic;
}

#yjotqkofka .gt_super {
  font-size: 65%;
}

#yjotqkofka .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#yjotqkofka .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#yjotqkofka .gt_indent_1 {
  text-indent: 5px;
}

#yjotqkofka .gt_indent_2 {
  text-indent: 10px;
}

#yjotqkofka .gt_indent_3 {
  text-indent: 15px;
}

#yjotqkofka .gt_indent_4 {
  text-indent: 20px;
}

#yjotqkofka .gt_indent_5 {
  text-indent: 25px;
}

#yjotqkofka .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#yjotqkofka div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>
<table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
  <thead>
    <tr class="gt_col_headings">
      <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Team">Team</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="Strength of Schedule (Z-Score)">Strength of Schedule (Z-Score)</th>
    </tr>
  </thead>
  <tbody class="gt_table_body">
    <tr><td headers="Team" class="gt_row gt_left">Leicester City</td>
<td headers="Strength of Schedule (Z-Score)" class="gt_row gt_center">−0.28</td></tr>
    <tr><td headers="Team" class="gt_row gt_left">Ipswich Town</td>
<td headers="Strength of Schedule (Z-Score)" class="gt_row gt_center">0.45</td></tr>
    <tr><td headers="Team" class="gt_row gt_left">Southampton</td>
<td headers="Strength of Schedule (Z-Score)" class="gt_row gt_center">1.02</td></tr>
    <tr><td headers="Team" class="gt_row gt_left">Leeds United</td>
<td headers="Strength of Schedule (Z-Score)" class="gt_row gt_center">1.1</td></tr>
  </tbody>
  <tfoot class="gt_sourcenotes">
    <tr>
      <td class="gt_sourcenote" style="text-align: left;" colspan="2">Source: FBref Via {worldfootballR}</td>
    </tr>
  </tfoot>
  <tfoot class="gt_footnotes">
    <tr>
      <td class="gt_footnote" style="text-align: left;" colspan="2"> z &lt; 0 = Easier than league average; z &gt; 0 = Harder than league average</td>
    </tr>
  </tfoot>
</table>
</div>
</div>
</div>
</figure>
</div>
</div>
<p>If the now slim <a href="https://analytic-fpl.streamlit.app/">probability of automatic promotion</a> wasn’t enough, Saints also face one of the most challenging schedules, only beaten by Leeds. Saint have to play Leeds and Leicester before the end of the season, both away from home, in addition to Coventry and Preston, who are still in the hunt for the final playoff spot. Southampton are the toughest team any of the others will face, though Leeds and Ipswich still have to face several playoff chasers, and Leicester are up against multiple relegation candidates.</p>
<p>Things don’t look much better when compared to the rest of the league.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb17-1">champ_sos <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb17-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">team =</span> forcats<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct_reorder</span>(team, sos)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb17-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> team, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> sos, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> sos <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb17-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_col</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb17-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_hline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">yintercept =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb17-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_text</span>(</span>
<span id="cb17-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(</span>
<span id="cb17-8">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(sos, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>),</span>
<span id="cb17-9">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">between</span>(sos, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>),</span>
<span id="cb17-10">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">case_when</span>(</span>
<span id="cb17-11">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">between</span>(sos, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>,</span>
<span id="cb17-12">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">between</span>(sos, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>,</span>
<span id="cb17-13">        sos <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>,</span>
<span id="cb17-14">        sos <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span></span>
<span id="cb17-15">        )</span>
<span id="cb17-16">      ),</span>
<span id="cb17-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fontface =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bold"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span></span>
<span id="cb17-18">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb17-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coord_flip</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb17-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_fill_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#D93649"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">guide =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"none"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb17-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_colour_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">guide =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"none"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb17-22">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb17-23">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Championship Teams' Strength of Schedule for Remaining Games"</span>,</span>
<span id="cb17-24">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span></span>
<span id="cb17-25">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb17-26">        glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb17-27">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Remaining schedule difficulty in the Championship, represented as "</span>,</span>
<span id="cb17-28">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Z-Scores. Scores above zero are harder than league average, below "</span>,</span>
<span id="cb17-29">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"easier. Z-Scores are the standard deviation distance from the mean "</span>,</span>
<span id="cb17-30">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"(i.e, scores of +1 (or -1) are 1 SD above (or below) mean)."</span></span>
<span id="cb17-31">          ),</span>
<span id="cb17-32">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb17-33">        ),</span>
<span id="cb17-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Strength of Schedule (Z-Score)"</span>,</span>
<span id="cb17-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson  |  Data: FBref Via {worldfootballR}"</span></span>
<span id="cb17-36">    )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-04-02-calculating-strength-of-schedule-football/index_files/figure-html/championship-sos-plot-1.png" class="img-fluid figure-img" alt="A barplot visualising the strength of remaining schedules for every team in the Championship. Positive scores indicate harder than league average schedules, and negative scores indicate easier than league average scores. The hardest remaining schedules are Blackburn (1.92), Watford (1.58), and Coventry (1.25), while the easiest schedules are Rotherham (-1.61), Swansea (-1.46), and Bristol City (-1.33). " width="672"></p>
</figure>
</div>
</div>
</div>
<p>No problem. Last night I asked <del>my landlord</del> the Championship to increase <del>my rent</del> the gap between the top three and Saints. That’s how much I believe in <del>my</del> Southampton’s grind/hustle.</p>
</section>
<section id="limitations" class="level2">
<h2 class="anchored" data-anchor-id="limitations">Limitations</h2>
<p>The most significant limitation is that this could be a lot more precise. I suspect the team ratings are the area with the greatest room for improvement. The 70%/30% split between npxGD/90 and npGD/90 is acceptable as a starting point, but a more precise approach to measuring team strengths will make a big difference in the final SOS calculations since the ratings do most of the heavy lifting.</p>
<p>The other major component in the model is how the opponents’ opponents are factored in as a means of weighting team ratings more effectively. I like the approach used here. It is a reasonably simple but effective way to get at this issue. That said, I wonder if the weight given to OR and OOR is ideal. I can’t think of a more robust approach, but maybe there is a better way to do things?</p>
<p>Finally, from a slightly different angle, should the baseline team ratings incorporate the schedules that each team has faced so that they are a more accurate representation of team strengths<sup>11</sup>? This doesn’t impact the final results of the SOS model, but it would make the team ratings more meaningful.</p>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>Nothing I’ve done here is particularly fancy or impressive, but SOS seems to be an overlooked area of football analytics, so does this at least fill a small gap? I’m sure SOS hasn’t received much attention because it’s just not that interesting, and everyone can live without it, but I fancied having a little play around with it, and here we are.</p>
<p>I can’t think of a better way to validate these results besides the eye test, but looking over the SOS for both the Premier League and the Championship, the results feel approximately correct. With the <a href="https://paulj1989.github.io/fitba/"><strong>fitba</strong></a> package, this approach can be applied to past or remaining schedules. It will be little use if you’re trying to measure SOS for the first handful of games in a season, but why would you do that anyway? Stop being a bozo and wait a few games. Regardless, I hope this method can be helpful to someone, even if only inspiring them to come up with something much better because I’m an idiot.</p>
</section>




<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Preview image by <a href="https://unsplash.com/@fearvi">Max Titov</a> on <a href="https://unsplash.com/photos/black-and-white-board-on-white-metal-frame-wb71RvAuvRY">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>



</div></section><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-caley2023" class="csl-entry">
Caley, Michael, and Mike Goodman. 2023. <em>Schedule Adjustments and the Premier League</em>. The Double Pivot Podcast. September. <a href="https://www.patreon.com/posts/schedule-and-89480237">https://www.patreon.com/posts/schedule-and-89480237</a>.
</div>
<div id="ref-torvaney2021xg" class="csl-entry">
Torvaney, Ben. 2021a. <em>Does xG Really Tell Us Everything about Team Performance?</em> <a href="https://www.statsandsnakeoil.com/2021/06/09/does-xg-really-tell-all/">https://www.statsandsnakeoil.com/2021/06/09/does-xg-really-tell-all/</a>.
</div>
<div id="ref-torvaney2021ratings" class="csl-entry">
Torvaney, Ben. 2021b. <em>How to Estimate Team Strength from xG Totals</em>. <a href="https://www.statsandsnakeoil.com/2021/06/24/estimating-team-strength-from-xg-totals/">https://www.statsandsnakeoil.com/2021/06/24/estimating-team-strength-from-xg-totals/</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>If anyone wants to complain about it being called soccer, then please a) grow up, and b) go look at who first came up with that term.↩︎</p></li>
<li id="fn2"><p>I’m not claiming to be an expert in the various ways SOS is calculated in American sports, so if you’re after a detailed literature review, I’m afraid you’ve come to the wrong place.↩︎</p></li>
<li id="fn3"><p>There are, however, lots of ways of approaching this <span class="citation" data-cites="torvaney2021ratings caley2023">(Torvaney 2021b; Caley and Goodman 2023)</span>.↩︎</p></li>
<li id="fn4"><p>I have included notation for each step in building the model, but I have hidden it because it isn’t necessary to understand the methodology. It’s just there for the sickos.↩︎</p></li>
<li id="fn5"><p>I mean, clearly, that’s not true. This blog post would not exist if I wasn’t an insufferable bore. But even I have my limits.↩︎</p></li>
<li id="fn6"><p>My main reason for abbreviating this is because writing this multiple times (and not messing up the punctuation) was intolerable.↩︎</p></li>
<li id="fn7"><p>I’m unsure if my concerns are warranted. I may be overthinking things. Feedback is welcome!↩︎</p></li>
<li id="fn8"><p><strong>F</strong>unctions <strong>I</strong>n<strong>T</strong>ended for foot<strong>B</strong>all <strong>A</strong>nalytics… Yes, I’m an idiot↩︎</p></li>
<li id="fn9"><p>The same applies to the top three in the Premier League this season. I care less about giving them credit.↩︎</p></li>
<li id="fn10"><p>Look, I know this isn’t true. For a while, the underlying numbers suggested they might be a level below Leeds, Leicester, and Saints. The numbers haven’t had my back for a while now, but I also watched multiple Ipswich games where they never really stood out (though they were pretty good against Southampton on Monday). I know it isn’t true. I’m sure I just watched a bad sample of Ipswich games. Let me live.↩︎</p></li>
<li id="fn11"><p>Yes, they probably should, but I also only just thought of this, and I can’t be bothered to go back and fix it right now.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2024" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2024. <span>“Calculating a Football Team’s Strength of
Schedule .”</span> April 2. <a href="https://paulrjohnson.net/blog/2024-04-02-calculating-strength-of-schedule-football/">https://paulrjohnson.net/blog/2024-04-02-calculating-strength-of-schedule-football/</a>.
</div></div></section></div> ]]></description>
  <category>Football Analytics</category>
  <category>Statistics</category>
  <category>R</category>
  <guid>https://paulrjohnson.net/blog/2024-04-02-calculating-strength-of-schedule-football/</guid>
  <pubDate>Tue, 02 Apr 2024 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2024-04-02-calculating-strength-of-schedule-football/scoreboard.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Missing Data Matters (Part II) - Solutions</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2024-03-26-missing-data-solutions/</link>
  <description><![CDATA[ 





<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>This is the second post in the Missing Data Matters series. The first post, about missing data mechanisms, can be found <a href="../../blog/missing-data-mechanisms">here</a>.</p>
</div>
</div>
<div class="cell">
<details class="code-fold">
<summary>Setup Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import packages</span></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">suppressPackageStartupMessages</span>({</span>
<span id="cb1-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(dplyr)</span>
<span id="cb1-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ggplot2)</span>
<span id="cb1-5">})</span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># helper function for transforming factor variables to title case</span></span>
<span id="cb1-8">str_titlecase_fct <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-9">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x, ...) {</span>
<span id="cb1-10">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">levels</span>(x) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-11">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_to_title</span>(stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_replace</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">levels</span>(x), ...))</span>
<span id="cb1-12">    x</span>
<span id="cb1-13">  }</span>
<span id="cb1-14"></span>
<span id="cb1-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import data</span></span>
<span id="cb1-16">attrition <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-17">  modeldata<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tibble</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-19">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(</span>
<span id="cb1-21">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"job_"</span>),</span>
<span id="cb1-22">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ends_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_satisfaction"</span>),</span>
<span id="cb1-23">    age,</span>
<span id="cb1-24">    attrition,</span>
<span id="cb1-25">    education,</span>
<span id="cb1-26">    monthly_income,</span>
<span id="cb1-27">    total_working_years,</span>
<span id="cb1-28">    num_companies_worked</span>
<span id="cb1-29">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-30">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb1-31">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(</span>
<span id="cb1-32">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">where</span>(is.factor),</span>
<span id="cb1-33">      <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_titlecase_fct</span>(.x, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span>)</span>
<span id="cb1-34">    )</span>
<span id="cb1-35">  )</span>
<span id="cb1-36"></span>
<span id="cb1-37"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># setup fonts</span></span>
<span id="cb1-38">sysfonts<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">font_add_google</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>)</span>
<span id="cb1-39">sysfonts<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">font_add_google</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>)</span>
<span id="cb1-40">showtext<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">showtext_auto</span>()</span>
<span id="cb1-41"></span>
<span id="cb1-42"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set plot theme</span></span>
<span id="cb1-43"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># inspired by https://github.com/z3tt/TidyTuesday/blob/main/R/2020_31_PalmerPenguins.Rmd</span></span>
<span id="cb1-44"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_set</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-45">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_update</span>(</span>
<span id="cb1-46">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.major =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb1-47">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.minor =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb1-48">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.title.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-49">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>,</span>
<span id="cb1-50">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb1-51">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-52">    ),</span>
<span id="cb1-53">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.title.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-54">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>,</span>
<span id="cb1-55">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">r =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb1-56">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-57">    ),</span>
<span id="cb1-58">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey50"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb1-59">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb1-60">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks.length =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lines"</span>),</span>
<span id="cb1-61">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"top"</span>,</span>
<span id="cb1-62">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.title =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb1-63">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb1-64">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.box.margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb1-65">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.title =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-66">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb1-67">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>,</span>
<span id="cb1-68">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>,</span>
<span id="cb1-69">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>),</span>
<span id="cb1-70">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-71">    ),</span>
<span id="cb1-72">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.subtitle =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-73">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb1-74">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>,</span>
<span id="cb1-75">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>,</span>
<span id="cb1-76">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lineheight =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>,</span>
<span id="cb1-77">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>),</span>
<span id="cb1-78">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb1-79">    ),</span>
<span id="cb1-80">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.title.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plot"</span>,</span>
<span id="cb1-81">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.caption =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-82">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey50"</span>,</span>
<span id="cb1-83">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>),</span>
<span id="cb1-84">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb1-85">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb1-86">    ),</span>
<span id="cb1-87">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.caption.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plot"</span>,</span>
<span id="cb1-88">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)),</span>
<span id="cb1-89">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">strip.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span>
<span id="cb1-90">  )</span>
<span id="cb1-91"></span>
<span id="cb1-92"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set table theme</span></span>
<span id="cb1-93">tbl_theme <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-94">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(tbl, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>) {</span>
<span id="cb1-95">    tbl <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-96">      gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_source_note</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source_note =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Source: IBM Watson Analytics Lab"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-97">      gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_options</span>(</span>
<span id="cb1-98">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.width =</span> gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pct</span>(width),</span>
<span id="cb1-99">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.font.names =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span></span>
<span id="cb1-100">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-101">      gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb1-102">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>),</span>
<span id="cb1-103">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_source_notes</span>(), gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_footnotes</span>())</span>
<span id="cb1-104">      )</span>
<span id="cb1-105">  }</span></code></pre></div></div>
</details>
</div>
<p>In the opening post in the Missing Data Matters series<sup>1</sup>, I looked at the mechanisms that cause missing data - missing completely at random (MCAR), missing at random (MAR), and missing not at random (MNAR) - and demonstrated some of the options available for diagnosing missing data mechanisms. This post will cover the next step in the missing data workflow - what the hell are you supposed to do now, having realised that your data is complete trash?</p>
<p>I will use the same <a href="https://modeldata.tidymodels.org/reference/attrition.html">employee attrition</a> dataset taken from the <a href="https://modeldata.tidymodels.org/"><strong>modeldata</strong></a> package and created by the IBM Watson Analytics Lab and will continue to add missingness to this data with reckless abandon. I will talk through the range of options available to you when faced with missing data, including both deletion and imputation methods, and I will also discuss how the missing data mechanism you are dealing with impacts the appropriateness of the available solutions. Finally, I will demonstrate how some of these methods work and compare their performance using a series of logistic regressions.</p>
<section id="have-you-considered-not-having-missing-data" class="level2">
<h2 class="anchored" data-anchor-id="have-you-considered-not-having-missing-data">Have You Considered Not Having Missing Data?</h2>
<p>The maximally optimal approach to missing data is to not have any, so if you have missing data, the best thing you can do is stop having it. The only way to do that is to go and find it! This may seem glib, but it’s important to highlight this point before looking at the other options. All of the strategies that are detailed below have drawbacks. If you can find your missing values, this is a much better choice than trying to model some solution. This may involve further data collection, identifying bugs/issues in your data processing pipeline, or theory-driven inference<sup>2</sup>.</p>
<p>However, when this is not possible, there are two broad approaches to dealing with missing values. The first approach is to delete missing values, and the second is to replace them. The right approach is highly dependent on the nature of the missing data. Generally speaking, data that is MCAR is the most flexible, and simple methods like deletion can work without problems, but more complex methods like imputation are necessary when data is MAR. Finally, when dealing with MNAR data, it is required to model the missingness mechanism explicitly <span class="citation" data-cites="gelman2006">(Gelman and Hill 2006)</span>.</p>
<section id="a-quick-note-on-mnar-data" class="level3">
<h3 class="anchored" data-anchor-id="a-quick-note-on-mnar-data">A Quick Note on MNAR Data</h3>
<p>Although we may touch on MNAR data in passing in this second post, the focus will be on MCAR and MAR data. The process for modelling MNAR data is complicated, and I am a massive coward. Cramming the suite of potential MNAR solutions into an already complex post would not do them justice.</p>
<p>However, as a quick summary, there are two main approaches to modelling MNAR data - selection modelling and pattern mixture modelling. Selection models treat missingness as the outcome in a regression, similar to a more precise version of the logistic regression fit in the previous post, while pattern mixture models treat the missingness as an explanatory variable.</p>
<p>For more information about MNAR modelling processes, I’d recommend <span class="citation" data-cites="enders2022">Enders (2022)</span>’s <em>Applied Missing Data Analysis</em>.</p>
</section>
<section id="and-another-on-likelihood-methods-for-good-measure" class="level3">
<h3 class="anchored" data-anchor-id="and-another-on-likelihood-methods-for-good-measure">And Another on Likelihood Methods for Good Measure</h3>
<p>One group of methods I haven’t discussed here is likelihood methods, such as full information maximum likelihood (FIML). In simple terms, likelihood methods borrow information from complete cases to improve the estimation of parameters with missing data <span class="citation" data-cites="peters2002">(Peters and Enders 2002)</span>. Maximum likelihood uses the available information to estimate a log-likelihood function most likely to have produced the observed data <span class="citation" data-cites="enders2022">(Enders 2022)</span>. In particular, FIML considers only complete cases when calculating the log-likelihood function and maximises it using an expectation-maximisation algorithm <span class="citation" data-cites="xu2022">(Xu et al. 2022)</span>.</p>
<p>However, implementing methods like FIML in R is a little tricky<sup>3</sup>, so these methods are out of scope for my rubbish little blog post. If you want to learn more about the implementation of FIML in R, I’d recommend the <a href="https://www.statistical-thinking.com/fiml">“Full Information Maximum Likelihood”</a> section of William Murrah’s <em>Statistical Thinking</em> site and there the <a href="https://lavaan.ugent.be/"><strong>lavaan</strong> package documentation</a> can also help figure out how to compute FIML to deal with missing data. If I am feeling like a total mad lad later on, I may write another post about implementing FIML.</p>
</section>
</section>
<section id="deletion-methods" class="level2">
<h2 class="anchored" data-anchor-id="deletion-methods">Deletion Methods</h2>
<p>The most straightforward and most common approach to handling missing data is to delete it. There are two different approaches to deleting missing values: listwise and pairwise deletion<sup>4</sup>.</p>
<p>Listwise deletion, sometimes called complete case analysis, is the most common. It removes any rows containing missing values for relevant variables. This means that the analysis is carried out on all complete cases. This is the default approach that almost every statistical tool in any language uses. It is the mechanism by which the plots in <a href="../../blog/missing-data-mechanisms">Part I</a> of the series are visualising the different types of missing data<sup>5</sup>. When you choose not to resolve the missing data in your dataset, you are passing the buck and letting whatever statistical tool you are using do it for you, and they are usually carrying out listwise deletion.</p>
<p>Pairwise deletion, or available case analysis, is less common. It involves removing any missing values but not the entire row. Instead, the available observations for each variable are used to calculate their means and covariances, which can be used to build statistical models <span class="citation" data-cites="vanbuuren2018">(Van Buuren 2018)</span>. This process is a little more involved and cannot be applied to as many use cases, so you should see pairwise deletion far less often in the wild.</p>
<p>Deletion-based methods can be robust under the right conditions. When data is MCAR and volumes of missing data are not vast, deletion methods may be suitable. However, things can start to unravel when data is MAR, and deletion methods will likely cause many problems when data is MNAR. Deleting values when data is MNAR (and to a slightly lesser extent MAR) creates selection bias. The sample that remains after deletion is a function of the missing data mechanism, which cannot be accounted for in a model if the data has been deleted. Nonetheless, deletion methods prevail because they are the default approach.</p>
</section>
<section id="imputation-methods" class="level2">
<h2 class="anchored" data-anchor-id="imputation-methods">Imputation Methods</h2>
<p>If we are not deleting missing values, we have to replace them. Imputation involves using a statistical procedure to replace missing values with values estimated from the rest of the data.</p>
<p>Imputation methods can be divided into single imputation and multiple imputation. Single imputation replaces missing values with a single value, while multiple imputation creates <img src="https://latex.codecogs.com/png.latex?m"> datasets, each replacing missing values with plausible estimated values and pooling estimates from analyses carried out on each dataset.</p>
<p>Imputation is appropriate under the starting assumption that the data is MAR. It is also suitable when dealing with MCAR data, but deletion methods are usually most appropriate unless dealing with large volumes of missingness.</p>
<p>In addition to <strong>mice</strong>’s exploratory capabilities, it is also the go-to option for carrying out imputation in R<sup>6</sup>. While I will briefly overview these methods, there is much more to imputation than could be covered here. To learn just about all there is to know about imputation, <span class="citation" data-cites="vanbuuren2018">Van Buuren (2018)</span>’s <a href="https://stefvanbuuren.name/fimd/"><em>Flexible Imputation of Missing Data</em></a> will have you covered.</p>
<section id="single-imputation" class="level3">
<h3 class="anchored" data-anchor-id="single-imputation">Single Imputation</h3>
<p>There are a few different forms of single imputation, the most common being simple imputation methods that replace all missing values with the variable’s average value (usually the mean, but median and mode can be used too) or replace missing values using randomly drawn values from the same variable, otherwise known as simple hot-deck imputation <span class="citation" data-cites="xu2022">(Xu et al. 2022)</span>. Simple imputation methods are almost always harmful, especially methods like mean imputation. They distort the variable’s distribution, underestimating its variance <span class="citation" data-cites="vanbuuren2018">(Van Buuren 2018)</span>, disrupting the relationship between the variable with imputed values and all other variables <span class="citation" data-cites="nguyen2020">(Nguyen 2020)</span>, and biasing model estimates <span class="citation" data-cites="vanbuuren2018">(Van Buuren 2018)</span>. It is important to know that these simple imputation methods exist, but the circumstances where using them is valid are very few!</p>
<p>Another approach is to estimate a regression model that predicts missing values. Regression imputation could take the form of any regression model, depending on the data type and complexity, with linear and logistic regression being the most common. However, <span class="citation" data-cites="vanbuuren2018">Van Buuren (2018)</span> argues that regression imputation is the “most dangerous” method because it gives false confidence in outputs.</p>
<p>We can look at the effects of imputation by visualising imputation methods. I have transformed the total working years value for 75% of employees with high or very high relationship satisfaction to NA. Obviously, this is a very high proportion of missing values. If 75% of your data is missing, you should be deeply alarmed, stop whatever you are doing, and bin that dataset. However, in this case, it is meant to illustrate how imputation methods work, and having a disproportionately large number of missing values makes it easier to see the effects visually.</p>
<div class="cell">
<details class="code-fold">
<summary>Data Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb2-2"></span>
<span id="cb2-3">missing_years <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb2-4">  attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb2-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">total_working_years =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace</span>(</span>
<span id="cb2-7">      total_working_years,</span>
<span id="cb2-8">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.75</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span></span>
<span id="cb2-9">        relationship_satisfaction <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"High"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Very High"</span>),</span>
<span id="cb2-10">      <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb2-11">    ),</span>
<span id="cb2-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">missingness =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ifelse</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(total_working_years), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Imputed"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Observed"</span>)</span>
<span id="cb2-13">  )</span></code></pre></div></div>
</details>
</div>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true" href="">Original Data</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false" href="">Simple Imputation</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-3-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-3" aria-controls="tabset-1-3" aria-selected="false" href="">Regression Imputation</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">plot_regression <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb3-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data) {</span>
<span id="cb3-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"missingness"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(data)) {</span>
<span id="cb3-4">      data <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-5">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> total_working_years, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> monthly_income)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-6">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> missingness), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-7">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb3-8">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb3-9">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>,</span>
<span id="cb3-10">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>,</span>
<span id="cb3-11">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span></span>
<span id="cb3-12">        ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-13">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_colour_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#D93649"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343A40"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-14">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_y_continuous</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_currency</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-15">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">guides</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">guide_legend</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">override.aes =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-16">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb3-17">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Total Working Years"</span>,</span>
<span id="cb3-18">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Monthly Income"</span>,</span>
<span id="cb3-19">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson  |  Data: IBM Watson Analytics Lab"</span></span>
<span id="cb3-20">        )</span>
<span id="cb3-21">    } <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> {</span>
<span id="cb3-22">      data <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-23">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> total_working_years, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> monthly_income)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-24">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#343A40"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-25">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_smooth</span>(</span>
<span id="cb3-26">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> lm,</span>
<span id="cb3-27">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>,</span>
<span id="cb3-28">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>,</span>
<span id="cb3-29">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span></span>
<span id="cb3-30">        ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-31">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_y_continuous</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_currency</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-32">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb3-33">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Total Working Years"</span>,</span>
<span id="cb3-34">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Monthly Income"</span>,</span>
<span id="cb3-35">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson  |  Data: IBM Watson Analytics Lab"</span></span>
<span id="cb3-36">        )</span>
<span id="cb3-37">    }</span>
<span id="cb3-38">  }</span>
<span id="cb3-39"></span>
<span id="cb3-40">attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-41">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_regression</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-42">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb3-43">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"No Missing Data &amp; No Imputation"</span>,</span>
<span id="cb3-44">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb3-45">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb3-46">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Employee's monthly income by total length of their career, without "</span>,</span>
<span id="cb3-47">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"missing values and without imputation."</span></span>
<span id="cb3-48">      ),</span>
<span id="cb3-49">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span></span>
<span id="cb3-50">    )</span>
<span id="cb3-51">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-03-26-missing-data-solutions/index_files/figure-html/original-data-1.png" class="img-fluid figure-img" alt="A scatterplot visualising the association between total working years and monthly income, without any missing data and therefore no imputation carried out. The plot shows a strong positive association between career length and monthly income. " width="672"></p>
</figure>
</div>
</div>
</div>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">missing_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-2">  mice<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mice</span>(</span>
<span id="cb4-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>,</span>
<span id="cb4-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">m =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb4-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">maxit =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb4-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">print =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb4-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-8">  mice<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">complete</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_regression</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb4-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb4-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mean Imputation"</span>,</span>
<span id="cb4-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb4-13">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb4-14">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Employee's monthly income by total length of their career, with "</span>,</span>
<span id="cb4-15">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"missing values replaced using mean imputation."</span></span>
<span id="cb4-16">      ),</span>
<span id="cb4-17">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span></span>
<span id="cb4-18">    )</span>
<span id="cb4-19">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-03-26-missing-data-solutions/index_files/figure-html/mean-imputation-1.png" class="img-fluid figure-img" alt="A scatterplot visualising the association between total working years and monthly income, with missing data resolved using mean imputation. The plot shows a strong positive association between career length and monthly income, with a large number of points imputed at the mean value of career length, just over 10 years. " width="672"></p>
</figure>
</div>
</div>
</div>
</div>
<div id="tabset-1-3" class="tab-pane" aria-labelledby="tabset-1-3-tab">
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1">missing_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-2">  mice<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mice</span>(</span>
<span id="cb5-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"norm.predict"</span>,</span>
<span id="cb5-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">m =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb5-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">maxit =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb5-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">print =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb5-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-8">  mice<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">complete</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_regression</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb5-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Linear Regression Imputation"</span>,</span>
<span id="cb5-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb5-13">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb5-14">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Employee's monthly income by total length of their career, with "</span>,</span>
<span id="cb5-15">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"missing values replaced using regression imputation with linear "</span>,</span>
<span id="cb5-16">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"regression."</span></span>
<span id="cb5-17">      ),</span>
<span id="cb5-18">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span></span>
<span id="cb5-19">    )</span>
<span id="cb5-20">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-03-26-missing-data-solutions/index_files/figure-html/regression-imputation-1.png" class="img-fluid figure-img" alt="A scatterplot visualising the association between total working years and monthly income, with missing data resolved using linear regression imputation. The plot shows a strong positive association between career length and monthly income, but imputed values appear to follow a less structured pattern than the observed values. " width="672"></p>
</figure>
</div>
</div>
</div>
</div>
</div>
</div>
<p>Imputing missing values using simple mean imputation is quick and easy, but the results clearly leave much to be desired. However, estimates can sometimes be useful even if they are imprecise. That’s not the case here either because mean imputation narrows the distribution of total working years. The confidence intervals around the regression line are narrower around the mean but significantly wider at the higher end of total working years.</p>
<p>The regression imputation is okay at first inspection, but it imputes values of total working years to six decimal points while the actual values are all integers. The imputation also thinks that some people have worked negative years! These issues can be fixed by giving <strong>mice</strong> the necessary details to impute more realistic values. However, the razor-thin error bars, particularly at the lower values of total working years, cannot be fixed using single imputation.</p>
<p>This points to the inherent flaw with single imputation that none of these methods can escape. In <span class="citation" data-cites="rubin1987">Rubin (1987)</span>’s words:</p>
<blockquote class="blockquote">
<p>Imputing one value for a missing datum cannot be correct in general, because we don’t know what value to impute with certainty (if we did, it wouldn’t be missing).</p>
</blockquote>
<p>We cannot account for the uncertainty in imputing missing values using single imputation because we are plugging in a single value in place of the missing value and treating it with the same confidence as the observed values. There are ways to add more uncertainty to single imputation methods, such as stochastic regression imputation, but ultimately, these are papering over the cracks. Single imputation always offers a false sense of certainty because it imputes a single value in place of each missing value.</p>
</section>
<section id="sec-multiple-imputation" class="level3">
<h3 class="anchored" data-anchor-id="sec-multiple-imputation">Multiple Imputation</h3>
<p>Multiple imputation attempts to address the fundamental flaw in single imputation methods, acknowledging the uncertainty in imputed values and baking that uncertainty into the process. Multiple imputation involves generating multiple datasets, performing analysis on each, and pooling the results. The multiple imputation process yields parameter estimates that “average over a number of plausible replacement values” <span class="citation" data-cites="enders2022">(Enders 2022, 189)</span> instead of the one that single imputation does. Multiple imputation can be appropriate for missing data that is not MAR, as long as the response mechanism has been explicitly modelled or other identifying assumptions have been made <span class="citation" data-cites="murray2018">(Murray 2018)</span>.</p>
<p><span class="citation" data-cites="enders2022">Enders (2022)</span> splits the multiple imputation process into three phases - imputation, analysis, and pooling.</p>
<ol type="1">
<li>Imputation Phase - generates multiple, <img src="https://latex.codecogs.com/png.latex?m">, complete datasets, estimating the missing values plus a random component to capture the uncertainty in the estimate,</li>
<li>Analysis Phase - computes parameter estimates using typical statistical methods, but computed <img src="https://latex.codecogs.com/png.latex?m"> times and applied to the <img src="https://latex.codecogs.com/png.latex?m"> completed datasets,</li>
<li>Pooling Phase - combines these estimates<sup>7</sup> and calculates the pooled estimates and their standard errors.</li>
</ol>
<p>While there are multiple ways to approach each phase, the three phases are typical across multiple imputation.</p>
<p>Here, we will use multiple imputation by chained equations (MICE). MICE imputes one variable at a time, using a separate model for each incomplete variable, a process called Fully Conditional Specification. Plausible values are generated using the rest of the data columns (using various methods depending on the variable) in an iterative process that uses Gibbs sampling <span class="citation" data-cites="vanbuuren2011">(Van Buuren and Groothuis-Oudshoorn 2011)</span>.</p>
<p>Effective multiple imputation requires as much information as possible, including variables associated with the missingness itself and with the observed values of that variable (which are, therefore, likely to be associated with the missing values). Thus, <span class="citation" data-cites="murray2018">Murray (2018)</span> argues that imputation models should include as many variables as possible.</p>
<p>The plot below shows the results of the imputation phase of the multiple imputation process, with the pooling carried out manually, but it is important to note that the results are not a perfect implementation of multiple imputation. Instead, each of the five completed datasets has been stacked together, and the mean value of each row<sup>8</sup> across those five datasets has been calculated. The results plotted below do not perfectly demonstrate what multiple imputation looks like, but they are at least an approximation.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">missing_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-2">  mice<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mice</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pmm"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">print =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-3">  mice<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">complete</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">action =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"long"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(</span>
<span id="cb6-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(total_working_years, monthly_income), <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(.x), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)),</span>
<span id="cb6-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(.id, missingness)</span>
<span id="cb6-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_regression</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb6-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb6-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Multiple Imputation with Predictive Mean Matching"</span>,</span>
<span id="cb6-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb6-12">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb6-13">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Employee's monthly income by total length of their career, with missing "</span>,</span>
<span id="cb6-14">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"values replaced using multiple imputation with predictive mean matching."</span></span>
<span id="cb6-15">      ),</span>
<span id="cb6-16">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span></span>
<span id="cb6-17">    )</span>
<span id="cb6-18">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-03-26-missing-data-solutions/index_files/figure-html/multiple-imputation-1.png" class="img-fluid figure-img" alt="A scatterplot visualising the association between total working years and monthly income, with missing data resolved using multiple imputation with predictive mean matching. The plot shows a strong positive association between career length and monthly income. Imputed values appear to follow a very similar pattern to observed values, and the multiple imputation plot looks very similar to the plot of the original data. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>The confidence intervals don’t capture the baked-in uncertainty, a significant advantage of multiple imputation. The plot only shows the final mean values calculated from the five imputed datasets. However, the multiple imputation process results follow a similar distribution to the original data, which should reduce the risk of imputations producing biased parameter estimates. Further, the imputed values appear to be structured similarly to the observed data, making the multiple imputation plot look very similar to the original data plot. This is generally a good sign because the closer you are to replicating the data-generating process, the better your chance of making accurate inferences. The structural similarities are primarily due to the method used to carry out the multiple imputation, predictive mean matching.</p>
<section id="predictive-mean-matching" class="level4">
<h4 class="anchored" data-anchor-id="predictive-mean-matching">Predictive Mean Matching</h4>
<p>The method used for modelling plausible values is predictive mean matching (PMM). PMM estimates missing values by identifying candidates from the observed data with predicted values close to the missing observation’s predicted value, from which a candidate is randomly selected and the observed value is plugged in the missing observation’s place <span class="citation" data-cites="vanbuuren2018">(Van Buuren 2018)</span>. Predictions are typically generated using a linear regression model. PMM effectively identifies <img src="https://latex.codecogs.com/png.latex?n"> observations from the observed data closest to the predicted value of the missing data and picks one at random.</p>
<p>There are several advantages to using PMM. Implementation is simple; it relies on imputations that are observed elsewhere in the data (which ensures it is realistic and won’t produce nonsensical imputations), and because the imputation process is implicit, it doesn’t require explicit modelling of the missingness distribution and, therefore reduces the risk of misspecification <span class="citation" data-cites="vanbuuren2018">(Van Buuren 2018)</span>. A more detailed discussion of PMM can be found in the <a href="https://stefvanbuuren.name/fimd/sec-pmm.html">“Predictive Mean Matching”</a> section of <span class="citation" data-cites="vanbuuren2018">Van Buuren (2018)</span>’s <em>Flexible Imputation of Missing Data</em>.</p>
<p>While I’ve used PMM here, <strong>mice</strong> offers <a href="https://amices.org/mice/reference/mice.html">functionality for various methods</a> for multiple imputation. In this case, the missing values are all numeric, for which <strong>mice</strong> uses PMM as the default imputation method. However, for binary factor variables, logistic regression is used by default, and where a factor variable has more than two levels, proportional odds regression is used when it is ordered, and polytomous logistic regression is used when it is unordered.</p>
</section>
</section>
</section>
<section id="comparing-model-estimates" class="level2">
<h2 class="anchored" data-anchor-id="comparing-model-estimates">Comparing Model Estimates</h2>
<p>Finally, we can test these missing data methods by fitting regression models using them. We can compare the model estimates with each other and against a regression fit on the original data.</p>
<p>I have fit a series of logistic regressions that measure the association between the outcome, job attrition, and the explanatory variables monthly income, total working years, and number of companies worked. All explanatory variables have been transformed to include some missingness. The missing data mechanism in each case is MAR. Monthly income values have been converted to NA for 75% of research scientists or sales executives educated to a Bachelor’s degree or higher. For total working years, 75% of employees between 50 and 60 have been converted to NA. Finally, the number of companies an employee has worked at has been converted to NA for 25% of employees with low job satisfaction.</p>
<div class="cell">
<details class="code-fold">
<summary>Data Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb7-2"></span>
<span id="cb7-3">missing_income <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb7-4">  attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb7-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">monthly_income =</span> arm<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rescale</span>(</span>
<span id="cb7-7">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace</span>(</span>
<span id="cb7-8">        monthly_income,</span>
<span id="cb7-9">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.75</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span></span>
<span id="cb7-10">          (education <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span></span>
<span id="cb7-11">            <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bachelor"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Master"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Doctor"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span></span>
<span id="cb7-12">            job_role <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Research Scientist"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sales Executive"</span>)),</span>
<span id="cb7-13">        <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb7-14">      )</span>
<span id="cb7-15">    ),</span>
<span id="cb7-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">total_working_years =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace</span>(</span>
<span id="cb7-17">      total_working_years,</span>
<span id="cb7-18">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.75</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span></span>
<span id="cb7-19">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">between</span>(age, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60</span>),</span>
<span id="cb7-20">      <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb7-21">    ),</span>
<span id="cb7-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">num_companies_worked =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace</span>(</span>
<span id="cb7-23">      num_companies_worked,</span>
<span id="cb7-24">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span></span>
<span id="cb7-25">        job_satisfaction <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Low"</span>),</span>
<span id="cb7-26">      <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb7-27">    )</span>
<span id="cb7-28">  )</span></code></pre></div></div>
</details>
</div>
<p>I have used the defaults for most imputation processes, but I have increased the number of iterations that the Gibbs sampler uses from 5 to 10 and have increased the number of complete datasets generated by the multiple imputation process from 5 to 30. While earlier literature on the subject argues that a small number of imputations (typically 3-5 total) is better, <span class="citation" data-cites="vanbuuren2018">Van Buuren (2018)</span> lays out the case for increasing the number of imputations, where computational cost is not a problem, in the <a href="https://stefvanbuuren.name/fimd/sec-howmany.html">“How Many Imputations?”</a> section of <em>Flexible Imputation of Missing Data</em>.</p>
<div class="cell">
<details class="code-fold">
<summary>Regression Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1">get_pooled_estimates <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb8-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data, method, m, maxit) {</span>
<span id="cb8-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (m <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) {</span>
<span id="cb8-4">      data <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-5">        mice<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mice</span>(</span>
<span id="cb8-6">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> method,</span>
<span id="cb8-7">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">m =</span> m,</span>
<span id="cb8-8">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">maxit =</span> maxit,</span>
<span id="cb8-9">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">print =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb8-10">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span></span>
<span id="cb8-11">        ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-12">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">with</span>(</span>
<span id="cb8-13">          <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glm</span>(</span>
<span id="cb8-14">            attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span></span>
<span id="cb8-15">              monthly_income <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> total_working_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> num_companies_worked,</span>
<span id="cb8-16">            <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"binomial"</span></span>
<span id="cb8-17">          )</span>
<span id="cb8-18">        ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-19">        mice<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pool</span>()</span>
<span id="cb8-20">    } <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> {</span>
<span id="cb8-21">      data <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-22">        mice<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mice</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> method, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">m =</span> m, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">maxit =</span> maxit, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">print =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-23">        mice<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">complete</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-24">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glm</span>(</span>
<span id="cb8-25">          attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span></span>
<span id="cb8-26">            monthly_income <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> total_working_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> num_companies_worked,</span>
<span id="cb8-27">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"binomial"</span>,</span>
<span id="cb8-28">          <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> _</span>
<span id="cb8-29">        )</span>
<span id="cb8-30">    }</span>
<span id="cb8-31">  }</span>
<span id="cb8-32"></span>
<span id="cb8-33">original_glm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb8-34">  attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-35">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">monthly_income =</span> arm<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rescale</span>(monthly_income)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-36">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glm</span>(</span>
<span id="cb8-37">    attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> monthly_income <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> total_working_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> num_companies_worked,</span>
<span id="cb8-38">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"binomial"</span>,</span>
<span id="cb8-39">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> _</span>
<span id="cb8-40">  )</span>
<span id="cb8-41"></span>
<span id="cb8-42">listwise_deletion <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb8-43">  missing_income <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-44">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glm</span>(</span>
<span id="cb8-45">    attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> monthly_income <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> total_working_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> num_companies_worked,</span>
<span id="cb8-46">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"binomial"</span>,</span>
<span id="cb8-47">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> _</span>
<span id="cb8-48">  )</span>
<span id="cb8-49"></span>
<span id="cb8-50">mean_imputation <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb8-51">  missing_income <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-52">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_pooled_estimates</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">m =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">maxit =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb8-53"></span>
<span id="cb8-54">regression_imputation <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb8-55">  missing_income <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-56">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_pooled_estimates</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"norm.predict"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">m =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">maxit =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb8-57"></span>
<span id="cb8-58">multiple_imputation <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb8-59">  missing_income <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-60">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_pooled_estimates</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pmm"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">m =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">maxit =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span></code></pre></div></div>
</details>
</div>
<p>More can be done to tailor and tighten up <strong>mice</strong>’s imputations, but the intention here is only to demonstrate how different missing data methods perform out of the box.</p>
<p>While the imputations visualised in Section&nbsp;3.2 are only an approximation of the process, the outputs displayed in Table&nbsp;1 below fully demonstrate the multiple imputation method.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1">modelsummary<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">modelsummary</span>(</span>
<span id="cb9-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">models =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb9-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Original Data"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> original_glm,</span>
<span id="cb9-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Listwise Deletion"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> listwise_deletion,</span>
<span id="cb9-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Mean"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> mean_imputation,</span>
<span id="cb9-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Regression"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> regression_imputation,</span>
<span id="cb9-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Multiple"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> multiple_imputation</span>
<span id="cb9-8">  ),</span>
<span id="cb9-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coef_rename =</span> modelsummary<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>coef_rename,</span>
<span id="cb9-10">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">exponentiate =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,</span>
<span id="cb9-11">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">gof_omit =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IC|Log|F|RMSE"</span>,</span>
<span id="cb9-12">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">output =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gt"</span></span>
<span id="cb9-13">) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-14">  gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_spanner</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Imputation"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-15">  gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_spanner</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Outcome: Job Attrition"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>()</span></code></pre></div></div>
</details>
<div id="tbl-regression" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-regression-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Logistic Regressions Using Different Missing Data Strategies
</figcaption>
<div aria-describedby="tbl-regression-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="osncjrvket" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#osncjrvket table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#osncjrvket thead, #osncjrvket tbody, #osncjrvket tfoot, #osncjrvket tr, #osncjrvket td, #osncjrvket th {
  border-style: none;
}

#osncjrvket p {
  margin: 0;
  padding: 0;
}

#osncjrvket .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#osncjrvket .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#osncjrvket .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#osncjrvket .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#osncjrvket .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#osncjrvket .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#osncjrvket .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#osncjrvket .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#osncjrvket .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#osncjrvket .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#osncjrvket .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#osncjrvket .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#osncjrvket .gt_spanner_row {
  border-bottom-style: hidden;
}

#osncjrvket .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#osncjrvket .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#osncjrvket .gt_from_md > :first-child {
  margin-top: 0;
}

#osncjrvket .gt_from_md > :last-child {
  margin-bottom: 0;
}

#osncjrvket .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#osncjrvket .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#osncjrvket .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#osncjrvket .gt_row_group_first td {
  border-top-width: 2px;
}

#osncjrvket .gt_row_group_first th {
  border-top-width: 2px;
}

#osncjrvket .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#osncjrvket .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#osncjrvket .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#osncjrvket .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#osncjrvket .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#osncjrvket .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#osncjrvket .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#osncjrvket .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#osncjrvket .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#osncjrvket .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#osncjrvket .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#osncjrvket .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#osncjrvket .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#osncjrvket .gt_left {
  text-align: left;
}

#osncjrvket .gt_center {
  text-align: center;
}

#osncjrvket .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#osncjrvket .gt_font_normal {
  font-weight: normal;
}

#osncjrvket .gt_font_bold {
  font-weight: bold;
}

#osncjrvket .gt_font_italic {
  font-style: italic;
}

#osncjrvket .gt_super {
  font-size: 65%;
}

#osncjrvket .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#osncjrvket .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#osncjrvket .gt_indent_1 {
  text-indent: 5px;
}

#osncjrvket .gt_indent_2 {
  text-indent: 10px;
}

#osncjrvket .gt_indent_3 {
  text-indent: 15px;
}

#osncjrvket .gt_indent_4 {
  text-indent: 20px;
}

#osncjrvket .gt_indent_5 {
  text-indent: 25px;
}

#osncjrvket .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#osncjrvket div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<colgroup>
<col style="width: 16%">
<col style="width: 16%">
<col style="width: 16%">
<col style="width: 16%">
<col style="width: 16%">
<col style="width: 16%">
</colgroup>
<thead>
<tr class="gt_col_headings gt_spanner_row header">
<th class="gt_center gt_columns_top_border gt_column_spanner_outer" data-quarto-table-cell-role="th" scope="col"></th>
<th colspan="5" id="Outcome: Job Attrition" class="gt_center gt_columns_top_border gt_column_spanner_outer" data-quarto-table-cell-role="th" scope="colgroup"><div class="gt_column_spanner">
Outcome: Job Attrition
</div></th>
</tr>
<tr class="gt_col_headings gt_spanner_row even">
<th rowspan="2" id="a-" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col"></th>
<th rowspan="2" id="Original-Data" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Original Data</th>
<th rowspan="2" id="Listwise-Deletion" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Listwise Deletion</th>
<th colspan="3" id="Imputation" class="gt_center gt_columns_top_border gt_column_spanner_outer" data-quarto-table-cell-role="th" scope="colgroup"><div class="gt_column_spanner">
Imputation
</div></th>
</tr>
<tr class="gt_col_headings header">
<th id="Mean" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Mean</th>
<th id="Regression" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Regression</th>
<th id="Multiple" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Multiple</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers=" ">(Intercept)</td>
<td class="gt_row gt_center" headers="Original Data">0.260</td>
<td class="gt_row gt_center" headers="Listwise Deletion">0.297</td>
<td class="gt_row gt_center" headers="Mean">0.247</td>
<td class="gt_row gt_center" headers="Regression">0.261</td>
<td class="gt_row gt_center" headers="Multiple">0.262</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers=" "></td>
<td class="gt_row gt_center" headers="Original Data">(0.052)</td>
<td class="gt_row gt_center" headers="Listwise Deletion">(0.082)</td>
<td class="gt_row gt_center" headers="Mean">(0.047)</td>
<td class="gt_row gt_center" headers="Regression">(0.056)</td>
<td class="gt_row gt_center" headers="Multiple">(0.058)</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers=" ">Monthly Income</td>
<td class="gt_row gt_center" headers="Original Data">0.574</td>
<td class="gt_row gt_center" headers="Listwise Deletion">0.387</td>
<td class="gt_row gt_center" headers="Mean">0.334</td>
<td class="gt_row gt_center" headers="Regression">0.520</td>
<td class="gt_row gt_center" headers="Multiple">0.543</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers=" "></td>
<td class="gt_row gt_center" headers="Original Data">(0.161)</td>
<td class="gt_row gt_center" headers="Listwise Deletion">(0.166)</td>
<td class="gt_row gt_center" headers="Mean">(0.095)</td>
<td class="gt_row gt_center" headers="Regression">(0.163)</td>
<td class="gt_row gt_center" headers="Multiple">(0.174)</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers=" ">Total Working Years</td>
<td class="gt_row gt_center" headers="Original Data">0.937</td>
<td class="gt_row gt_center" headers="Listwise Deletion">0.906</td>
<td class="gt_row gt_center" headers="Mean">0.931</td>
<td class="gt_row gt_center" headers="Regression">0.932</td>
<td class="gt_row gt_center" headers="Multiple">0.933</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers=" "></td>
<td class="gt_row gt_center" headers="Original Data">(0.017)</td>
<td class="gt_row gt_center" headers="Listwise Deletion">(0.023)</td>
<td class="gt_row gt_center" headers="Mean">(0.017)</td>
<td class="gt_row gt_center" headers="Regression">(0.017)</td>
<td class="gt_row gt_center" headers="Multiple">(0.018)</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers=" ">Num Companies Worked</td>
<td class="gt_row gt_center" headers="Original Data">1.107</td>
<td class="gt_row gt_center" headers="Listwise Deletion">1.097</td>
<td class="gt_row gt_center" headers="Mean">1.114</td>
<td class="gt_row gt_center" headers="Regression">1.117</td>
<td class="gt_row gt_center" headers="Multiple">1.111</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers=" " style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000"></td>
<td class="gt_row gt_center" headers="Original Data" style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000">(0.032)</td>
<td class="gt_row gt_center" headers="Listwise Deletion" style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000">(0.041)</td>
<td class="gt_row gt_center" headers="Mean" style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000">(0.033)</td>
<td class="gt_row gt_center" headers="Regression" style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000">(0.033)</td>
<td class="gt_row gt_center" headers="Multiple" style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000">(0.033)</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers=" ">Num.Obs.</td>
<td class="gt_row gt_center" headers="Original Data">1470</td>
<td class="gt_row gt_center" headers="Listwise Deletion">989</td>
<td class="gt_row gt_center" headers="Mean">1470</td>
<td class="gt_row gt_center" headers="Regression">1470</td>
<td class="gt_row gt_center" headers="Multiple">1470</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers=" ">Num.Imp.</td>
<td class="gt_row gt_center" headers="Original Data"></td>
<td class="gt_row gt_center" headers="Listwise Deletion"></td>
<td class="gt_row gt_center" headers="Mean"></td>
<td class="gt_row gt_center" headers="Regression"></td>
<td class="gt_row gt_center" headers="Multiple">50</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="6" class="gt_sourcenote" style="text-align: left;">Source: IBM Watson Analytics Lab</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>Table&nbsp;1 highlights how impressive multiple imputation can be and why it is often ill-advised to use deletion or single imputation methods. While there are one or two coefficients where the deletion or single imputation methods are close to or even marginally outperform the multiple imputation process, the multiple imputation results are significantly better overall.</p>
<p>It’s not only that the coefficient estimates are generally closer to the estimates on the original data but also that the standard errors account for the greater uncertainty that should be factored in when imputing missing values. This is good. We do not want to be overconfident in conclusions drawn on data that includes imputed values, and multiple imputation guards against this.</p>
</section>
<section id="which-way-western-man" class="level2">
<h2 class="anchored" data-anchor-id="which-way-western-man">Which Way, Western Man?</h2>
<p>So, what kind of analyst are you going to be? Are you going to impute everything because unbiased estimates are overrated? Or will you delete all your missing data because less data is good, and there couldn’t be anything important in those observations anyway? The good news is that these are improvements compared to what you have probably been doing until now. Not dealing with missing values is a methodological choice in and of itself, often a bad one. Sometimes, listwise deletion is defensible, but you should be the one to make that call because you’re the one who’s on the hook for the consequences! As <span class="citation" data-cites="newman2014">Newman (2014)</span> argue - abstinence is not an option.</p>
<p>Of course, if you want to show everyone what a wise old sage you are, consider multiple imputation instead.</p>
<p>This blog post only scratches the surface of missing data methods. As tempting as it might be to summarise an entire research field, I’d also have to read about 2,000 Donald Rubin papers before I could even get started on what anyone else has to say on this topic. Various methods, such as likelihood methods and multilevel imputation, haven’t been covered here, and I haven’t discussed the <a href="stefvanbuuren.name/fimd/sec-evaluation.html">evaluation of imputation results</a>. All of this stuff is important! But this blog post is already longer than I originally planned, and if I’m not careful it’ll soon end up being so large that tech companies will start using it as a corpus to train their large language models. Hopefully, this brief introduction will inspire you to continue learning about missing data methods.</p>
</section>




<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Many thanks to Camilo Alvarez (of the great Trivote Discord fame) for his kind but constructive feedback during the development of this series of blog posts. I greatly appreciate anyone who helps me be just a little less stupid.</p>
<p>The preview image was generated using StabilityAI’s <a href="https://beta.dreamstudio.ai/">DreamStudio</a>, using the prompt “An eerie-looking image of a boy lost in a field, with a sign behind him saying ‘Missing Data - Please Return At Earliest Convenience’”.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>



</div></section><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-enders2022" class="csl-entry">
Enders, Craig K. 2022. <em>Applied Missing Data Analysis</em>. Guilford Publications.
</div>
<div id="ref-gelman2006" class="csl-entry">
Gelman, Andrew, and Jennifer Hill. 2006. <span>“Missing-Data Imputation.”</span> In <em>Data Analysis Using Regression and Multilevel/Hierarchical Models</em>. Cambridge University Press.
</div>
<div id="ref-murray2018" class="csl-entry">
Murray, Jared S. 2018. <em>Multiple Imputation: A Review of Practical and Theoretical Findings</em>. <a href="https://arxiv.org/pdf/1801.04058.pdf">https://arxiv.org/pdf/1801.04058.pdf</a>.
</div>
<div id="ref-newman2014" class="csl-entry">
Newman, Daniel A. 2014. <span>“Missing Data: Five Practical Guidelines.”</span> <em>Organizational Research Methods</em> 17 (4): 372–411.
</div>
<div id="ref-nguyen2020" class="csl-entry">
Nguyen, Mike. 2020. <em>A Guide on Data Analysis</em>. Bookdown. <a href="https://bookdown.org/mike/data_analysis/">https://bookdown.org/mike/data_analysis/</a>.
</div>
<div id="ref-peters2002" class="csl-entry">
Peters, Cara Lee Okleshen, and Craig Enders. 2002. <span>“A Primer for the Estimation of Structural Equation Models in the Presence of Missing Data: Maximum Likelihood Algorithms.”</span> <em>Journal of Targeting, Measurement and Analysis for Marketing</em> 11: 81–95.
</div>
<div id="ref-rubin1987" class="csl-entry">
Rubin, Donald B. 1987. <em>Multiple Imputation for Nonresponse in Surveys</em>. Wiley.
</div>
<div id="ref-vanbuuren2018" class="csl-entry">
Van Buuren, Stef. 2018. <em>Flexible Imputation of Missing Data</em>. CRC Press. <a href="https://stefvanbuuren.name/fimd/">https://stefvanbuuren.name/fimd/</a>.
</div>
<div id="ref-vanbuuren2011" class="csl-entry">
Van Buuren, Stef, and Karin Groothuis-Oudshoorn. 2011. <span>“MICE: Multivariate Imputation by Chained Equations in r.”</span> <em>Journal of Statistical Software</em> 45 (3): 1–67. <a href="https://doi.org/10.18637/jss.v045.i03">https://doi.org/10.18637/jss.v045.i03</a>.
</div>
<div id="ref-xu2022" class="csl-entry">
Xu, Tianchen, Kun Chen, and Gen Li. 2022. <span>“The More Data, the Better? Demystifying Deletion-Based Methods in Linear Regression with Missing Data.”</span> <em>Statistics and Its Interface</em> 15 (4): 515.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>I keep calling it a series because I couldn’t think of another way to refer to it, but calling two posts a series feels grandiose. Am I forgetting a better word for this?↩︎</p></li>
<li id="fn2"><p>If you know the data well and can identify precisely why the data is missing, you may also be able to plug in the missing values. However, you should be pretty sure when doing this because otherwise, you have personally taken the time to add some error to your data. This is bad for all but the most graft-thirsty High Performance Podcast listening maniacs. If you would take the <a href="https://i.kym-cdn.com/entries/icons/original/000/038/686/jayz.jpg">$500k over dinner with Jay-Z</a>, you should make sure your theory is sound!↩︎</p></li>
<li id="fn3"><p>Or is at least sufficiently distinct from the implementation of the methods discussed below that it would be significant work to include likelihood methods in this post.↩︎</p></li>
<li id="fn4"><p>As I type this, it occurs to me that there are probably more than two methods for deleting missing values. Maybe someone out there advocates deleting the whole dataset and smashing your laptop with a hammer whenever you encounter NAs.↩︎</p></li>
<li id="fn5"><p><strong>ggplot2</strong> removes NAs by default, so the plots in the previous post are working by creating missing values and letting <strong>ggplot2</strong> do the rest.↩︎</p></li>
<li id="fn6"><p>For anyone that prefers to use Python, <a href="https://www.statsmodels.org/stable/imputation.html"><strong>statsmodels</strong></a> also has the functionality for multiple imputation by chained equations, while <a href="https://github.com/iskandr/fancyimpute"><strong>fancyimpute</strong></a> and <a href="https://scikit-learn.org/stable/modules/classes.html#module-sklearn.impute"><strong>sklearn.impute</strong></a> offer further imputation functionality.↩︎</p></li>
<li id="fn7"><p><span class="citation" data-cites="rubin1987">Rubin (1987)</span> devised formulas for pooling parameter estimates and standard errors, where the pooled parameter estimate is the arithmetic mean of the individual estimates, while pooled standard errors follow a similar logic but a slightly more complex process <span class="citation" data-cites="enders2022">(Enders 2022)</span>. There are also methods for calculating statistical significance, but things are getting much more complicated now, and this is not the time or the place. I’d recommend reading “The Analysis and Pooling Phases of Multiple Imputation” in <span class="citation" data-cites="enders2022">Enders (2022)</span>’s <em>Applied Missing Data Analysis</em> if you want to get in the weeds.↩︎</p></li>
<li id="fn8"><p>The mean value has been rounded to the integer value so as to not mask what predictive mean matching is doing.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2024" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2024. <span>“Missing Data Matters (Part II) -
Solutions.”</span> March 26. <a href="https://paulrjohnson.net/blog/2024-03-26-missing-data-solutions/">https://paulrjohnson.net/blog/2024-03-26-missing-data-solutions/</a>.
</div></div></section></div> ]]></description>
  <category>Missing Data</category>
  <category>Imputation</category>
  <category>Statistics</category>
  <category>R</category>
  <guid>https://paulrjohnson.net/blog/2024-03-26-missing-data-solutions/</guid>
  <pubDate>Tue, 26 Mar 2024 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2024-03-26-missing-data-solutions/missing_data.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Missing Data Matters (Part I): Mechanisms</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/</link>
  <description><![CDATA[ 





<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>This is the first post in the Missing Data Matters series. The second post, about missing data solutions, can be found <a href="../../blog/missing-data-solutions">here</a>.</p>
</div>
</div>
<div class="cell">
<details class="code-fold">
<summary>Setup Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import packages</span></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">suppressPackageStartupMessages</span>({</span>
<span id="cb1-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(dplyr)</span>
<span id="cb1-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ggplot2)</span>
<span id="cb1-5">})</span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># helper function for transforming factor variables to title case</span></span>
<span id="cb1-8">str_titlecase_fct <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-9">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x, ...) {</span>
<span id="cb1-10">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">levels</span>(x) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-11">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_to_title</span>(stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_replace</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">levels</span>(x), ...))</span>
<span id="cb1-12">    x</span>
<span id="cb1-13">  }</span>
<span id="cb1-14"></span>
<span id="cb1-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import data</span></span>
<span id="cb1-16">attrition <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-17">  modeldata<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tibble</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-19">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb1-21">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(</span>
<span id="cb1-22">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">where</span>(is.factor),</span>
<span id="cb1-23">      <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_titlecase_fct</span>(.x, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span>)</span>
<span id="cb1-24">    )</span>
<span id="cb1-25">  )</span>
<span id="cb1-26"></span>
<span id="cb1-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># setup fonts</span></span>
<span id="cb1-28">sysfonts<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">font_add_google</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>)</span>
<span id="cb1-29">sysfonts<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">font_add_google</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>)</span>
<span id="cb1-30">showtext<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">showtext_auto</span>()</span>
<span id="cb1-31"></span>
<span id="cb1-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set plot theme</span></span>
<span id="cb1-33"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># inspired by https://github.com/z3tt/TidyTuesday/blob/main/R/2020_31_PalmerPenguins.Rmd</span></span>
<span id="cb1-34"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_set</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-35">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_update</span>(</span>
<span id="cb1-36">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.major =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb1-37">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.minor =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb1-38">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.title.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-39">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>,</span>
<span id="cb1-40">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb1-41">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-42">    ),</span>
<span id="cb1-43">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.title.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-44">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>,</span>
<span id="cb1-45">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">r =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb1-46">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-47">    ),</span>
<span id="cb1-48">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey50"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb1-49">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb1-50">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks.length =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lines"</span>),</span>
<span id="cb1-51">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"top"</span>,</span>
<span id="cb1-52">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.title =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb1-53">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb1-54">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.box.margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb1-55">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.title =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-56">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb1-57">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>,</span>
<span id="cb1-58">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>,</span>
<span id="cb1-59">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>),</span>
<span id="cb1-60">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-61">    ),</span>
<span id="cb1-62">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.subtitle =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-63">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb1-64">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>,</span>
<span id="cb1-65">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>,</span>
<span id="cb1-66">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lineheight =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>,</span>
<span id="cb1-67">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>),</span>
<span id="cb1-68">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb1-69">    ),</span>
<span id="cb1-70">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.title.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plot"</span>,</span>
<span id="cb1-71">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.caption =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-72">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey50"</span>,</span>
<span id="cb1-73">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>),</span>
<span id="cb1-74">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb1-75">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb1-76">    ),</span>
<span id="cb1-77">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.caption.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plot"</span>,</span>
<span id="cb1-78">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)),</span>
<span id="cb1-79">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">strip.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span>
<span id="cb1-80">  )</span>
<span id="cb1-81"></span>
<span id="cb1-82"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set table theme</span></span>
<span id="cb1-83">tbl_theme <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-84">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(tbl, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>) {</span>
<span id="cb1-85">    tbl <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-86">      gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_source_note</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source_note =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Source: IBM Watson Analytics Lab"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-87">      gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_options</span>(</span>
<span id="cb1-88">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.width =</span> gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pct</span>(width),</span>
<span id="cb1-89">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.font.names =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span></span>
<span id="cb1-90">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-91">      gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb1-92">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>),</span>
<span id="cb1-93">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_source_notes</span>(), gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_footnotes</span>())</span>
<span id="cb1-94">      )</span>
<span id="cb1-95">  }</span></code></pre></div></div>
</details>
</div>
<p>I recently presented a talk about missing data, discussing the different types of missing data and their appropriate solutions. As a modern man who understands that the posting never ends, I figured I could turn this talk into a series of blog posts. Resources discussing missing data often offer either brief overviews or incredible depth, but there are fewer resources out there that thread the needle between the two. My goal is to do that with this series.</p>
<p>It turns out that missing data is a rich field. There is far more to it than simply pretending you didn’t see it, like seeing a friend’s child misbehaving. It’s not my problem unless I make it my problem, right? Wrong. Unlike your friend’s child, there are consequences to not taking some responsibility for missing data. This series will make a case for taking missing data seriously. This first post will introduce the key concepts in this area, focusing on identifying missing data and its types. The second blog post will look at solutions to these missing data problems, illustrating the when’s and why’s of these solutions. Please enjoy my regurgitated data slop.</p>
<p>The data used as an illustration in this series is a synthetic <a href="https://modeldata.tidymodels.org/reference/attrition.html">employee attrition</a> dataset taken from the <a href="https://modeldata.tidymodels.org/"><strong>modeldata</strong></a> package, created by the IBM Watson Analytics Lab. The dataset contains 1,470 observations and is picture-perfect, containing nothing but observations that wouldn’t dream of being missing. Instead, I will invoke missingness by replacing values with NAs.</p>
<section id="confessing-my-sins" class="level2">
<h2 class="anchored" data-anchor-id="confessing-my-sins">Confessing My Sins</h2>
<p>Missingness is a common problem in data, but it doesn’t receive the attention it deserves, and as a result, it often goes unaddressed in analyses. I have been guilty of this plenty of times in the past. I’m sure many of us have been.</p>
<p>It is easy to ignore missing data if you want to. Most statistical tools and programming languages have default mechanisms for dealing with NAs when encountered in the data, which is necessary because missing data is so common. Not having a method for resolving NAs would trip these tools up constantly. However, this produces unintended consequences. It makes it far too easy for the user to pass the buck and practice abstinence when it comes to missing data.</p>
<p>Missing data is the drawer in your fridge filled with soggy vegetables you hope someone else will deal with. Out of sight, out of mind. I’m just that insufferable productivity guy telling you that your chores won’t seem like such a big deal if you do them as soon as they come up. Dealing with missing data is choosing a healthy lifestyle. It’s your regular sleep schedule.</p>
</section>
<section id="sec-mechanisms" class="level2">
<h2 class="anchored" data-anchor-id="sec-mechanisms">Missing Data Mechanisms</h2>
<p><span class="citation" data-cites="rubin1976">Rubin (1976)</span> laid a lot of the groundwork for how we think about missing data today. He argued that all observations in a dataset have some likelihood of being missing, referring to this process as the missing data mechanism. He specifies three different mechanisms that cause missing data - missing completely at random (MCAR), missing at random (MAR), and missing not at random (MNAR). I think this terminology can be a little confusing. The difference between MCAR and MAR is not clear from their names. I would define these three categories as follows:</p>
<ul>
<li><p>Missing Completely at Random (MCAR) – the probability of an observation being missing is the same for all cases, implying that the cause of missing values is unrelated to the data <span class="citation" data-cites="vanbuuren2018">(Van Buuren 2018)</span>. MCAR data is not associated with other variables in the dataset and is uniformly random within-variable. In other words, it is <strong>completely</strong> random<sup>1</sup>.</p></li>
<li><p>Missing at Random (MAR) – the probability of an observation being missing is uniformly distributed within that variable, meaning that all potential values are equally as likely to be missing. However, missing data is associated with other variables in the data. The observed values of correlated variables could be used to predict missing values.</p></li>
<li><p>Missing Not at Random (MNAR) – the probability of an observation being missing is not random, and the mechanism that underpins missing values is unknown. Missing values follow a pattern, but that pattern is a function of unobserved data, whether it be the variable’s values themselves (for example, values over a certain threshold are all missing) or an unobserved variable.</p></li>
</ul>
<p>For a more detailed explanation of the differences between MCAR, MAR, and MNAR data, I’d recommend the <a href="https://stefvanbuuren.name/fimd/sec-MCAR.html">“Concepts of MCAR, MAR and MNAR”</a> section of <span class="citation" data-cites="vanbuuren2018">Van Buuren (2018)</span>’s <em>Flexible Imputation of Missing Data</em> to help make sense of the differences<sup>2</sup>.</p>
<p>The plots below illustrate how the different missing data mechanisms might impact a variable’s distribution.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true" href="">Original Data</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false" href="">MCAR</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-3-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-3" aria-controls="tabset-1-3" aria-selected="false" href="">MAR</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-4-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-4" aria-controls="tabset-1-4" aria-selected="false" href="">MNAR</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">plot_satisfaction <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb2-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data) {</span>
<span id="cb2-3">    data <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-4">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(</span>
<span id="cb2-5">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> years_at_company,</span>
<span id="cb2-6">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> forcats<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct_rev</span>(job_satisfaction)</span>
<span id="cb2-7">      )) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb2-8">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_histogram</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">binwidth =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb2-9">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_hline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">yintercept =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb2-10">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_fill_manual</span>(</span>
<span id="cb2-11">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#6C9ABA"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#B0C8DC"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#F2F9FF"</span>),</span>
<span id="cb2-12">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> snakecase<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>to_title_case</span>
<span id="cb2-13">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb2-14">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb2-15">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Years at Company"</span>,</span>
<span id="cb2-16">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb2-17">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson  |  Data: IBM Watson Analytics Lab"</span></span>
<span id="cb2-18">      )</span>
<span id="cb2-19">  }</span>
<span id="cb2-20"></span>
<span id="cb2-21">attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-22">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_satisfaction</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb2-23">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb2-24">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"No Missing Data"</span>,</span>
<span id="cb2-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb2-26">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb2-27">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The distribution of Years at Company, conditional on Job Satisfaction, "</span>,</span>
<span id="cb2-28">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"with no missing data."</span></span>
<span id="cb2-29">      ),</span>
<span id="cb2-30">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb2-31">    )</span>
<span id="cb2-32">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/index_files/figure-html/original-dist-1.png" class="img-fluid figure-img" alt="A histogram visualising the distribution of the total years that employees have worked at their company, conditional on their job satisfaction, without any missing data. The distribution is right-skewed, with the majority of employees' tenures falling below ten years, but some employees working at their company for up to 40 years. " width="672"></p>
</figure>
</div>
</div>
</div>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb3-2"></span>
<span id="cb3-3">attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb3-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">years_at_company =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace</span>(</span>
<span id="cb3-6">      years_at_company,</span>
<span id="cb3-7">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>,</span>
<span id="cb3-8">      <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb3-9">    )</span>
<span id="cb3-10">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_satisfaction</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb3-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Missing Completely at Random (MCAR)"</span>,</span>
<span id="cb3-14">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb3-15">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb3-16">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The distribution of Years at Company, conditional on Job Satisfaction, "</span>,</span>
<span id="cb3-17">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"when Years at Company has been transformed to NA, at random, for 50% "</span>,</span>
<span id="cb3-18">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"of all employees."</span></span>
<span id="cb3-19">      ),</span>
<span id="cb3-20">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb3-21">    )</span>
<span id="cb3-22">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/index_files/figure-html/mcar-dist-1.png" class="img-fluid figure-img" alt="A histogram visualising the distribution of the total years that employees have worked at their company, conditional on their job satisfaction, with MCAR data. The shape of the distribution is similar to the original data distribution. " width="672"></p>
</figure>
</div>
</div>
</div>
</div>
<div id="tabset-1-3" class="tab-pane" aria-labelledby="tabset-1-3-tab">
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb4-2"></span>
<span id="cb4-3">attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb4-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">years_at_company =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace</span>(</span>
<span id="cb4-6">      years_at_company,</span>
<span id="cb4-7">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> job_satisfaction <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Low"</span>,</span>
<span id="cb4-8">      <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb4-9">    )</span>
<span id="cb4-10">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_satisfaction</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb4-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb4-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Missing at Random (MAR)"</span>,</span>
<span id="cb4-14">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb4-15">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb4-16">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The distribution of Years at Company, grouped by Job satisfaction, "</span>,</span>
<span id="cb4-17">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"when employee tenure has been transformed to NA, at random, for "</span>,</span>
<span id="cb4-18">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"80% of all employees with low job satisfaction."</span></span>
<span id="cb4-19">      ),</span>
<span id="cb4-20">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb4-21">    )</span>
<span id="cb4-22">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/index_files/figure-html/mar-dist-1.png" class="img-fluid figure-img" alt="A histogram visualising the distribution of the total years that employees have worked at their company, conditional on their job satisfaction, with MAR data. The shape of the distribution is similar to the original data distribution, but the share of employees with low job satisfaction is significantly lower across the whole distribution. " width="672"></p>
</figure>
</div>
</div>
</div>
</div>
<div id="tabset-1-4" class="tab-pane" aria-labelledby="tabset-1-4-tab">
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1">attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb5-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">years_at_company =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace</span>(</span>
<span id="cb5-4">      years_at_company,</span>
<span id="cb5-5">      <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">between</span>(years_at_company, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>),</span>
<span id="cb5-6">      <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb5-7">    )</span>
<span id="cb5-8">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb5-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_satisfaction</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb5-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Missing Not at Random (MNAR)"</span>,</span>
<span id="cb5-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb5-13">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb5-14">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The distribution of Years at Company, conditional on Job Satisfaction, "</span>,</span>
<span id="cb5-15">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"when Years at Company has been transformed to NA for all employees "</span>,</span>
<span id="cb5-16">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"with less than five or more than thirty years at the company."</span></span>
<span id="cb5-17">      ),</span>
<span id="cb5-18">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb5-19">    )</span>
<span id="cb5-20">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/index_files/figure-html/mnar-dist-1.png" class="img-fluid figure-img" alt="A histogram visualising the distribution of the total years that employees have worked at their company, conditional on their job satisfaction, with MNAR data. The shape of the distribution is even more right-skewed than the original data distribution, with the largest bar being the furthest left bar. The distribution has a smaller range, with 5 being the minimum and 30 being the maximum. " width="672"></p>
</figure>
</div>
</div>
</div>
</div>
</div>
</div>
<p>The type of missing data you’re dealing with can significantly impact a variable’s distribution and bias your precious estimates. The extent of the problem depends on the missing data mechanism and the amount of missingness. Data that is MCAR provides more flexibility than data that is MAR. If you catch wind of MNAR data, you are in real trouble.</p>
</section>
<section id="diagnosing-mechanisms" class="level2">
<h2 class="anchored" data-anchor-id="diagnosing-mechanisms">Diagnosing Mechanisms</h2>
<p>Finding missing data is the first step, but understanding why it is missing matters most. I recognise I’m arguing in favour of creating more work for yourself, but there is good news - it is also hard to identify the missing data mechanism. The mechanism will not be explicitly detailed as it has been for the plots in Section&nbsp;2. In the wild, you can’t observe the missing values or the population distribution for comparison, so you won’t be able to identify the source of your missing values conclusively.</p>
<p>To make matters worse, it is not possible to conclusively define the missing data mechanism because you cannot observe the missing values or the population distribution the observed values came from. It’s not that I’m saying it is guesswork. But I’m not <strong>not</strong> saying that it’s guesswork…<sup>3</sup></p>
<section id="exploring-missing-data" class="level3">
<h3 class="anchored" data-anchor-id="exploring-missing-data">Exploring Missing Data</h3>
<p>There are lots of good resources for learning how to effectively diagnose the missing data mechanism, so in the interest of not turning this blog post into a tome, I won’t go into incredible detail about this process. <span class="citation" data-cites="tierney2022">Tierney and Horst (2022)</span>’s <a href="https://tmb.njtierney.com/"><em>The Missing Book</em></a> is fantastic for learning about the missing data exploratory analysis workflow using the R package <a href="https://naniar.njtierney.com/"><strong>naniar</strong></a><sup>4</sup>. The <a href="https://amices.org/mice/"><strong>mice</strong></a> and <a href="https://amices.org/ggmice/"><strong>ggmice</strong></a> R packages offer additional functionality for investigating missingess<sup>5</sup>. Instead of detailing an entire exploratory workflow, I will give a brief overview, with example plots<sup>6</sup>. While not exhaustive, it will hopefully serve as inspiration to get you started.</p>
<p>I’ve transformed the attrition dataset to include missing data spread across multiple variables. Most missing data is MCAR, but the years an employee has spent at the company is MAR. Missing values for employee tenure are associated with low job satisfaction and high monthly income (greater than $15k per month).</p>
<div class="cell">
<details class="code-fold">
<summary>Data Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb6-2"></span>
<span id="cb6-3">missing_years <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb6-4">  attrition <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb6-6">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(</span>
<span id="cb6-7">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"job"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>job_satisfaction,</span>
<span id="cb6-8">      <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace</span>(.x, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>)</span>
<span id="cb6-9">    ),</span>
<span id="cb6-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">years_at_company =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace</span>(</span>
<span id="cb6-11">      years_at_company,</span>
<span id="cb6-12">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.75</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span></span>
<span id="cb6-13">        (job_satisfaction <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Low"</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> monthly_income <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15000</span>),</span>
<span id="cb6-14">      <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb6-15">    ),</span>
<span id="cb6-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">relationship_satisfaction =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace</span>(</span>
<span id="cb6-17">      relationship_satisfaction,</span>
<span id="cb6-18">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.075</span>,</span>
<span id="cb6-19">      <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb6-20">    ),</span>
<span id="cb6-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">work_life_balance =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace</span>(work_life_balance, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>)</span>
<span id="cb6-22">  )</span></code></pre></div></div>
</details>
</div>
<p>The starting point in any exploratory analysis of missing data is to get some idea of the quantity of missingness and where it is. The plot below<sup>7</sup> summarises the missingness in the attrition dataset.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1">missing_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">everything</span>(), <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(.x)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>())) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-3">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(</span>
<span id="cb7-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">everything</span>(),</span>
<span id="cb7-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"variable"</span>,</span>
<span id="cb7-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span></span>
<span id="cb7-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb7-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">variable =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_to_title</span>(</span>
<span id="cb7-11">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_replace_all</span>(variable, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span>)</span>
<span id="cb7-12">    ),</span>
<span id="cb7-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">variable =</span> forcats<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct_reorder</span>(variable, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>value, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.desc =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb7-14">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb7-15">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> variable, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> value)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_col</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(variable) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-17">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_text</span>(</span>
<span id="cb7-18">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(</span>
<span id="cb7-19">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste0</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%2.1f"</span>, value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%"</span>),</span>
<span id="cb7-20">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">03</span>,</span>
<span id="cb7-21">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">if_else</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">03</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb7-22">    ),</span>
<span id="cb7-23">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>,</span>
<span id="cb7-24">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fontface =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bold"</span>,</span>
<span id="cb7-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span></span>
<span id="cb7-26">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-27">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_hline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">yintercept =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-28">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coord_flip</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-29">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_discrete</span>(</span>
<span id="cb7-30">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb7-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_wrap</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>)</span>
<span id="cb7-32">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-33">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_y_continuous</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">guide =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"none"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">expand =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-03</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-03</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-34">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_fill_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey50"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">guide =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"none"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-35">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_colour_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">guide =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"none"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-36">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb7-37">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Proportion of Values Missing for All Variables"</span>,</span>
<span id="cb7-38">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb7-39">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb7-40">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The percentage of missing values for variables that contain "</span>,</span>
<span id="cb7-41">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"missingness. Relationship Satisfaction and Work Life Balance contain "</span>,</span>
<span id="cb7-42">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"significant missing values, but Years at Company has ~3x as many as "</span>,</span>
<span id="cb7-43">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"any other variable."</span></span>
<span id="cb7-44">      ),</span>
<span id="cb7-45">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">93</span></span>
<span id="cb7-46">    ),</span>
<span id="cb7-47">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson  |  Data: IBM Watson Analytics Lab"</span></span>
<span id="cb7-48">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-49">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span>(</span>
<span id="cb7-50">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.subtitle =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)),</span>
<span id="cb7-51">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb7-52">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>,</span>
<span id="cb7-53">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>),</span>
<span id="cb7-54">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>,</span>
<span id="cb7-55">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>),</span>
<span id="cb7-56">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lineheight =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb7-57">    ),</span>
<span id="cb7-58">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>()</span>
<span id="cb7-59">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/index_files/figure-html/percent-missing-1.png" class="img-fluid figure-img" alt="A bar chart visualising the proportion of missing values for each variable, excluding any variables that do not have any missing values. There are six variables with missing values - years at company (21%), relationship satisfaction (7.1%), work life balance (5.2%), job role (1.1%), job level (0.9%), and job involvement (0.7%). " width="672"></p>
</figure>
</div>
</div>
</div>
<p>Having already detailed what I did when adding missingness to the data, I feel a little silly not just visualising this but now describing the results. It turns out that there are a bunch of missing values spread across six variables, but the biggest culprit is an employee’s tenure at the company. Astonishing. Whoever could have predicted this?</p>
<p>A rigorous analysis would look at each variable and diagnose the mechanism driving the missingness. Given I’m the underlying cause for all missing values, we will take the shortcut and focus on employee tenure.</p>
</section>
<section id="assume-mar-test-mnarmcar" class="level3">
<h3 class="anchored" data-anchor-id="assume-mar-test-mnarmcar">Assume MAR; Test MNAR/MCAR</h3>
<p>Generally speaking, MCAR data is rare. Missing values can occur for many reasons, and the likelihood that the cause is independent of all other variables is low.</p>
<p>It is more plausible that the data is either MAR or MNAR <span class="citation" data-cites="nahhas2024">(Nahhas 2024)</span>. However, dealing with MNAR data is particularly complicated<sup>8</sup>. It is reasonable to assume your data is MAR until you find enough evidence to suggest otherwise (in either direction).</p>
<p>In practice, identifying the type of missingness you’re dealing with requires exploratory analysis, domain expertise, and good judgment. Testing the assumption that your data is not MNAR involves exploring missing values and looking for evidence that missingness may not be random. For example, observed values may be constrained at a value lower than your expertise suggests should be the maximum, indicating some censoring of the variable. Simple summary functions and plotting distributions can uncover evidence that missing values are non-random. However, concluding that data is MNAR requires domain expertise and a good understanding of your data.</p>
<p>It is a little easier to test the assumption data is not MCAR because any association between observed and missing values acts as evidence data is MAR. One way to look for associations is to create a binary variable that represents a variable’s missingness using <code>naniar::bind_shadow()</code> and plotting the distribution of other variables conditional on missingness. Spikes in the distribution of missing values, relative to the distribution of observed values, indicate a correlation between that variable and the missing values.</p>
<p>The plot below visualises the monthly income distribution, conditional on employee tenure’s missingness. A thorough analysis would require digging to find associations, but I’m cheating and already know where to look.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1">missing_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-2">  naniar<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bind_shadow</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(</span>
<span id="cb8-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> monthly_income,</span>
<span id="cb8-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> forcats<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct_rev</span>(years_at_company_NA)</span>
<span id="cb8-6">  )) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb8-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_histogram</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dodge"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb8-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_hline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">yintercept =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb8-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_fill_manual</span>(</span>
<span id="cb8-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Missing"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Not Missing"</span>),</span>
<span id="cb8-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#D93649"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>)</span>
<span id="cb8-12">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb8-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_continuous</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_currency</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb8-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb8-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Years at Company Missingness Distribution"</span>,</span>
<span id="cb8-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb8-17">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb8-18">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The distribution of Monthly Income conditional on the missingness of "</span>,</span>
<span id="cb8-19">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Years at Company. While the distribution of not missing values has a "</span>,</span>
<span id="cb8-20">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"is much larger scale across the majority of the income range, "</span>,</span>
<span id="cb8-21">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"there are more missing values from $15-20k."</span></span>
<span id="cb8-22">      ),</span>
<span id="cb8-23">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb8-24">    ),</span>
<span id="cb8-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Monthly Income"</span>,</span>
<span id="cb8-26">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>,</span>
<span id="cb8-27">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson  |  Data: IBM Watson Analytics Lab"</span></span>
<span id="cb8-28">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/index_files/figure-html/missingness-distribution-1.png" class="img-fluid figure-img" alt="A histogram visualising the distribution of employee monthly income, conditional on whether years at company is missing or not. The histogram shows a distribution in blue, representing the values that are not missing, which is much larger than the red distribution, representing the missing values. While the scale of the distributions differ, the shapes are similar. However, at the highest values of monthly income, over $15,000, there are more missing values than not missing values. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>We expect the missing data distribution to follow a similar pattern to the observed values if it is MCAR. That is more or less the case for the monthly income distribution, but there is a spike at the higher end from around $15-20k. That suggests we might be dealing with MAR data.</p>
<p>We can also use <code>naniar::geom_miss_point()</code> to plot the association between employee tenure and income, and we can facet the data into separate plots for each level of job satisfaction (since we already know that job satisfaction is associated with tenure missingness).</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1">missing_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> years_at_company, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> monthly_income)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-3">  naniar<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_miss_point</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">facet_wrap</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(job_satisfaction)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_colour_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#D93649"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_y_continuous</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_currency</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">guides</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">guide_legend</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">override.aes =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb9-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Years at Company Missingness Associations"</span>,</span>
<span id="cb9-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb9-11">      glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb9-12">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The association between Years at Company and Monthly Income, "</span>,</span>
<span id="cb9-13">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"conditional on Years at Company's missingness and split by Job "</span>,</span>
<span id="cb9-14">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Satisfaction. For low satisfaction, missing values are distributed "</span>,</span>
<span id="cb9-15">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"across all values of monthly income. For all other levels of "</span>,</span>
<span id="cb9-16">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"satisfaction, missing values are clustered between $15k and $20k."</span></span>
<span id="cb9-17">      ),</span>
<span id="cb9-18">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">92</span></span>
<span id="cb9-19">    ),</span>
<span id="cb9-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Years at Company"</span>,</span>
<span id="cb9-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Monthly Income"</span>,</span>
<span id="cb9-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson  |  Data: IBM Watson Analytics Lab"</span></span>
<span id="cb9-23">  )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/index_files/figure-html/missingness-associations-1.png" class="img-fluid figure-img" alt="A grid of four scatter plots showing the association between years at company and monthly income, conditional on whether years at company is missing or not and split by job satisfaction. The four plots show a noisy but positive relationship between years at copany and monthly income, and for medium, high, and very high job satisfaction there is a cluster of missing values between $15000 and $20000. For low job satisfaction, there are much more missing values, making up the majority of the observations in this scatter plot, and they cover the full range of monthly incomes, from below $5000 to $20000. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>While the income distribution indicated that employee tenure might contain missing values that are not MCAR, the above scatter plots provide strong evidence we’re dealing with MAR data. The scatter plots show that missing values are limited to the $15-20k monthly income range, except when job satisfaction is low, where missingness exists across all incomes. The fact that missing values group around specific ranges of observed values indicates that employee tenure’s missing values are not randomly distributed and suggests a relationship between these missing values and monthly income and job satisfaction. These results provide strong evidence that the missingness in the employee tenure variable is <strong>not</strong> MCAR.</p>
<p>It is also possible to compute statistical tests of the association between missing values and the observed values in the data. One option is to model missing values using logistic regression, treating missingness as the binary outcome (using <code>naniar::bind_shadow()</code> as before) and the rest of the dataset as explanatory variables. Table&nbsp;1 shows the outputs from a regression on employee tenure’s missing values. I have rescaled monthly income (and monthly rate) using <code>arm::rescale()</code><sup>9</sup> because it is on a significantly larger scale than other variables, and this makes it difficult to interpret the effect size.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1">missing_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-2">  naniar<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bind_shadow</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(years_at_company_NA <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>years_at_company <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ends_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NA"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb10-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">where</span>(is.factor) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>years_at_company_NA, as.numeric),</span>
<span id="cb10-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">monthly_income =</span> arm<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rescale</span>(monthly_income),</span>
<span id="cb10-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">monthly_rate =</span> arm<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rescale</span>(monthly_rate)</span>
<span id="cb10-8">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glm</span>(years_at_company_NA <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> ., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"binomial"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> _) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Years at Company Missingness"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> _) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-11">  modelsummary<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">modelsummary</span>(</span>
<span id="cb10-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coef_rename =</span> modelsummary<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>coef_rename,</span>
<span id="cb10-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coef_omit =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">19</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">26</span>),</span>
<span id="cb10-14">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">gof_omit =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"IC|Log"</span>,</span>
<span id="cb10-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">exponentiate =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,</span>
<span id="cb10-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stars =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,</span>
<span id="cb10-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">output =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gt"</span></span>
<span id="cb10-18">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb10-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>()</span></code></pre></div></div>
</details>
<div id="tbl-regression" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-regression-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Logistic Regression of Years at Company’s Missing Values
</figcaption>
<div aria-describedby="tbl-regression-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="rkpfyapnbr" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#rkpfyapnbr table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#rkpfyapnbr thead, #rkpfyapnbr tbody, #rkpfyapnbr tfoot, #rkpfyapnbr tr, #rkpfyapnbr td, #rkpfyapnbr th {
  border-style: none;
}

#rkpfyapnbr p {
  margin: 0;
  padding: 0;
}

#rkpfyapnbr .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#rkpfyapnbr .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#rkpfyapnbr .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#rkpfyapnbr .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#rkpfyapnbr .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#rkpfyapnbr .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#rkpfyapnbr .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#rkpfyapnbr .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#rkpfyapnbr .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#rkpfyapnbr .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#rkpfyapnbr .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#rkpfyapnbr .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#rkpfyapnbr .gt_spanner_row {
  border-bottom-style: hidden;
}

#rkpfyapnbr .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#rkpfyapnbr .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#rkpfyapnbr .gt_from_md > :first-child {
  margin-top: 0;
}

#rkpfyapnbr .gt_from_md > :last-child {
  margin-bottom: 0;
}

#rkpfyapnbr .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#rkpfyapnbr .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#rkpfyapnbr .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#rkpfyapnbr .gt_row_group_first td {
  border-top-width: 2px;
}

#rkpfyapnbr .gt_row_group_first th {
  border-top-width: 2px;
}

#rkpfyapnbr .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#rkpfyapnbr .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#rkpfyapnbr .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#rkpfyapnbr .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#rkpfyapnbr .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#rkpfyapnbr .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#rkpfyapnbr .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#rkpfyapnbr .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#rkpfyapnbr .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#rkpfyapnbr .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#rkpfyapnbr .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#rkpfyapnbr .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#rkpfyapnbr .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#rkpfyapnbr .gt_left {
  text-align: left;
}

#rkpfyapnbr .gt_center {
  text-align: center;
}

#rkpfyapnbr .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#rkpfyapnbr .gt_font_normal {
  font-weight: normal;
}

#rkpfyapnbr .gt_font_bold {
  font-weight: bold;
}

#rkpfyapnbr .gt_font_italic {
  font-style: italic;
}

#rkpfyapnbr .gt_super {
  font-size: 65%;
}

#rkpfyapnbr .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#rkpfyapnbr .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#rkpfyapnbr .gt_indent_1 {
  text-indent: 5px;
}

#rkpfyapnbr .gt_indent_2 {
  text-indent: 10px;
}

#rkpfyapnbr .gt_indent_3 {
  text-indent: 15px;
}

#rkpfyapnbr .gt_indent_4 {
  text-indent: 20px;
}

#rkpfyapnbr .gt_indent_5 {
  text-indent: 25px;
}

#rkpfyapnbr .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#rkpfyapnbr div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="a-" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col"></th>
<th id="Years-at-Company-Missingness" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Years at Company Missingness</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers=" ">Distance from Home</td>
<td class="gt_row gt_center" headers="Years at Company Missingness">0.971*</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers=" "></td>
<td class="gt_row gt_center" headers="Years at Company Missingness">(0.013)</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers=" ">Job Satisfaction</td>
<td class="gt_row gt_center" headers="Years at Company Missingness">0.097***</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers=" "></td>
<td class="gt_row gt_center" headers="Years at Company Missingness">(0.015)</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers=" ">Monthly Income</td>
<td class="gt_row gt_center" headers="Years at Company Missingness">52.938***</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers=" "></td>
<td class="gt_row gt_center" headers="Years at Company Missingness">(37.810)</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers=" ">Monthly Rate</td>
<td class="gt_row gt_center" headers="Years at Company Missingness">0.658*</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers=" "></td>
<td class="gt_row gt_center" headers="Years at Company Missingness">(0.139)</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers=" ">Total Working Years</td>
<td class="gt_row gt_center" headers="Years at Company Missingness">1.050+</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers=" " style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000"></td>
<td class="gt_row gt_center" headers="Years at Company Missingness" style="border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #000000">(0.029)</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers=" ">Num.Obs.</td>
<td class="gt_row gt_center" headers="Years at Company Missingness">1261</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers=" ">RMSE</td>
<td class="gt_row gt_center" headers="Years at Company Missingness">0.27</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="2" class="gt_sourcenote" style="text-align: left;">+ p &lt; 0.1, * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001</td>
</tr>
<tr class="even">
<td colspan="2" class="gt_sourcenote" style="text-align: left;">Source: IBM Watson Analytics Lab</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>I have only included statistically significant variables<sup>10</sup>. While this is generally a bad practice, regression tables with 31 variables look like a mess in the middle of a blog post. A narrow focus on p-values is a bad idea in any regression model because effect size tells us a lot more than significance, but in this case, we’re taking some shortcuts. The extremely small p-values for monthly income and job satisfaction indicate that the probability of observing an effect size at least as extreme as our model coefficients if the data was MCAR is small<sup>11</sup>. These results support our assumption that the data is MAR.</p>
<p>Another option is to use <strong>naniar</strong>’s <code>mcar_test()</code> to calculate <span class="citation" data-cites="little1988">Little (1988)</span>’s test statistic for MCAR data<sup>12</sup>. Table&nbsp;2 shows the results of running Little’s MCAR test on our dataset.</p>
<div class="cell">
<style type="text/css">
.rm-striping .gt_table tr.odd {
  --bs-table-striped-bg: transparent;
}
</style>
</div>
<div class="cell rm-striping">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1">missing_years <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-2">  naniar<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcar_test</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">everything</span>(), <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(.x))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(</span>
<span id="cb11-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Test Statistic"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> statistic,</span>
<span id="cb11-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Degrees of Freedom"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df,</span>
<span id="cb11-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P-Value"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> p.value,</span>
<span id="cb11-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Missing Patterns"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> missing.patterns</span>
<span id="cb11-9">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-10">  gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-11">  gt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_align</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tbl_theme</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>)</span></code></pre></div></div>
</details>
<div id="tbl-mcar-test" class="cell rm-striping quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-mcar-test-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;2: Little’s Little MCAR Test
</figcaption>
<div aria-describedby="tbl-mcar-test-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="xkzuydoajn" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#xkzuydoajn table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#xkzuydoajn thead, #xkzuydoajn tbody, #xkzuydoajn tfoot, #xkzuydoajn tr, #xkzuydoajn td, #xkzuydoajn th {
  border-style: none;
}

#xkzuydoajn p {
  margin: 0;
  padding: 0;
}

#xkzuydoajn .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 80%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#xkzuydoajn .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#xkzuydoajn .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#xkzuydoajn .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#xkzuydoajn .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#xkzuydoajn .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#xkzuydoajn .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#xkzuydoajn .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#xkzuydoajn .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#xkzuydoajn .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#xkzuydoajn .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#xkzuydoajn .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#xkzuydoajn .gt_spanner_row {
  border-bottom-style: hidden;
}

#xkzuydoajn .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#xkzuydoajn .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#xkzuydoajn .gt_from_md > :first-child {
  margin-top: 0;
}

#xkzuydoajn .gt_from_md > :last-child {
  margin-bottom: 0;
}

#xkzuydoajn .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#xkzuydoajn .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#xkzuydoajn .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#xkzuydoajn .gt_row_group_first td {
  border-top-width: 2px;
}

#xkzuydoajn .gt_row_group_first th {
  border-top-width: 2px;
}

#xkzuydoajn .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#xkzuydoajn .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#xkzuydoajn .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#xkzuydoajn .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#xkzuydoajn .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#xkzuydoajn .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#xkzuydoajn .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#xkzuydoajn .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#xkzuydoajn .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#xkzuydoajn .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#xkzuydoajn .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#xkzuydoajn .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#xkzuydoajn .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#xkzuydoajn .gt_left {
  text-align: left;
}

#xkzuydoajn .gt_center {
  text-align: center;
}

#xkzuydoajn .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#xkzuydoajn .gt_font_normal {
  font-weight: normal;
}

#xkzuydoajn .gt_font_bold {
  font-weight: bold;
}

#xkzuydoajn .gt_font_italic {
  font-style: italic;
}

#xkzuydoajn .gt_super {
  font-size: 65%;
}

#xkzuydoajn .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#xkzuydoajn .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#xkzuydoajn .gt_indent_1 {
  text-indent: 5px;
}

#xkzuydoajn .gt_indent_2 {
  text-indent: 10px;
}

#xkzuydoajn .gt_indent_3 {
  text-indent: 15px;
}

#xkzuydoajn .gt_indent_4 {
  text-indent: 20px;
}

#xkzuydoajn .gt_indent_5 {
  text-indent: 25px;
}

#xkzuydoajn .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#xkzuydoajn div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell rm-striping caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="Test-Statistic" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Test Statistic</th>
<th id="Degrees-of-Freedom" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Degrees of Freedom</th>
<th id="P-Value" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">P-Value</th>
<th id="Missing-Patterns" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Missing Patterns</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_center" headers="Test Statistic">1052</td>
<td class="gt_row gt_center" headers="Degrees of Freedom">468</td>
<td class="gt_row gt_center" headers="P-Value">0</td>
<td class="gt_row gt_center" headers="Missing Patterns">17</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="4" class="gt_sourcenote" style="text-align: left;">Source: IBM Watson Analytics Lab</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>A high test statistic value and a p-value of zero means we reject the null hypothesis. If the data is MCAR, the probability of observing mean differences as or more extreme than this is very low, suggesting the missing data is either MNAR or MAR. However, there are several limitations to Little’s MCAR test. First, it tests all missing data across the entire dataset instead of testing specific missing patterns. Running logistic regressions on specific missingness is a lot more granular and can be more informative. Second, Little’s MCAR test relies on a slightly backwards approach to hypothesis testing. The null hypothesis is that the data is MCAR. Failing to reject the null is not the same as being able to conclude that the null is true, so it isn’t a test for MCAR data as much as it is a test to reject the hypothesis that the data is MCAR. I’d argue this is fine because the starting assumption is that data is MAR. Little’s MCAR test provides a broad summary of the data. A high p-value suggests further investigation is needed because data might not be MAR, and a low p-value is evidence to support the assumption that the data is MAR. However, I think logistic regressions are more informative, robust, and equally easy to compute, so I would recommend this approach instead.</p>
<p>Finally, another approach to identifying associations between missingness and observed values, which makes fewer assumptions of the data than either modelling approach, is calculating the mean difference of variables conditional on the missingness of the variable in question.</p>
<p>Ultimately, there are no shortcuts in this process. Whichever approach you take, it can only provide supporting evidence, not confirmation. A detailed exploratory analysis combined with domain expertise is the only way to understand how the data may have come to be missing.</p>
</section>
</section>
<section id="well-what-now" class="level2">
<h2 class="anchored" data-anchor-id="well-what-now">Well, What Now?</h2>
<p>There you have it. You now know everything you need to know about missing values. That’s a lie. You know nothing. It’s a vast, overwhelming field full of anguish. All I’ve done is expose you to its existence. Now you will never escape the shame of being flippant about missing data. You’re welcome.</p>
<p>Missing data can have multiple causes, and the mechanism driving missingness can have distinct impacts on data distributions. MNAR and MAR data can seriously bias estimates, while MCAR data is less concerning. For this reason, it is important to understand what is causing missing data. Having (hopefully) convinced you to care about missing data and given you some of the tools needed for identifying its mechanism, the next step is figuring out what to do with it. In the next post in this series, I will discuss solutions to the mess you’ve <del>made</del> found.</p>
</section>




<div id="quarto-appendix" class="default"><section id="acknowledegments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledegments</h2><div class="quarto-appendix-contents">

<p>Many thanks to Camilo Alvarez (of the great Trivote Discord fame) for his kind but constructive feedback during the development of this series of blog posts. I greatly appreciate anyone who helps me be just a little less stupid.</p>
<p>Preview image generated using StabilityAI’s <a href="https://beta.dreamstudio.ai/">DreamStudio</a>, using the prompt “A red milk carton with a missing persons advert on the side of the carton, but instead of a person it is data that is missing”.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>



</div></section><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-gelman2008" class="csl-entry">
Gelman, Andrew. 2008. <span>“Scaling Regression Inputs by Dividing by Two Standard Deviations.”</span> <em>Statistics in Medicine</em> 27 (15): 2865–73.
</div>
<div id="ref-little1988" class="csl-entry">
Little, Roderick JA. 1988. <span>“A Test of Missing Completely at Random for Multivariate Data with Missing Values.”</span> <em>Journal of the American Statistical Association</em> 83 (404): 1198–202.
</div>
<div id="ref-nahhas2024" class="csl-entry">
Nahhas, Ramzi W. 2024. <em>Introduction to Regression Methods for Public Health Using r</em>. <a href="https://bookdown.org/rwnahhas/RMPH/">https://bookdown.org/rwnahhas/RMPH/</a>.
</div>
<div id="ref-rubin1976" class="csl-entry">
Rubin, Donald B. 1976. <span>“Inference and Missing Data.”</span> <em>Biometrika</em> 63 (3): 581–92.
</div>
<div id="ref-scherer2021" class="csl-entry">
Scherer, Cédric. 2021. <em>A Quick How-to on Labelling Bar Graphs in Ggplot2</em>. <a href="https://www.cedricscherer.com/2021/07/05/a-quick-how-to-on-labelling-bar-graphs-in-ggplot2/">https://www.cedricscherer.com/2021/07/05/a-quick-how-to-on-labelling-bar-graphs-in-ggplot2/</a>.
</div>
<div id="ref-scherer2023" class="csl-entry">
Scherer, Cédric. 2023. <em>Yet Another How-to on Labelling Bar Graphs in Ggplot2</em>. <a href="https://www.cedricscherer.com/2023/10/26/yet-another-how-to-on-labelling-bar-graphs-in-ggplot2/">https://www.cedricscherer.com/2023/10/26/yet-another-how-to-on-labelling-bar-graphs-in-ggplot2/</a>.
</div>
<div id="ref-tierney2022" class="csl-entry">
Tierney, Nicholas, and Allison Horst. 2022. <em>The Missing Book</em>. <a href="https://tmb.njtierney.com/">https://tmb.njtierney.com/</a>.
</div>
<div id="ref-vanbuuren2018" class="csl-entry">
Van Buuren, Stef. 2018. <em>Flexible Imputation of Missing Data</em>. CRC Press. <a href="https://stefvanbuuren.name/fimd/">https://stefvanbuuren.name/fimd/</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>However, as <span class="citation" data-cites="tierney2022">Tierney and Horst (2022)</span> noted, data missing completely at random does not mean values are missing for no reason. Something must have caused the missingness, but the missingness is uniformly distributed and unrelated to observed values.↩︎</p></li>
<li id="fn2"><p>I would also recommend the <a href="https://stefvanbuuren.name/fimd/sec-idconcepts.html">“Concepts in Incomplete Data”</a> section of his book if you are looking for more precise definitions of MCAR, MAR, and MNAR data.↩︎</p></li>
<li id="fn3"><p>I am, in fact, not saying that you should be guessing the missing data mechanism. Making evidence-based deductions is not guessing. It’s just uncertain and noisy.↩︎</p></li>
<li id="fn4"><p>The <a href="https://naniar.njtierney.com/articles/getting-started-w-naniar.html">“Getting Started with <strong>naniar</strong>”</a> and <a href="https://naniar.njtierney.com/articles/naniar-visualisation.html">“Gallery of Missing Data Visualisations”</a> vignettes also detail various approaches to exploring missing data.↩︎</p></li>
<li id="fn5"><p><strong>mice</strong>’s <a href="https://www.gerkovink.com/miceVignettes/Missingness_inspection/Missingness_inspection.html">“Missingness Inspection”</a> vignette details an example analysis of missing data.↩︎</p></li>
<li id="fn6"><p>Some plots didn’t use the listed packages but can be easily reproduced using functions from those packages. They won’t be as aesthetically pleasing, but that doesn’t matter for exploratory purposes (it only matters for my silly little blog).↩︎</p></li>
<li id="fn7"><p>Created with the help of Cédric Scherer’s <span class="citation" data-cites="scherer2021 scherer2023">(2021, 2023)</span> excellent guidance on labelling bar plots.↩︎</p></li>
<li id="fn8"><p>It requires specifying a missing data model and doing difficult things like sensitivity analysis <span class="citation" data-cites="vanbuuren2018 nahhas2024">(Van Buuren 2018; Nahhas 2024)</span>.↩︎</p></li>
<li id="fn9"><p>This rescale function standardises variables by centring and dividing their values by two standard deviations <span class="citation" data-cites="gelman2008">(Gelman 2008)</span>.↩︎</p></li>
<li id="fn10"><p>I used <code>coef_omit = c(-7, -16, -18, -19, -26)</code> in <a href="https://modelsummary.com/"><strong>modelsummary</strong></a> to do this because I couldn’t figure out a programmatic way of omitting by significance. If anyone has any idea of a non-manual way to achieve this, I’d love to hear it! I promise I won’t do it on proper regression models.↩︎</p></li>
<li id="fn11"><p>The other significant coefficients will be an artefact of those variables’ association with monthly income and job satisfaction.↩︎</p></li>
<li id="fn12"><p><span class="citation" data-cites="little1988">Little (1988)</span>’s MCAR test tests for mean differences on all variables in the dataset, split by subgroups that share the same missing data pattern. Subgroup observed means are compared against expected means, calculated using the expectation-maximisation algorithm, and this difference forms the basis of the test. The null hypothesis is that the data is MCAR, and the computed test statistic is a chi-squared value.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2024" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2024. <span>“Missing Data Matters (Part I): Mechanisms
.”</span> March 14. <a href="https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/">https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/</a>.
</div></div></section></div> ]]></description>
  <category>Missing Data</category>
  <category>Statistics</category>
  <category>R</category>
  <guid>https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/</guid>
  <pubDate>Thu, 14 Mar 2024 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2024-03-14-missing-data-mechanisms/missing_data.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Setting up Netlify Redirects With Quarto</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2024-03-01-setting-up-netlify-redirects-with-quarto/</link>
  <description><![CDATA[ 





<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>I have updated my process for generating Netlify redirects. If you are interested in an automated process, check out the <a href="../../blog/generating-redirects-with-lua">blog post</a> discussing my updated approach.</p>
</div>
</div>
<p>If you are using Netlify to host your Quarto website there is a ton of helpful functionality that can smooth out the process. They even give you a fancy deployment status badge, and who among us can really claim they’re better than a nice status badge?</p>
<p>One of the features that Netlify offers is a simple process for handling redirects. Whether you need to redirect traffic from old URLs from your previous site URL structure (it’s me) or you want to shorten URLs to make it easier to share links to your blog posts, Netlify’s <code>_redirects</code> <a href="https://www.netlify.com/blog/2019/01/16/redirect-rules-for-all-how-to-configure-redirects-for-your-static-site/">handles all of this very easily</a>.</p>
<p>It’s pretty easy to add a <code>_redirects</code> file to your site if you manually publish from your local machine or link your Netlify site to a Git repository. However, if you have continuous deployment setup with GitHub and/or Netlify or if you want to automate the process of grabbing URLs and generating their redirects (or both), then it’s not immediately obvious how to do this in a painfully manual way with a Quarto website.</p>
<p>There are a few resources out there that will help you figure this out, but my needs were a little different. I had to adapt these guides to fit what I was trying to do, so I thought I’d put a quick explainer together to help others in the same situation.</p>
<section id="standing-on-the-shoulders-of-giants" class="level2">
<h2 class="anchored" data-anchor-id="standing-on-the-shoulders-of-giants">Standing on the Shoulders of Giants</h2>
<p>Much of the process detailed in this blog post has been influenced by or borrowed from other online guides. Rather than try and pitch this as the product of my unique, beautiful mind<sup>1</sup>, I want to give credit where it is due.</p>
<p>These were the resources I found most useful:</p>
<ul>
<li>Danielle Navarro - <a href="https://blog.djnavarro.net/posts/2022-04-20_porting-to-quarto/#netlify-redirects">Porting a Distill Blog to Quarto</a></li>
<li>Silvia Canelón - <a href="https://silviacanelon.com/blog/2023-09-29-hello-quarto/#setting-up-redirects">Hello Quarto: Porting my Website from Hugo Apéro</a></li>
<li>Aster Hu - <a href="https://www.asterhu.com/post/2023-03-30-jekyll-migrating-to-quarto/#build-quarto-from-github-actions-to-netlify">Migrating from Jekyll to Quarto</a></li>
<li>Jadey Ryan - <a href="https://jadeyryan.com/blog/2023-11-19_publish-quarto-website/#configure-continuous-deployment">Intermediate Guide to Publish a Quarto Website with GitHub &amp; Netlify</a></li>
</ul>
<p>These are much more detailed blog posts about creating a website with Quarto, and there’s a lot more good information in these than just setting up redirects. This blog post will have a shorter, more specific focus, but my solution leans heavily on several of these guides, so I want to dish out the appropriate credit right away. I will also try to highlight throughout the post where my code is adapted from one of these resources.</p>
</section>
<section id="setting-up-manual-redirects" class="level2">
<h2 class="anchored" data-anchor-id="setting-up-manual-redirects">Setting Up Manual Redirects</h2>
<p>First, I created a <code>_manualredirects</code> file that I’ve added to the assets directory (following a similar process to Silvia Canelón). It contains all the blog posts I wrote a couple years ago because the old blog used a slightly different URL structure. I’ve also added a couple other pages that no longer exist, and they redirect to either the homepage or other pages that are successors.</p>
<p>I’m sure it would be possible to automate most of this, but I haven’t figured out an easy fix<sup>2</sup>. Wherever you’ve got multiple redirects that don’t follow the same pattern and aren’t going to change in the future (so wherever you’re fixing redirects from an old site or old site structure), it’s probably easier to specify these manually.</p>
<p>Each line in a redirects file refers to a different redirect rule, with the original path listed first, followed by the path being redirected to. Your redirects might look something like this:</p>
<pre><code>/portfolio/                               /projects/
/2023/08/good-but-long-post/              /blog/2023-08-good-but-long-post/
/2023/10/okay-post-that-no-one-needed/    /blog/2023-10-okay-post-that-no-one-needed/
/2024/01/boring-post-you-regret/          /blog/2024-01-boring-post-you-regret/</code></pre>
<p>There are quite a few ways you can customise the behaviour of a redirect rule, and for anything more complex I would recommend reading through the <a href="https://docs.netlify.com/routing/redirects/">Netlify documentation</a>.</p>
</section>
<section id="automating-redirects" class="level2">
<h2 class="anchored" data-anchor-id="automating-redirects">Automating Redirects</h2>
<p>To automate the process of creating a redirects file you need to add some code somewhere that it can be run regularly. I’ve added these code chunks to the <code>index.qmd</code> file in the project root folder, and I’ve added <code>echo: false</code> to the YAML frontmatter so that the code doesn’t appear on my homepage. This is more or less the same process that Danielle Navarro and Silvia Canelón follow, but the difference is that I am not setting <code>freeze: false</code> in the YAML frontmatter (for reasons explained in Section&nbsp;4).</p>
<p>There are multiple sources from which redirect rules will be derived, which requires several steps to bring them together in the <code>_redirects</code> file, but the first step is to import the <code>_manualredirects</code> file.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import redirects</span></span>
<span id="cb2-2">manual_redirects <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> readr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_lines</span>(here<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">here</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"assets"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_manualredirects"</span>))</span></code></pre></div></div>
</div>
<section id="redirecting-blog-posts" class="level3">
<h3 class="anchored" data-anchor-id="redirecting-blog-posts">Redirecting Blog Posts</h3>
<p>Besides making sure no one gets lost in the ether using your old URLs, one of the benefits of redirects is creating shorter URLs that are easier to share. In my case, I’m really just removing the date slug from my blog posts, but this still looks a little neater and is easier to remember.</p>
<p>The code chunk below is also adapted from Silvia Canelón’s process, making a few changes to meet my needs, and it defines a function that gets the file paths to every blog post and then defines redirect rules for each.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># get file paths for all blog posts</span></span>
<span id="cb3-2">get_file_paths <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb3-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(folder) {</span>
<span id="cb3-4">    blog_posts <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb3-5">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list.dirs</span>(</span>
<span id="cb3-6">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">path =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(here<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">here</span>(folder)),</span>
<span id="cb3-7">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">full.names =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb3-8">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">recursive =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb3-9">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-10">      tibble<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tibble_col</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">column_name =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"path"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-11">      dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">folder =</span> folder)</span>
<span id="cb3-12">  }</span>
<span id="cb3-13"></span>
<span id="cb3-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># create &amp; extract shortened redirects</span></span>
<span id="cb3-15">blog_posts <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb3-16">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># get blog post file paths</span></span>
<span id="cb3-17">  purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"blog"</span>, get_file_paths) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-18">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># row-bind file paths</span></span>
<span id="cb3-19">  purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list_rbind</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-20">  dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb3-21">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># remove date slug</span></span>
<span id="cb3-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">blog_title =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_remove</span>(path, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"(?!</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">-)</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">d{4}-</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">d{2}-</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">d{2}-"</span>),</span>
<span id="cb3-23">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># create short path</span></span>
<span id="cb3-24">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">short_path =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste0</span>(folder, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/"</span>, blog_title),</span>
<span id="cb3-25">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># combine old path and new path to create redirect rule</span></span>
<span id="cb3-26">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">redirects =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste0</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/"</span>, short_path, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/"</span>, folder, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/"</span>, path)</span>
<span id="cb3-27">  )</span>
<span id="cb3-28"></span>
<span id="cb3-29">blog_redirects <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb3-30">  blog_posts <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-31">  dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pull</span>(redirects)</span></code></pre></div></div>
</div>
</section>
<section id="redirecting-categories" class="level3">
<h3 class="anchored" data-anchor-id="redirecting-categories">Redirecting Categories</h3>
<p>Another useful trick that is possible using a similar process is redirecting old tags or categories for blog posts. This probably isn’t necessary for my site because I doubt I have written enough posts or drawn enough traffic to my blog posts that the old tags are being used that often, but it is nice to be thorough. This might be more useful to those of you who are a much bigger deal than me!</p>
<p>The code chunk below is adapted from Danielle Navarro’s process, again with some minor adaptations specific to my use case, defining a function to get all categories listed in blog posts<sup>3</sup>, and defines redirect rules by specifying the old (tags) and new paths (categories).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># get categories from blog posts</span></span>
<span id="cb4-2">get_categories <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb4-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(post) {</span>
<span id="cb4-4">    file <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> here<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">here</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"blog"</span>, post) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> fs<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">path</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"index.qmd"</span>)</span>
<span id="cb4-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>fs<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">file_exists</span>(file)) {</span>
<span id="cb4-6">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">character</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span>
<span id="cb4-7">    }</span>
<span id="cb4-8">    file <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-9">      readr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_lines</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-10">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_subset</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^categories:"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-11">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_extract</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">[.*</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">]"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-12">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_remove_all</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">[</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">]]"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-13">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_split</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">", "</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-14">      purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list_c</span>()</span>
<span id="cb4-15">  }</span>
<span id="cb4-16"></span>
<span id="cb4-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># extract categories</span></span>
<span id="cb4-18">categories <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb4-19">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># blog post categories</span></span>
<span id="cb4-20">  purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(blog_posts <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pull</span>(path), get_categories) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-21">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># concatenate categories into a vector</span></span>
<span id="cb4-22">  purrr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list_c</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-23">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unique</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-24">  stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_replace_all</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%20"</span>)</span>
<span id="cb4-25"></span>
<span id="cb4-26"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># extract tags</span></span>
<span id="cb4-27">tags <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb4-28">  categories <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-29">  stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_to_lower</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-30">  stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_replace_all</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%20"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-"</span>)</span>
<span id="cb4-31"></span>
<span id="cb4-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># write category redirects</span></span>
<span id="cb4-33">category_redirects <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb4-34">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste0</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/tags/"</span>, tags, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" "</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/blog/#category="</span>, categories)</span></code></pre></div></div>
</div>
<p>The previous code chunks have compiled all the redirect rules for the site, and most of it uses an automated process. This saves time and limits my opportunities to be an idiot, which I always appreciate.</p>
</section>
<section id="bringing-it-all-together" class="level3">
<h3 class="anchored" data-anchor-id="bringing-it-all-together">Bringing it All Together</h3>
<p>Finally, we can combine everything into a single vector and save this as <code>_redirects</code> in the project root, for reasons that should become clear in just a moment.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># write the _redirects file</span></span>
<span id="cb5-2">readr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">write_lines</span>(</span>
<span id="cb5-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(manual_redirects, blog_redirects, category_redirects),</span>
<span id="cb5-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">file =</span> here<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">here</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_redirects"</span>)</span>
<span id="cb5-5">)</span></code></pre></div></div>
</div>
<p>We now have a <code>_redirects</code> file that contains all the redirect rules we want to use on our site, from manual redirects to automated blog posts and category redirects.</p>
</section>
</section>
<section id="sec-build" class="level2">
<h2 class="anchored" data-anchor-id="sec-build">Including Redirects in Netlify Builds</h2>
<p>The solutions I have used as a reference point all run this code every time the site renders, saving the <code>_redirects</code> file in the <code>_site</code> directory. This works in those cases because they don’t appear to be using continuous deployment. They are pushing the <code>_site</code> directory to GitHub and using this to deploy their website via Netlify. There is nothing wrong with doing it this way, and if you want to save yourself some trouble I’d recommend taking this easier (and probably more sensible) route instead. However, I really like Netlify’s build tools, and there are some Netlify plugins that I want to use.</p>
<p>Given that I want to use continuous deployment, I don’t want to check my <code>_site</code> directory into version control, so I have stored the <code>_redirects</code> file in the root. Instead, I need to move the file to the build directory once everything has been built, which leads me to the other sticking point. I can’t set <code>freeze: false</code> because this will cause the R code to run every time the site is rendered, including when it is being built on Netlify. This would require Netlify to have R installed, and, as far as I am aware, that is not possible. I needed a solution that would freeze all computations and make it possible for Netlify to build the site.</p>
<p>My solution was to save the redirects file to the root and include it as a resource for the build process, by adding <code>resources: _redirects</code> to <code>_quarto.yml</code>, nested under <code>projects</code>. This ensures that when Netlify builds the site, it moves the redirects to your build directory, where Netlify can see it! I have also kept <code>freeze: auto</code> for the file containing the redirects code, to avoid Netlify trying to run it and deployment failing. That means that when Quarto renders the site it stores the results of running these code chunks in the <code>_freeze</code> folder, which needs to be checked into version control so that Netlify can use these outputs.</p>
<p>This is an imperfect solution because freezing this code means that it won’t run unless the source code of the file this code is in changes, which probably won’t happen that often. My solution is to run <code>quarto render index.qmd</code> whenever the redirects need updating. This isn’t ideal, and I’m sure this will result in me forgetting to update the redirects, but I’ve yet to think of a better alternative<sup>4</sup>.</p>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>Netlify offers some valuable features. Netlify’s build tools and redirect capabilities are great, but they don’t necessarily play nice with Quarto, depending on how you want to combine them.</p>
<p>There are guides available online for getting redirects working with Quarto, but things get a little trickier if you want to use continuous deployment with Netlify’s build tools. This post sought to build on the good work others have done and explain how I got redirects working for my particular use case. I suspect there are better ways to approach this. My solution is very much cobbled together. However, it addresses a slightly different problem than the resources I’ve found about setting up Netlify’s redirects with Quarto.</p>
<p>If you have come up with a better way of doing this than me, please let me know!</p>
</section>



<div id="quarto-appendix" class="default"><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>


</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>Please understand that I definitely have a unique, beautiful mind though.↩︎</p></li>
<li id="fn2"><p>I think this should be relatively simple for older blog posts, but for the ad-hoc pages that are being redirected, I think a manual approach is probably the only option.↩︎</p></li>
<li id="fn3"><p>I really like this function. It would have taken me a long time to come up with something much worse than this, so thanks to Danielle for her work!↩︎</p></li>
<li id="fn4"><p>If you have any suggestions, I’d love to hear them.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2024" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2024. <span>“Setting up Netlify Redirects With
Quarto.”</span> March 1. <a href="https://paulrjohnson.net/blog/2024-03-01-setting-up-netlify-redirects-with-quarto/">https://paulrjohnson.net/blog/2024-03-01-setting-up-netlify-redirects-with-quarto/</a>.
</div></div></section></div> ]]></description>
  <category>Netlify</category>
  <category>Quarto</category>
  <category>Web Development</category>
  <category>R</category>
  <guid>https://paulrjohnson.net/blog/2024-03-01-setting-up-netlify-redirects-with-quarto/</guid>
  <pubDate>Fri, 01 Mar 2024 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2024-03-01-setting-up-netlify-redirects-with-quarto/netlify.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Developing Offensive Ratings Using Desirability Functions</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2024-02-22-football-ratings-using-desirability-functions/</link>
  <description><![CDATA[ 





<div class="cell">
<details class="code-fold">
<summary>Setup Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import packages</span></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">suppressPackageStartupMessages</span>({</span>
<span id="cb1-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(dplyr)</span>
<span id="cb1-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(gt)</span>
<span id="cb1-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(showtext)</span>
<span id="cb1-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ggplot2)</span>
<span id="cb1-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(worldfootballR)</span>
<span id="cb1-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(desirability2)</span>
<span id="cb1-9">})</span>
<span id="cb1-10"></span>
<span id="cb1-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># setup fonts</span></span>
<span id="cb1-12">sysfonts<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">font_add_google</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>)</span>
<span id="cb1-13">sysfonts<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">font_add_google</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>)</span>
<span id="cb1-14">showtext<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">showtext_auto</span>()</span>
<span id="cb1-15"></span>
<span id="cb1-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set plot theme</span></span>
<span id="cb1-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># inspired by https://github.com/z3tt/TidyTuesday/blob/main/R/2020_31_PalmerPenguins.Rmd</span></span>
<span id="cb1-18"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_set</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_update</span>(</span>
<span id="cb1-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.major =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb1-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.minor =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb1-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.title.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-23">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-24">      ),</span>
<span id="cb1-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.title.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-26">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">r =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.05</span>)</span>
<span id="cb1-27">      ),</span>
<span id="cb1-28">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey50"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb1-29">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb1-30">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks.length =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unit</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lines"</span>),</span>
<span id="cb1-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"top"</span>,</span>
<span id="cb1-32">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.title =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb1-33">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend.text =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb1-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.title =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-35">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>,</span>
<span id="cb1-36">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-37">    ),</span>
<span id="cb1-38">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.subtitle =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-39">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lora"</span>,</span>
<span id="cb1-40">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lineheight =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.1</span>), </span>
<span id="cb1-41">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb1-42">    ),</span>
<span id="cb1-43">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.title.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plot"</span>,</span>
<span id="cb1-44">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.caption =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb1-45">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey50"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb1-46">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb1-47">    ),</span>
<span id="cb1-48">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.caption.position =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plot"</span>,</span>
<span id="cb1-49">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot.margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb1-50">  )</span>
<span id="cb1-51"></span>
<span id="cb1-52"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># function for creating tables</span></span>
<span id="cb1-53">format_table <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-54">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(data, cols) {</span>
<span id="cb1-55">    data <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-56">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-57">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fmt_number</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> cols, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">decimals =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-58">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_spanner</span>(</span>
<span id="cb1-59">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Desirability Scores"</span>,</span>
<span id="cb1-60">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> cols</span>
<span id="cb1-61">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-62">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cols_align</span>(</span>
<span id="cb1-63">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span>,</span>
<span id="cb1-64">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">columns =</span> cols</span>
<span id="cb1-65">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-66">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_source_note</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source_note =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Source: FBref Via {worldfootballR}"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-67">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_options</span>(</span>
<span id="cb1-68">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.width =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pct</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>),</span>
<span id="cb1-69">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">table.font.names =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poppins"</span></span>
<span id="cb1-70">      ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-71">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tab_style</span>(</span>
<span id="cb1-72">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">align =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"left"</span>),</span>
<span id="cb1-73">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">locations =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_source_notes</span>(), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cells_footnotes</span>())</span>
<span id="cb1-74">      )</span>
<span id="cb1-75">  }</span></code></pre></div></div>
</details>
</div>
<p>Building rating systems for complex, multidimensional contexts is difficult, and the results are often underwhelming. There are many examples of this in sports, where rating systems are common. While many sports have metrics that accurately describe team and player performance in specific contexts, ratings that summarise performance are more limited. Football has expected goals (xG). xG is a relatively accurate proxy for team performance because it describes every team’s primary objective - score more goals than the opponent. However, players help their team achieve this objective in many ways that xG does not capture.</p>
<p>An accurate player rating system would help address this. Performance has multiple components, so rating players is a balancing act. While goals may be the most important part of the game, a player who scored two goals has not necessarily played better than their teammate who contributed a goal and an assist, because player performance is a combination of factors. Player ratings are a multivariate optimisation problem.</p>
<p>In this blog post, I will use a simple but often overlooked method for multivariate optimisation - desirability functions - to develop a rating system for offensive players in football, using data from the big five leagues in the 2022/23 season. The ratings will attempt to identify the best players in Europe in the 2022/23 season because match-level ratings seem less fun (and more difficult).</p>
<p>As someone prone to seeing rabbit holes as a challenge, I have spent far too much time debating what factors should go into player ratings and how to maximise the performance of a rating system, but the focus of this post is on the demonstration of desirability functions. The result is a rating system with plenty of room for improvement, but hopefully, in the process, this post will serve as a brief introduction to desirability functions.</p>
<section id="desirability-functions" class="level2">
<h2 class="anchored" data-anchor-id="desirability-functions">Desirability Functions</h2>
<p>Desirability functions are a method for simultaneously optimising multiple variables <span class="citation" data-cites="kuhn2023 harrington1965 derringer1980">(Kuhn 2023; Harrington 1965; Derringer and Suich 1980)</span>. If you have multiple variables, finding the optimal value of one may take you further away from the optimal value of the others. It is necessary to find an optimal combination of values instead, and desirability functions are a simple solution to this problem <span class="citation" data-cites="kuhn2023">(Kuhn 2023)</span>.</p>
<p>Desirability functions are common in fields like genomics, and they are sometimes used in machine learning to optimise across multiple evaluation metrics or model parameters. The <a href="https://desirability2.tidymodels.org/"><strong>desirability2</strong></a> package is a part of the <a href="https://www.tidymodels.org/"><strong>tidymodels</strong></a> machine learning framework, but it is not limited to optimising evaluation metrics. While there are other ways of approaching this type of task, I like desirability functions for their relative simplicity. They are quick and easy, and they’re pretty simple to explain to non-technical audiences.</p>
<section id="how-desirability-works" class="level3">
<h3 class="anchored" data-anchor-id="how-desirability-works">How Desirability Works</h3>
<p>Desirability functions optimise across multiple variables by mapping each variable onto a standard scale from one (maximally desirable) to zero (unacceptable) using a transformation function<sup>1</sup>, before calculating the weighted combination of these individual scores using the arithmetic or geometric mean<sup>2</sup> and optimising this overall desirability score <span class="citation" data-cites="kuhn2016 kuhn2019 kuhn2023">(Kuhn 2016, 2023; Kuhn and Johnson 2019)</span>.</p>
<p>Mapping each variable to a standard scale makes a direct comparison between variables easier. The transformation function depends on what desirability looks like for each variable. If higher values are more desirable, maximisation would be appropriate, or minimisation when lower values are more desirable. Other transformations are possible, such as a particular target value or a box function that specifies a desirable interval, and there are also mechanisms for making desirability easier or harder to achieve, using scaling features. Having transformed each variable onto a scale where values approaching one are more desirable, the observation that achieves the highest average value of all individual desirability scores is the observation that is the closest to being maximally desirable.</p>
</section>
<section id="the-desirability2-package" class="level3">
<h3 class="anchored" data-anchor-id="the-desirability2-package">The <strong>desirability2</strong> Package</h3>
<p>There are two main groups of functions in the <a href="https://desirability2.tidymodels.org/reference/index.html"><strong>desirability2</strong></a> package - the <a href="https://desirability2.tidymodels.org/reference/inline_desirability.html">transformation functions</a> and the <a href="https://desirability2.tidymodels.org/reference/d_overall.html">overall desirability function</a>.</p>
<p>While the most commonly used transformation functions will be <code>d_max()</code> and <code>d_min()</code>, there are several other transformations (<code>d_target()</code>, <code>d_box()</code>, and <code>d_category()</code>). Where none of these functions are sufficient, <code>d_custom()</code> offers functionality for specifying a custom transformation. Finally, <code>d_overall()</code> calculates the overall desirability score.</p>
<p>All <strong>desirability2</strong> functions can be a part of a typical <a href="https://www.tidyverse.org/"><strong>tidyverse</strong></a> pipeline.</p>
</section>
</section>
<section id="a-rating-system-for-offensive-football-players" class="level2">
<h2 class="anchored" data-anchor-id="a-rating-system-for-offensive-football-players">A Rating System for Offensive Football Players</h2>
<div class="cell">
<details class="code-fold">
<summary>Data Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># get raw data</span></span>
<span id="cb2-2">standard_stats <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb2-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fb_big5_advanced_season_stats</span>(</span>
<span id="cb2-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">season_end_year =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2023</span>,</span>
<span id="cb2-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stat_type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"standard"</span>,</span>
<span id="cb2-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">team_or_player =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"player"</span></span>
<span id="cb2-7">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-8">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>(</span>
<span id="cb2-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb2-10">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Playing"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>,</span>
<span id="cb2-11">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Expected"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>,</span>
<span id="cb2-12">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Progression"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>,</span>
<span id="cb2-13">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PK"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pk"</span>,</span>
<span id="cb2-14">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PKatt"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pk_att"</span>,</span>
<span id="cb2-15">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xG"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xg"</span>,</span>
<span id="cb2-16">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xAG"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xag"</span>,</span>
<span id="cb2-17">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Per_90"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"90"</span>,</span>
<span id="cb2-18">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Per"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"90"</span></span>
<span id="cb2-19">    )</span>
<span id="cb2-20">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb2-22">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(</span>
<span id="cb2-23">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prg"</span>), <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(.x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>mins90, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), </span>
<span id="cb2-24">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.names =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"{.col}90"</span></span>
<span id="cb2-25">      ),</span>
<span id="cb2-26">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">position =</span> stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_split_i</span>(pos, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pattern =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">","</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">i =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-27">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-28">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(player, position, squad, comp, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ends_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"90"</span>))</span>
<span id="cb2-29"></span>
<span id="cb2-30">shooting_stats <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb2-31">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fb_big5_advanced_season_stats</span>(</span>
<span id="cb2-32">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">season_end_year =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2023</span>,</span>
<span id="cb2-33">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stat_type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"shooting"</span>,</span>
<span id="cb2-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">team_or_player =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"player"</span></span>
<span id="cb2-35">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-36">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>(</span>
<span id="cb2-37">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb2-38">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Standard"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>,</span>
<span id="cb2-39">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_per_90"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"90"</span></span>
<span id="cb2-40">      )</span>
<span id="cb2-41">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-42">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(player, squad, sh90)</span>
<span id="cb2-43"></span>
<span id="cb2-44">passing_stats <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb2-45">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fb_big5_advanced_season_stats</span>(</span>
<span id="cb2-46">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">season_end_year =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2023</span>,</span>
<span id="cb2-47">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stat_type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"passing"</span>,</span>
<span id="cb2-48">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">team_or_player =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"player"</span></span>
<span id="cb2-49">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-50">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>(</span>
<span id="cb2-51">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb2-52">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_Expected"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>,</span>
<span id="cb2-53">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xA"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xa"</span></span>
<span id="cb2-54">      )</span>
<span id="cb2-55">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-56">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xa90 =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(xa<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>mins_per_90, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-57">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(player, squad, xa90)</span>
<span id="cb2-58"></span>
<span id="cb2-59">gca_stats <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb2-60">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fb_big5_advanced_season_stats</span>(</span>
<span id="cb2-61">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">season_end_year =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2023</span>, </span>
<span id="cb2-62">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stat_type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gca"</span>, </span>
<span id="cb2-63">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">team_or_player =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"player"</span></span>
<span id="cb2-64">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb2-65">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_SCA"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-66">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(player, squad, sca90)</span>
<span id="cb2-67"></span>
<span id="cb2-68">possession_stats <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb2-69">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fb_big5_advanced_season_stats</span>(</span>
<span id="cb2-70">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">season_end_year =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2023</span>,</span>
<span id="cb2-71">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stat_type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"possession"</span>,</span>
<span id="cb2-72">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">team_or_player =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"player"</span></span>
<span id="cb2-73">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-74">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-75">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pen_touches90 =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(att_pen_touches<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-76">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(player, squad, pen_touches90)</span>
<span id="cb2-77"></span>
<span id="cb2-78"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># join full dataset</span></span>
<span id="cb2-79">big_five_stats <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb2-80">  standard_stats <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-81">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">full_join</span>(shooting_stats) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-82">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">full_join</span>(passing_stats) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-83">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">full_join</span>(gca_stats) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-84">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">full_join</span>(possession_stats) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-85">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-86">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">drop_na</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-87">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(mins90 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> position <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GK"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb2-88">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(</span>
<span id="cb2-89">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">team =</span> squad, </span>
<span id="cb2-90">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">league =</span> comp,</span>
<span id="cb2-91">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">npg90 =</span> g_minus_pk90</span>
<span id="cb2-92">    )</span></code></pre></div></div>
</details>
</div>
<p>Using the excellent <a href="https://jaseziv.github.io/worldfootballR"><strong>worldfootballR</strong></a> package, I have pulled together player-level <a href="https://fbref.com/">FBref</a> data for the 2022/23 season across the big five leagues, for a variety of different offensive measures. The data represents multiple elements of team offense, and in order to capture this, I have split the data into three components - goal threat, chance creation, and ball progression.</p>
<p>Goal threat is made up of four variables, non-penalty goals (npG), non-penalty expected goals (npxG), shots, and touches in the penalty area, while chance creation is comprised of just three - assists, expected assists (xA), and shot-creating actions (SCA). Finally, ball progression is also made up of three variables, progressive passes, carries, and receptions. Every variable in each desirability function is calculated per 90 minutes, to standardise variables by a player’s playing time.</p>
<p>The variables that make up each offensive component, and even the components themselves, are far from exhaustive. There are lots of different variables that could (and probably should) be included, and other aspects of a football team’s offense, like the defensive contributions made by offensive players higher up the pitch, would lead to a more precise rating system. However, the variables that make up the desirability functions here should do a reasonably effective job of capturing all three offensive components without overcomplicating things for the purpose of a blog post.</p>
<section id="goal-threat" class="level3">
<h3 class="anchored" data-anchor-id="goal-threat">Goal Threat</h3>
<p>Perhaps it is stating the obvious to even the most “I’m only here for the stats” folks reading this blog post, but scoring goals is a very important part of football. Goals are good. Teams love them. Everyone loves players that do them. So it makes sense to start the rating system with the goal threat component.</p>
<p>The four variables that make up the goal threat desirability function are npG, npxG, shots, and touches in the opponent’s penalty area. All of these variables have relatively clear predictive value when trying to predict goals, though you could also include other variables like average shot distance if you wanted to be more precise. Each variable also has a positive association with performance, so the desirability functions are all seeking to maximise their values.</p>
<p>The two most predictive variables are, perhaps unsurprisingly, npG and npxG, while shots and touches in the opponent’s penalty area are more supplementary. As a result, goals and expected goals have been rescaled to give them greater weight in the overall desirability score, while shots and touches have been rescaled to downweight their value (discussed in greater detail in Section&nbsp;2.1.1). The code for computing the goal threat desirability function is below (<code>d_max()</code> is the function doing all the work) and Table&nbsp;1 shows the top ten players in terms of goal threat.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">goal_threat <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> </span>
<span id="cb3-2">  big_five_stats <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb3-4">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># maximise npg90 &amp; npxg90 with higher scale</span></span>
<span id="cb3-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(</span>
<span id="cb3-6">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(npg90, npxg90),</span>
<span id="cb3-7">      <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_max</span>(.x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">use_data =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>),</span>
<span id="cb3-8">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.names =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"d_{.col}"</span></span>
<span id="cb3-9">      ),</span>
<span id="cb3-10">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># maximise shots90 &amp; pen_touches90 with lower scale</span></span>
<span id="cb3-11">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(</span>
<span id="cb3-12">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(sh90, pen_touches90),</span>
<span id="cb3-13">      <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_max</span>(.x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">use_data =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>),</span>
<span id="cb3-14">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.names =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"d_{.col}"</span></span>
<span id="cb3-15">    ),</span>
<span id="cb3-16">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># overall desirability score for goal scoring</span></span>
<span id="cb3-17">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># tolerance set to 0.1 so that lowest values are not 0</span></span>
<span id="cb3-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">d_goals =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_overall</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"d_"</span>)), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tolerance =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)</span>
<span id="cb3-19">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb3-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(player, position, team, league, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"d_"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb3-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">desc</span>(d_goals)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb3-22">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename_at</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(player<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>league), snakecase<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>to_title_case) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb3-23">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(</span>
<span id="cb3-24">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Non-Penalty Goals"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_npg90,</span>
<span id="cb3-25">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Non-Penalty xG"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_npxg90,</span>
<span id="cb3-26">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Shots"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_sh90,</span>
<span id="cb3-27">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Penalty Area Touches"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_pen_touches90,</span>
<span id="cb3-28">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Overall"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_goals</span>
<span id="cb3-29">  )</span></code></pre></div></div>
</div>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">goal_threat <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb4-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">format_table</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>)</span></code></pre></div></div>
</details>
<div id="tbl-goal-threat" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-goal-threat-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Goal Threat Ratings
</figcaption>
<div aria-describedby="tbl-goal-threat-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="ozpvaopmyc" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#ozpvaopmyc table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#ozpvaopmyc thead, #ozpvaopmyc tbody, #ozpvaopmyc tfoot, #ozpvaopmyc tr, #ozpvaopmyc td, #ozpvaopmyc th {
  border-style: none;
}

#ozpvaopmyc p {
  margin: 0;
  padding: 0;
}

#ozpvaopmyc .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#ozpvaopmyc .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#ozpvaopmyc .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#ozpvaopmyc .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#ozpvaopmyc .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#ozpvaopmyc .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#ozpvaopmyc .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#ozpvaopmyc .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#ozpvaopmyc .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#ozpvaopmyc .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#ozpvaopmyc .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#ozpvaopmyc .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#ozpvaopmyc .gt_spanner_row {
  border-bottom-style: hidden;
}

#ozpvaopmyc .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#ozpvaopmyc .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#ozpvaopmyc .gt_from_md > :first-child {
  margin-top: 0;
}

#ozpvaopmyc .gt_from_md > :last-child {
  margin-bottom: 0;
}

#ozpvaopmyc .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#ozpvaopmyc .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#ozpvaopmyc .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#ozpvaopmyc .gt_row_group_first td {
  border-top-width: 2px;
}

#ozpvaopmyc .gt_row_group_first th {
  border-top-width: 2px;
}

#ozpvaopmyc .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#ozpvaopmyc .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#ozpvaopmyc .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#ozpvaopmyc .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#ozpvaopmyc .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#ozpvaopmyc .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#ozpvaopmyc .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#ozpvaopmyc .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#ozpvaopmyc .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#ozpvaopmyc .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#ozpvaopmyc .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#ozpvaopmyc .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#ozpvaopmyc .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#ozpvaopmyc .gt_left {
  text-align: left;
}

#ozpvaopmyc .gt_center {
  text-align: center;
}

#ozpvaopmyc .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#ozpvaopmyc .gt_font_normal {
  font-weight: normal;
}

#ozpvaopmyc .gt_font_bold {
  font-weight: bold;
}

#ozpvaopmyc .gt_font_italic {
  font-style: italic;
}

#ozpvaopmyc .gt_super {
  font-size: 65%;
}

#ozpvaopmyc .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#ozpvaopmyc .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#ozpvaopmyc .gt_indent_1 {
  text-indent: 5px;
}

#ozpvaopmyc .gt_indent_2 {
  text-indent: 10px;
}

#ozpvaopmyc .gt_indent_3 {
  text-indent: 15px;
}

#ozpvaopmyc .gt_indent_4 {
  text-indent: 20px;
}

#ozpvaopmyc .gt_indent_5 {
  text-indent: 25px;
}

#ozpvaopmyc .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#ozpvaopmyc div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings gt_spanner_row header">
<th rowspan="2" id="Player" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Player</th>
<th rowspan="2" id="Position" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Position</th>
<th rowspan="2" id="Team" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Team</th>
<th rowspan="2" id="League" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">League</th>
<th colspan="5" id="Desirability Scores" class="gt_center gt_columns_top_border gt_column_spanner_outer" data-quarto-table-cell-role="th" scope="colgroup"><span class="gt_column_spanner">Desirability Scores</span></th>
</tr>
<tr class="gt_col_headings even">
<th id="Non-Penalty Goals" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Non-Penalty Goals</th>
<th id="Non-Penalty xG" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Non-Penalty xG</th>
<th id="Shots" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Shots</th>
<th id="Penalty Area Touches" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Penalty Area Touches</th>
<th id="Overall" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Overall</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Erling Haaland</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Manchester City</td>
<td class="gt_row gt_left" headers="League">Premier League</td>
<td class="gt_row gt_center" headers="Non-Penalty Goals">1.00</td>
<td class="gt_row gt_center" headers="Non-Penalty xG">1.00</td>
<td class="gt_row gt_center" headers="Shots">0.90</td>
<td class="gt_row gt_center" headers="Penalty Area Touches">0.85</td>
<td class="gt_row gt_center" headers="Overall">0.93</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Kylian Mbappé</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Paris S-G</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Non-Penalty Goals">0.78</td>
<td class="gt_row gt_center" headers="Non-Penalty xG">0.90</td>
<td class="gt_row gt_center" headers="Shots">1.00</td>
<td class="gt_row gt_center" headers="Penalty Area Touches">1.00</td>
<td class="gt_row gt_center" headers="Overall">0.91</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Victor Osimhen</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Napoli</td>
<td class="gt_row gt_left" headers="League">Serie A</td>
<td class="gt_row gt_center" headers="Non-Penalty Goals">0.80</td>
<td class="gt_row gt_center" headers="Non-Penalty xG">0.77</td>
<td class="gt_row gt_center" headers="Shots">1.00</td>
<td class="gt_row gt_center" headers="Penalty Area Touches">0.88</td>
<td class="gt_row gt_center" headers="Overall">0.86</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Robert Lewandowski</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Barcelona</td>
<td class="gt_row gt_left" headers="League">La Liga</td>
<td class="gt_row gt_center" headers="Non-Penalty Goals">0.60</td>
<td class="gt_row gt_center" headers="Non-Penalty xG">0.97</td>
<td class="gt_row gt_center" headers="Shots">0.96</td>
<td class="gt_row gt_center" headers="Penalty Area Touches">0.83</td>
<td class="gt_row gt_center" headers="Overall">0.83</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Callum Wilson</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Newcastle Utd</td>
<td class="gt_row gt_left" headers="League">Premier League</td>
<td class="gt_row gt_center" headers="Non-Penalty Goals">0.59</td>
<td class="gt_row gt_center" headers="Non-Penalty xG">0.92</td>
<td class="gt_row gt_center" headers="Shots">0.85</td>
<td class="gt_row gt_center" headers="Penalty Area Touches">0.64</td>
<td class="gt_row gt_center" headers="Overall">0.74</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Loïs Openda</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Lens</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Non-Penalty Goals">0.59</td>
<td class="gt_row gt_center" headers="Non-Penalty xG">0.71</td>
<td class="gt_row gt_center" headers="Shots">0.89</td>
<td class="gt_row gt_center" headers="Penalty Area Touches">0.74</td>
<td class="gt_row gt_center" headers="Overall">0.72</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Lautaro Martínez</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Inter</td>
<td class="gt_row gt_left" headers="League">Serie A</td>
<td class="gt_row gt_center" headers="Non-Penalty Goals">0.55</td>
<td class="gt_row gt_center" headers="Non-Penalty xG">0.60</td>
<td class="gt_row gt_center" headers="Shots">0.97</td>
<td class="gt_row gt_center" headers="Penalty Area Touches">0.75</td>
<td class="gt_row gt_center" headers="Overall">0.70</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Karim Benzema</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Real Madrid</td>
<td class="gt_row gt_left" headers="League">La Liga</td>
<td class="gt_row gt_center" headers="Non-Penalty Goals">0.32</td>
<td class="gt_row gt_center" headers="Non-Penalty xG">0.77</td>
<td class="gt_row gt_center" headers="Shots">0.97</td>
<td class="gt_row gt_center" headers="Penalty Area Touches">0.76</td>
<td class="gt_row gt_center" headers="Overall">0.65</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Alexandre Lacazette</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Lyon</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Non-Penalty Goals">0.48</td>
<td class="gt_row gt_center" headers="Non-Penalty xG">0.54</td>
<td class="gt_row gt_center" headers="Shots">0.84</td>
<td class="gt_row gt_center" headers="Penalty Area Touches">0.83</td>
<td class="gt_row gt_center" headers="Overall">0.65</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Christopher Nkunku</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">RB Leipzig</td>
<td class="gt_row gt_left" headers="League">Bundesliga</td>
<td class="gt_row gt_center" headers="Non-Penalty Goals">0.44</td>
<td class="gt_row gt_center" headers="Non-Penalty xG">0.52</td>
<td class="gt_row gt_center" headers="Shots">0.85</td>
<td class="gt_row gt_center" headers="Penalty Area Touches">0.65</td>
<td class="gt_row gt_center" headers="Overall">0.59</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="9" class="gt_sourcenote" style="text-align: left;">Source: FBref Via {worldfootballR}</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>Erling Haaland, Kylian Mbappé, and Victor Osimhen leading the way in Table&nbsp;1 definitely inspires some confidence in this approach! Bar a few exceptions, like Alexandre Lacazette being one of the ten greatest goal threats in Europe at his big old age, the top ten feels pretty reasonable. The player that stands out the most, in part due to how high he is on the list, is Callum Wilson. However, looking back at his numbers last season, it’s more that he had a freak season than that the goal threat desirability score is doing something wonky. I don’t believe Callum Wilson poses the fifth greatest goal threat in the big five leagues, but it’s hard to argue with him being ranked fifth for his production last season.</p>
<p>I was also a little surprised not to see Harry Kane making the top ten, and it turns out he is in 15th. This appears to be because his xG was lower than the players ahead of him, despite him scoring plenty of goals last season. I think Kane’s lower rating raises questions about the decision to weight goals and expected goals equally. A more detailed rating system would need to make a decision about whether the goal is to describe a player’s past performance or identify the best players, which is inherently about predicting future performance. If it is the former, goals should probably be weighted higher, but if it is the latter, then expected goals should probably be favoured.</p>
<section id="sec-scaling" class="level4">
<h4 class="anchored" data-anchor-id="sec-scaling">Scaling Desirability Functions</h4>
<p>Each individual desirability function can be easily adjusted using the scaling feature, <img src="https://latex.codecogs.com/png.latex?s">, which can be increased in order to make maximal desirability harder to reach, and decreased to make it easier. The default value is 1 because <img src="https://latex.codecogs.com/png.latex?s"> is an exponent and a 1 effectively cancels this out. We’re having fun.</p>
<p>In the goal threat desirability function, goals and expected goals have <img src="https://latex.codecogs.com/png.latex?s%20=%202">, while for shots and touches in the opponent’s penalty area <img src="https://latex.codecogs.com/png.latex?s%20=%200.5">. This captures the fact that npG and npxG are very direct measures of goal threat (they are literally the actual goals and the probability of scoring actual goals!), while shots and touches are a lot less direct. I suspect we’d be better served giving shots greater weight in the function than touches, but in the interest of trying my hardest not to get bogged down in the domain context and focus on the method, let’s just give them the same weight.</p>
<p>Given that <img src="https://latex.codecogs.com/png.latex?s"> is the exponent, the scaling feature transforms the desirability function in a non-linear manner. The plot below illustrates how scaling affects desirability.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1">big_five_stats <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb5-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb5-3">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># maximise shots90 without rescaling</span></span>
<span id="cb5-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">no_scale =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_max</span>(sh90, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">use_data =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>),</span>
<span id="cb5-5">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># maximise shots90 with lower scale</span></span>
<span id="cb5-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">easier   =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_max</span>(sh90, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">use_data =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>),</span>
<span id="cb5-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># maximise shots90 with higher scale</span></span>
<span id="cb5-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">harder =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_max</span>(sh90, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">use_data =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb5-9">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb5-10">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(</span>
<span id="cb5-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(no_scale, easier, harder), </span>
<span id="cb5-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"scaling"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span></span>
<span id="cb5-13">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb5-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scaling =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(scaling, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">levels =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"no_scale"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"easier"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"harder"</span>))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb5-15">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> sh90, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> value, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> scaling)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-17">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_colour_manual</span>(</span>
<span id="cb5-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#D93649"</span>),</span>
<span id="cb5-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> snakecase<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>to_title_case</span>
<span id="cb5-21">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-22">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb5-23">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> </span>
<span id="cb5-24">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Scaling Effects on the Desirability Score of Shots/90"</span>,</span>
<span id="cb5-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> </span>
<span id="cb5-26">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb5-27">        glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb5-28">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The unscaled desirability function is a linear transformation of "</span>,</span>
<span id="cb5-29">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"shots per 90, while the rescaled functions are non-linear, with "</span>,</span>
<span id="cb5-30">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"scaling values &gt; 1 making higher desirability more difficult to "</span>,</span>
<span id="cb5-31">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"satisfy and values &lt; 1 making it easier."</span></span>
<span id="cb5-32">          ),</span>
<span id="cb5-33">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb5-34">      ),</span>
<span id="cb5-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Shots/90"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Desirability"</span>,</span>
<span id="cb5-36">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> </span>
<span id="cb5-37">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson  |  Data: FBref Via {worldfootballR}"</span></span>
<span id="cb5-38">    )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-02-22-football-ratings-using-desirability-functions/index_files/figure-html/scaling-shots-1.png" class="img-fluid figure-img" alt="A line plot illustrating the effects of scaling features on desirability functions, using shots per 90 as the example. The plot demonstrates that values greater than 1 make it harder for desirability functions to reach maximal desirability, illustrated using a scaling feature of 5, where lower values are given much lower desirability scores and as values increase desirability increases exponentially. It also demonstrates that values lower than 1 make it easier for desirability functions to reach maximal desirability, illustrated using a scaling feature of 0.2, where lower values are given much higher desirability scores but as values increase desirability does not increase significantly. " width="672"></p>
</figure>
</div>
</div>
</div>
<p>When scaling desirability functions I think it is important to recognise the effects that imposing a non-linear transformation has. Because I’ve used the <code>use_data = TRUE</code> argument in <code>d_max()</code>, the maximum and minimum value in each desirability function is set by the data, meaning that regardless of the scaling applied the maximum value will still be 1 and the minimum value will be 0. However, as the scale increases, this will make it much harder for values to reach higher desirability scores, meaning that lower values of the corresponding variable will be given lower scores, but the non-linearity imposed increases the rate of desirability increases at higher values of the corresponding variable.</p>
<p>It is important to realise that making maximal desirability harder in this non-linear fashion does not downweight the highest values of that variable. Instead, it actually increases the magnitude of those highest values, because so few other observations are similarly high! Therefore, if you want to downweight the value of a particular variable in the overall desirability score, it needs to be easier to reach maximal desirability, because all values of that variable will have a higher score and that will give the highest values less leverage.</p>
<p>I think it is a little difficult to process the exponential effects of <img src="https://latex.codecogs.com/png.latex?s"> in this context. We are primarily interested in the highest values of each desirability function, given that the focus is on building a rating system, and increasing <img src="https://latex.codecogs.com/png.latex?s"> achieves our goals at the top-end of the ratings, but it obviously feels a little wonky to exponentially increase the value of a particular desirability function in order to downweight it in the overall desirability score! I think it is sensible to visualise the effects that your intended scaling will have, so as to help you think through the choices you’re making.</p>
</section>
</section>
<section id="chance-creation" class="level3">
<h3 class="anchored" data-anchor-id="chance-creation">Chance Creation</h3>
<p>If doing goals is the most important part of an offense in football, then helping others do goals must be the next best thing. Which brings us to chance creation. The process for creating a rating system for chance creation is more or less the same as with goal scoring. I’ve selected three variables that will go into the chance creation ratings - assists, expected assists (xA), and shot-creating actions (SCA).</p>
<p>In this case, the SCA desirability function has been scaled to reduce SCA’s effect on the overall score but assists and expected assists are unscaled. While I think that shot-creating actions are not quite as valuable as assists, I don’t want to exponentially increase the value of assists and expected assists at the top end of the desirability score. Goalscoring is the most important part of football, so I think small increases in the per 90 rate of goalscoring should be rewarded greatly, but creating chances, while still very important, is still reliant on the player receiving the ball putting it away, and I think the decisions made here reflect that.</p>
<p>Just as with the goal threat component, the choices I’ve made here are more of an art than a science, and I think I could easily be convinced that the way I’ve structured the desirability functions for chance creation are incorrect. Unfortunately for you, I’m not actually having that debate, so I went ahead and made my own choice. It’s probably wrong. Table&nbsp;2 shows the results of my poor choices, in life and in this blog post.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">chance_creation <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> </span>
<span id="cb6-2">  big_five_stats <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb6-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb6-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(</span>
<span id="cb6-5">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(ast90, xa90),</span>
<span id="cb6-6">      <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_max</span>(.x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">use_data =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>),</span>
<span id="cb6-7">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.names =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"d_{.col}"</span></span>
<span id="cb6-8">      ),</span>
<span id="cb6-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">d_sca90 =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_max</span>(sca90, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">use_data =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>),</span>
<span id="cb6-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">d_chances =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_overall</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"d_"</span>)), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tolerance =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)</span>
<span id="cb6-11">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb6-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(player, position, team, league, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"d_"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb6-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename_at</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(player<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>league), snakecase<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>to_title_case) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb6-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(</span>
<span id="cb6-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Assists"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_ast90,</span>
<span id="cb6-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xA"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_xa90,</span>
<span id="cb6-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SCA"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_sca90,</span>
<span id="cb6-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Overall"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_chances</span>
<span id="cb6-19">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb6-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">desc</span>(Overall))</span></code></pre></div></div>
</div>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1">chance_creation <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb7-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb7-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">format_table</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span></code></pre></div></div>
</details>
<div id="tbl-chance-creation" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-chance-creation-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;2: Chance Creation Ratings
</figcaption>
<div aria-describedby="tbl-chance-creation-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="zpvkdvbvst" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#zpvkdvbvst table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#zpvkdvbvst thead, #zpvkdvbvst tbody, #zpvkdvbvst tfoot, #zpvkdvbvst tr, #zpvkdvbvst td, #zpvkdvbvst th {
  border-style: none;
}

#zpvkdvbvst p {
  margin: 0;
  padding: 0;
}

#zpvkdvbvst .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#zpvkdvbvst .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#zpvkdvbvst .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#zpvkdvbvst .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#zpvkdvbvst .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#zpvkdvbvst .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#zpvkdvbvst .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#zpvkdvbvst .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#zpvkdvbvst .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#zpvkdvbvst .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#zpvkdvbvst .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#zpvkdvbvst .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#zpvkdvbvst .gt_spanner_row {
  border-bottom-style: hidden;
}

#zpvkdvbvst .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#zpvkdvbvst .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#zpvkdvbvst .gt_from_md > :first-child {
  margin-top: 0;
}

#zpvkdvbvst .gt_from_md > :last-child {
  margin-bottom: 0;
}

#zpvkdvbvst .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#zpvkdvbvst .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#zpvkdvbvst .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#zpvkdvbvst .gt_row_group_first td {
  border-top-width: 2px;
}

#zpvkdvbvst .gt_row_group_first th {
  border-top-width: 2px;
}

#zpvkdvbvst .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#zpvkdvbvst .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#zpvkdvbvst .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#zpvkdvbvst .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#zpvkdvbvst .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#zpvkdvbvst .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#zpvkdvbvst .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#zpvkdvbvst .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#zpvkdvbvst .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#zpvkdvbvst .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#zpvkdvbvst .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#zpvkdvbvst .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#zpvkdvbvst .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#zpvkdvbvst .gt_left {
  text-align: left;
}

#zpvkdvbvst .gt_center {
  text-align: center;
}

#zpvkdvbvst .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#zpvkdvbvst .gt_font_normal {
  font-weight: normal;
}

#zpvkdvbvst .gt_font_bold {
  font-weight: bold;
}

#zpvkdvbvst .gt_font_italic {
  font-style: italic;
}

#zpvkdvbvst .gt_super {
  font-size: 65%;
}

#zpvkdvbvst .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#zpvkdvbvst .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#zpvkdvbvst .gt_indent_1 {
  text-indent: 5px;
}

#zpvkdvbvst .gt_indent_2 {
  text-indent: 10px;
}

#zpvkdvbvst .gt_indent_3 {
  text-indent: 15px;
}

#zpvkdvbvst .gt_indent_4 {
  text-indent: 20px;
}

#zpvkdvbvst .gt_indent_5 {
  text-indent: 25px;
}

#zpvkdvbvst .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#zpvkdvbvst div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings gt_spanner_row header">
<th rowspan="2" id="Player" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Player</th>
<th rowspan="2" id="Position" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Position</th>
<th rowspan="2" id="Team" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Team</th>
<th rowspan="2" id="League" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">League</th>
<th colspan="4" id="Desirability Scores" class="gt_center gt_columns_top_border gt_column_spanner_outer" data-quarto-table-cell-role="th" scope="colgroup"><span class="gt_column_spanner">Desirability Scores</span></th>
</tr>
<tr class="gt_col_headings even">
<th id="Assists" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Assists</th>
<th id="xA" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">xA</th>
<th id="SCA" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">SCA</th>
<th id="Overall" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Overall</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Kevin De Bruyne</td>
<td class="gt_row gt_left" headers="Position">MF</td>
<td class="gt_row gt_left" headers="Team">Manchester City</td>
<td class="gt_row gt_left" headers="League">Premier League</td>
<td class="gt_row gt_center" headers="Assists">0.94</td>
<td class="gt_row gt_center" headers="xA">1.00</td>
<td class="gt_row gt_center" headers="SCA">1.00</td>
<td class="gt_row gt_center" headers="Overall">0.98</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Neymar</td>
<td class="gt_row gt_left" headers="Position">MF</td>
<td class="gt_row gt_left" headers="Team">Paris S-G</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Assists">1.00</td>
<td class="gt_row gt_center" headers="xA">0.83</td>
<td class="gt_row gt_center" headers="SCA">0.97</td>
<td class="gt_row gt_center" headers="Overall">0.93</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Lionel Messi</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Paris S-G</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Assists">0.80</td>
<td class="gt_row gt_center" headers="xA">0.98</td>
<td class="gt_row gt_center" headers="SCA">0.98</td>
<td class="gt_row gt_center" headers="Overall">0.91</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Rémy Cabella</td>
<td class="gt_row gt_left" headers="Position">MF</td>
<td class="gt_row gt_left" headers="Team">Lille</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Assists">0.56</td>
<td class="gt_row gt_center" headers="xA">0.83</td>
<td class="gt_row gt_center" headers="SCA">0.99</td>
<td class="gt_row gt_center" headers="Overall">0.77</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Thomas Müller</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Bayern Munich</td>
<td class="gt_row gt_left" headers="League">Bundesliga</td>
<td class="gt_row gt_center" headers="Assists">0.67</td>
<td class="gt_row gt_center" headers="xA">0.73</td>
<td class="gt_row gt_center" headers="SCA">0.84</td>
<td class="gt_row gt_center" headers="Overall">0.74</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Antoine Griezmann</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Atlético Madrid</td>
<td class="gt_row gt_left" headers="League">La Liga</td>
<td class="gt_row gt_center" headers="Assists">0.78</td>
<td class="gt_row gt_center" headers="xA">0.60</td>
<td class="gt_row gt_center" headers="SCA">0.88</td>
<td class="gt_row gt_center" headers="Overall">0.74</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Ousmane Dembélé</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Barcelona</td>
<td class="gt_row gt_left" headers="League">La Liga</td>
<td class="gt_row gt_center" headers="Assists">0.70</td>
<td class="gt_row gt_center" headers="xA">0.62</td>
<td class="gt_row gt_center" headers="SCA">0.91</td>
<td class="gt_row gt_center" headers="Overall">0.73</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Rayan Cherki</td>
<td class="gt_row gt_left" headers="Position">MF</td>
<td class="gt_row gt_left" headers="Team">Lyon</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Assists">0.45</td>
<td class="gt_row gt_center" headers="xA">0.83</td>
<td class="gt_row gt_center" headers="SCA">0.97</td>
<td class="gt_row gt_center" headers="Overall">0.71</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Kingsley Coman</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Bayern Munich</td>
<td class="gt_row gt_left" headers="League">Bundesliga</td>
<td class="gt_row gt_center" headers="Assists">0.50</td>
<td class="gt_row gt_center" headers="xA">0.79</td>
<td class="gt_row gt_center" headers="SCA">0.91</td>
<td class="gt_row gt_center" headers="Overall">0.71</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Raphaël Guerreiro</td>
<td class="gt_row gt_left" headers="Position">DF</td>
<td class="gt_row gt_left" headers="Team">Dortmund</td>
<td class="gt_row gt_left" headers="League">Bundesliga</td>
<td class="gt_row gt_center" headers="Assists">0.73</td>
<td class="gt_row gt_center" headers="xA">0.60</td>
<td class="gt_row gt_center" headers="SCA">0.81</td>
<td class="gt_row gt_center" headers="Overall">0.71</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="8" class="gt_sourcenote" style="text-align: left;">Source: FBref Via {worldfootballR}</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>Again, the names at the top of the Table&nbsp;2 ratings give me confidence, especially the three names at the very top - Kevin De Bruyne, Neymar, and Lionel Messi. I don’t think there are any huge surprises in these ratings, perhaps with the exception of Rémy Cabella, who has some solid to very good creation numbers but wouldn’t necessarily be a name you’d immediately think of when thinking about the ten best creative players in the world. This is once again a reminder that Ligue 1 is very silly but is wonderfully chaotic.</p>
</section>
<section id="ball-progression" class="level3">
<h3 class="anchored" data-anchor-id="ball-progression">Ball Progression</h3>
<p>The final component, and possibly the most interesting of the three, is ball progression. The three variables included in the ball progression desirability function are progressive carries, passes, and receptions. Just as is the case with the previous two components, I’m sure you could include other variables as measures of ball progression, but I’m still too lazy to do that and I think a lot of those other variables would risk double-counting where those actions are picked up by one of the progression metrics.</p>
<p>I am particularly unsure about how to weight the value of progressive actions, especially progressive passing and receptions, which are connected actions. I could see an argument for giving less weight to progressive receptions, and treating carries and passes equally, but I could also see a case that progressive passes and receptions should be treated equally because both the passer and receiver have to do their job to make the progressive action successful. Given my uncertainty about this particular category, I’ve decided it is best to weight all three variables equally.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1">ball_progression <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb8-2">  big_five_stats <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb8-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(</span>
<span id="cb8-5">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prg"</span>),</span>
<span id="cb8-6">      <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_max</span>(.x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">use_data =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>),</span>
<span id="cb8-7">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.names =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"d_{.col}"</span></span>
<span id="cb8-8">    ),</span>
<span id="cb8-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">d_prg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_overall</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"d_"</span>)), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tolerance =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)</span>
<span id="cb8-10">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(player, position, team, league, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"d_"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">desc</span>(d_prg)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb8-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename_at</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(player<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>league), snakecase<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>to_title_case) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb8-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(</span>
<span id="cb8-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Progressive Carrying"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_prg_c90,</span>
<span id="cb8-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Progressive Passing"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_prg_p90,</span>
<span id="cb8-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Progressive Receptions"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_prg_r90,</span>
<span id="cb8-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Overall"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> d_prg</span>
<span id="cb8-19">  )</span></code></pre></div></div>
</div>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1">ball_progression <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">format_table</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span></code></pre></div></div>
</details>
<div id="tbl-ball-progression" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-ball-progression-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;3: Ball Progression Ratings
</figcaption>
<div aria-describedby="tbl-ball-progression-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="cwnrqjcssx" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#cwnrqjcssx table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#cwnrqjcssx thead, #cwnrqjcssx tbody, #cwnrqjcssx tfoot, #cwnrqjcssx tr, #cwnrqjcssx td, #cwnrqjcssx th {
  border-style: none;
}

#cwnrqjcssx p {
  margin: 0;
  padding: 0;
}

#cwnrqjcssx .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#cwnrqjcssx .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#cwnrqjcssx .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#cwnrqjcssx .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#cwnrqjcssx .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#cwnrqjcssx .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#cwnrqjcssx .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#cwnrqjcssx .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#cwnrqjcssx .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#cwnrqjcssx .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#cwnrqjcssx .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#cwnrqjcssx .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#cwnrqjcssx .gt_spanner_row {
  border-bottom-style: hidden;
}

#cwnrqjcssx .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#cwnrqjcssx .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#cwnrqjcssx .gt_from_md > :first-child {
  margin-top: 0;
}

#cwnrqjcssx .gt_from_md > :last-child {
  margin-bottom: 0;
}

#cwnrqjcssx .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#cwnrqjcssx .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#cwnrqjcssx .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#cwnrqjcssx .gt_row_group_first td {
  border-top-width: 2px;
}

#cwnrqjcssx .gt_row_group_first th {
  border-top-width: 2px;
}

#cwnrqjcssx .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#cwnrqjcssx .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#cwnrqjcssx .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#cwnrqjcssx .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#cwnrqjcssx .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#cwnrqjcssx .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#cwnrqjcssx .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#cwnrqjcssx .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#cwnrqjcssx .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#cwnrqjcssx .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#cwnrqjcssx .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#cwnrqjcssx .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#cwnrqjcssx .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#cwnrqjcssx .gt_left {
  text-align: left;
}

#cwnrqjcssx .gt_center {
  text-align: center;
}

#cwnrqjcssx .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#cwnrqjcssx .gt_font_normal {
  font-weight: normal;
}

#cwnrqjcssx .gt_font_bold {
  font-weight: bold;
}

#cwnrqjcssx .gt_font_italic {
  font-style: italic;
}

#cwnrqjcssx .gt_super {
  font-size: 65%;
}

#cwnrqjcssx .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#cwnrqjcssx .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#cwnrqjcssx .gt_indent_1 {
  text-indent: 5px;
}

#cwnrqjcssx .gt_indent_2 {
  text-indent: 10px;
}

#cwnrqjcssx .gt_indent_3 {
  text-indent: 15px;
}

#cwnrqjcssx .gt_indent_4 {
  text-indent: 20px;
}

#cwnrqjcssx .gt_indent_5 {
  text-indent: 25px;
}

#cwnrqjcssx .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#cwnrqjcssx div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings gt_spanner_row header">
<th rowspan="2" id="Player" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Player</th>
<th rowspan="2" id="Position" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Position</th>
<th rowspan="2" id="Team" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Team</th>
<th rowspan="2" id="League" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">League</th>
<th colspan="4" id="Desirability Scores" class="gt_center gt_columns_top_border gt_column_spanner_outer" data-quarto-table-cell-role="th" scope="colgroup"><span class="gt_column_spanner">Desirability Scores</span></th>
</tr>
<tr class="gt_col_headings even">
<th id="Progressive Carrying" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Progressive Carrying</th>
<th id="Progressive Passing" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Progressive Passing</th>
<th id="Progressive Receptions" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Progressive Receptions</th>
<th id="Overall" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Overall</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Rayan Cherki</td>
<td class="gt_row gt_left" headers="Position">MF</td>
<td class="gt_row gt_left" headers="Team">Lyon</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.81</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.50</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.66</td>
<td class="gt_row gt_center" headers="Overall">0.64</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Kingsley Coman</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Bayern Munich</td>
<td class="gt_row gt_left" headers="League">Bundesliga</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.79</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.31</td>
<td class="gt_row gt_center" headers="Progressive Receptions">1.00</td>
<td class="gt_row gt_center" headers="Overall">0.62</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Ousmane Dembélé</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Barcelona</td>
<td class="gt_row gt_left" headers="League">La Liga</td>
<td class="gt_row gt_center" headers="Progressive Carrying">1.00</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.33</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.71</td>
<td class="gt_row gt_center" headers="Overall">0.61</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Jack Grealish</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Manchester City</td>
<td class="gt_row gt_left" headers="League">Premier League</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.79</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.30</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.72</td>
<td class="gt_row gt_center" headers="Overall">0.56</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Kevin De Bruyne</td>
<td class="gt_row gt_left" headers="Position">MF</td>
<td class="gt_row gt_left" headers="Team">Manchester City</td>
<td class="gt_row gt_left" headers="League">Premier League</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.47</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.67</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.48</td>
<td class="gt_row gt_center" headers="Overall">0.53</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Kylian Mbappé</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Paris S-G</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.67</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.28</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.79</td>
<td class="gt_row gt_center" headers="Overall">0.53</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Rémy Cabella</td>
<td class="gt_row gt_left" headers="Position">MF</td>
<td class="gt_row gt_left" headers="Team">Lille</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.51</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.60</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.46</td>
<td class="gt_row gt_center" headers="Overall">0.52</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Neymar</td>
<td class="gt_row gt_left" headers="Position">MF</td>
<td class="gt_row gt_left" headers="Team">Paris S-G</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.51</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.69</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.39</td>
<td class="gt_row gt_center" headers="Overall">0.52</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Raphinha</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Barcelona</td>
<td class="gt_row gt_left" headers="League">La Liga</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.53</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.31</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.78</td>
<td class="gt_row gt_center" headers="Overall">0.51</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Vinicius Júnior</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Real Madrid</td>
<td class="gt_row gt_left" headers="League">La Liga</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.89</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.17</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.84</td>
<td class="gt_row gt_center" headers="Overall">0.51</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="8" class="gt_sourcenote" style="text-align: left;">Source: FBref Via {worldfootballR}</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>Forwards dominated the first two components but Table&nbsp;3 is more diverse. This is to be expected, given that ball progression is often about moving the ball up the pitch to the forwards! Table&nbsp;4 aggregates the ball progression desirability scores by position.</p>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1">ball_progression <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb10-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">where</span>(is.numeric), mean), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.by =</span> Position) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb10-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">desc</span>(Overall)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb10-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">format_table</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div></div>
</details>
<div id="tbl-position-progression" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-position-progression-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;4: Ball Progression Desirability by Position
</figcaption>
<div aria-describedby="tbl-position-progression-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="erxyvnafjo" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#erxyvnafjo table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#erxyvnafjo thead, #erxyvnafjo tbody, #erxyvnafjo tfoot, #erxyvnafjo tr, #erxyvnafjo td, #erxyvnafjo th {
  border-style: none;
}

#erxyvnafjo p {
  margin: 0;
  padding: 0;
}

#erxyvnafjo .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#erxyvnafjo .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#erxyvnafjo .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#erxyvnafjo .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#erxyvnafjo .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#erxyvnafjo .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#erxyvnafjo .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#erxyvnafjo .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#erxyvnafjo .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#erxyvnafjo .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#erxyvnafjo .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#erxyvnafjo .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#erxyvnafjo .gt_spanner_row {
  border-bottom-style: hidden;
}

#erxyvnafjo .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#erxyvnafjo .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#erxyvnafjo .gt_from_md > :first-child {
  margin-top: 0;
}

#erxyvnafjo .gt_from_md > :last-child {
  margin-bottom: 0;
}

#erxyvnafjo .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#erxyvnafjo .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#erxyvnafjo .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#erxyvnafjo .gt_row_group_first td {
  border-top-width: 2px;
}

#erxyvnafjo .gt_row_group_first th {
  border-top-width: 2px;
}

#erxyvnafjo .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#erxyvnafjo .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#erxyvnafjo .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#erxyvnafjo .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#erxyvnafjo .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#erxyvnafjo .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#erxyvnafjo .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#erxyvnafjo .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#erxyvnafjo .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#erxyvnafjo .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#erxyvnafjo .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#erxyvnafjo .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#erxyvnafjo .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#erxyvnafjo .gt_left {
  text-align: left;
}

#erxyvnafjo .gt_center {
  text-align: center;
}

#erxyvnafjo .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#erxyvnafjo .gt_font_normal {
  font-weight: normal;
}

#erxyvnafjo .gt_font_bold {
  font-weight: bold;
}

#erxyvnafjo .gt_font_italic {
  font-style: italic;
}

#erxyvnafjo .gt_super {
  font-size: 65%;
}

#erxyvnafjo .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#erxyvnafjo .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#erxyvnafjo .gt_indent_1 {
  text-indent: 5px;
}

#erxyvnafjo .gt_indent_2 {
  text-indent: 10px;
}

#erxyvnafjo .gt_indent_3 {
  text-indent: 15px;
}

#erxyvnafjo .gt_indent_4 {
  text-indent: 20px;
}

#erxyvnafjo .gt_indent_5 {
  text-indent: 25px;
}

#erxyvnafjo .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#erxyvnafjo div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings gt_spanner_row header">
<th rowspan="2" id="Position" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Position</th>
<th colspan="4" id="Desirability Scores" class="gt_center gt_columns_top_border gt_column_spanner_outer" data-quarto-table-cell-role="th" scope="colgroup"><span class="gt_column_spanner">Desirability Scores</span></th>
</tr>
<tr class="gt_col_headings even">
<th id="Progressive Carrying" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Progressive Carrying</th>
<th id="Progressive Passing" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Progressive Passing</th>
<th id="Progressive Receptions" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Progressive Receptions</th>
<th id="Overall" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Overall</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.31</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.16</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.39</td>
<td class="gt_row gt_center" headers="Overall">0.26</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Position">MF</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.22</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.35</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.17</td>
<td class="gt_row gt_center" headers="Overall">0.23</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Position">DF</td>
<td class="gt_row gt_center" headers="Progressive Carrying">0.16</td>
<td class="gt_row gt_center" headers="Progressive Passing">0.24</td>
<td class="gt_row gt_center" headers="Progressive Receptions">0.12</td>
<td class="gt_row gt_center" headers="Overall">0.18</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="5" class="gt_sourcenote" style="text-align: left;">Source: FBref Via {worldfootballR}</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>The results are not shocking, but the marginal differences in progression by position are interesting. As expected, forwards are dominant in the receptions category, but the responsibilities for progressive carries are more evenly split, and forwards are third behind midfielders and defenders in progressive passing.</p>
</section>
<section id="overall-offensive-ratings" class="level3">
<h3 class="anchored" data-anchor-id="overall-offensive-ratings">Overall Offensive Ratings</h3>
<p>Having created desirability scores for each offensive component, we could combine all three into an overall offensive rating using <code>d_overall()</code>. I think this would be a reasonable choice when the assumption is that each category is equally important in the overall score, but as discussed already, I don’t think that’s the case here. I think goal threat matters most, and chance creation and ball progression are, while important enough to be the two other categories in the overall ratings, a little less important than goals.</p>
<p>Whether or not goals are more important than chance creation and ball progression is probably open to plenty of debate, but assuming that they are (because this is my blog and I said so), we have to weight the three categories to reflect this. Rather than overcomplicating things and trying to do this as part of the process within the desirability functions, I have downweighted chance creation and ball progression by multiplying them by 0.5.</p>
<p>Finally, I have opted for the arithmetic mean instead of the geometric mean, because I think the purpose of the geometric mean is of less value here.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1">offensive_rating <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb11-2">  goal_threat <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Threat"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> Overall) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb11-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">full_join</span>(chance_creation <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Chance Creation"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> Overall)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">full_join</span>(ball_progression <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ball Progression"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> Overall)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb11-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># downweight chance creation and ball progression desirability scores</span></span>
<span id="cb11-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Chance Creation"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ball Progression"</span>), <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> .x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>),</span>
<span id="cb11-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Overall =</span></span>
<span id="cb11-10">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_overall</span>(</span>
<span id="cb11-11">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Threat"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Chance Creation"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ball Progression"</span>)),</span>
<span id="cb11-12">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">geometric =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb11-13">        )</span>
<span id="cb11-14">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-15">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(</span>
<span id="cb11-16">    Player, Position, Team, League, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Threat"</span>, </span>
<span id="cb11-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Chance Creation"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ball Progression"</span>, Overall</span>
<span id="cb11-18">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb11-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">desc</span>(Overall))</span></code></pre></div></div>
</div>
<div class="cell">
<details class="code-fold">
<summary>Table Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">offensive_rating <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb12-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb12-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">format_table</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span></code></pre></div></div>
</details>
<div id="tbl-offensive-rating" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-offensive-rating-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;5: Overall Offensive Ratings
</figcaption>
<div aria-describedby="tbl-offensive-rating-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="hbmeekalnt" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#hbmeekalnt table {
  font-family: Poppins;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

#hbmeekalnt thead, #hbmeekalnt tbody, #hbmeekalnt tfoot, #hbmeekalnt tr, #hbmeekalnt td, #hbmeekalnt th {
  border-style: none;
}

#hbmeekalnt p {
  margin: 0;
  padding: 0;
}

#hbmeekalnt .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: 100%;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#hbmeekalnt .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#hbmeekalnt .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#hbmeekalnt .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#hbmeekalnt .gt_heading {
  background-color: #FFFFFF;
  text-align: center;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#hbmeekalnt .gt_bottom_border {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#hbmeekalnt .gt_col_headings {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#hbmeekalnt .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#hbmeekalnt .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#hbmeekalnt .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#hbmeekalnt .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#hbmeekalnt .gt_column_spanner {
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#hbmeekalnt .gt_spanner_row {
  border-bottom-style: hidden;
}

#hbmeekalnt .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#hbmeekalnt .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#hbmeekalnt .gt_from_md > :first-child {
  margin-top: 0;
}

#hbmeekalnt .gt_from_md > :last-child {
  margin-bottom: 0;
}

#hbmeekalnt .gt_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#hbmeekalnt .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#hbmeekalnt .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#hbmeekalnt .gt_row_group_first td {
  border-top-width: 2px;
}

#hbmeekalnt .gt_row_group_first th {
  border-top-width: 2px;
}

#hbmeekalnt .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#hbmeekalnt .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#hbmeekalnt .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#hbmeekalnt .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#hbmeekalnt .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#hbmeekalnt .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#hbmeekalnt .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#hbmeekalnt .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#hbmeekalnt .gt_table_body {
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#hbmeekalnt .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#hbmeekalnt .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#hbmeekalnt .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#hbmeekalnt .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#hbmeekalnt .gt_left {
  text-align: left;
}

#hbmeekalnt .gt_center {
  text-align: center;
}

#hbmeekalnt .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#hbmeekalnt .gt_font_normal {
  font-weight: normal;
}

#hbmeekalnt .gt_font_bold {
  font-weight: bold;
}

#hbmeekalnt .gt_font_italic {
  font-style: italic;
}

#hbmeekalnt .gt_super {
  font-size: 65%;
}

#hbmeekalnt .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#hbmeekalnt .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#hbmeekalnt .gt_indent_1 {
  text-indent: 5px;
}

#hbmeekalnt .gt_indent_2 {
  text-indent: 10px;
}

#hbmeekalnt .gt_indent_3 {
  text-indent: 15px;
}

#hbmeekalnt .gt_indent_4 {
  text-indent: 20px;
}

#hbmeekalnt .gt_indent_5 {
  text-indent: 25px;
}

#hbmeekalnt .katex-display {
  display: inline-flex !important;
  margin-bottom: 0.75em !important;
}

#hbmeekalnt div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
  height: 0px !important;
}
</style>

<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings gt_spanner_row header">
<th rowspan="2" id="Player" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Player</th>
<th rowspan="2" id="Position" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Position</th>
<th rowspan="2" id="Team" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Team</th>
<th rowspan="2" id="League" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">League</th>
<th colspan="4" id="Desirability Scores" class="gt_center gt_columns_top_border gt_column_spanner_outer" data-quarto-table-cell-role="th" scope="colgroup"><span class="gt_column_spanner">Desirability Scores</span></th>
</tr>
<tr class="gt_col_headings even">
<th id="Goal Threat" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Goal Threat</th>
<th id="Chance Creation" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Chance Creation</th>
<th id="Ball Progression" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Ball Progression</th>
<th id="Overall" class="gt_col_heading gt_columns_bottom_border gt_center" data-quarto-table-cell-role="th" scope="col">Overall</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Kylian Mbappé</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Paris S-G</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Goal Threat">0.91</td>
<td class="gt_row gt_center" headers="Chance Creation">0.25</td>
<td class="gt_row gt_center" headers="Ball Progression">0.26</td>
<td class="gt_row gt_center" headers="Overall">0.47</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Lionel Messi</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Paris S-G</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Goal Threat">0.54</td>
<td class="gt_row gt_center" headers="Chance Creation">0.46</td>
<td class="gt_row gt_center" headers="Ball Progression">0.25</td>
<td class="gt_row gt_center" headers="Overall">0.41</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Erling Haaland</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Manchester City</td>
<td class="gt_row gt_left" headers="League">Premier League</td>
<td class="gt_row gt_center" headers="Goal Threat">0.93</td>
<td class="gt_row gt_center" headers="Chance Creation">0.18</td>
<td class="gt_row gt_center" headers="Ball Progression">0.08</td>
<td class="gt_row gt_center" headers="Overall">0.40</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Robert Lewandowski</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Barcelona</td>
<td class="gt_row gt_left" headers="League">La Liga</td>
<td class="gt_row gt_center" headers="Goal Threat">0.83</td>
<td class="gt_row gt_center" headers="Chance Creation">0.21</td>
<td class="gt_row gt_center" headers="Ball Progression">0.13</td>
<td class="gt_row gt_center" headers="Overall">0.39</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Neymar</td>
<td class="gt_row gt_left" headers="Position">MF</td>
<td class="gt_row gt_left" headers="Team">Paris S-G</td>
<td class="gt_row gt_left" headers="League">Ligue 1</td>
<td class="gt_row gt_center" headers="Goal Threat">0.45</td>
<td class="gt_row gt_center" headers="Chance Creation">0.46</td>
<td class="gt_row gt_center" headers="Ball Progression">0.26</td>
<td class="gt_row gt_center" headers="Overall">0.39</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Victor Osimhen</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Napoli</td>
<td class="gt_row gt_left" headers="League">Serie A</td>
<td class="gt_row gt_center" headers="Goal Threat">0.86</td>
<td class="gt_row gt_center" headers="Chance Creation">0.13</td>
<td class="gt_row gt_center" headers="Ball Progression">0.10</td>
<td class="gt_row gt_center" headers="Overall">0.36</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Karim Benzema</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Real Madrid</td>
<td class="gt_row gt_left" headers="League">La Liga</td>
<td class="gt_row gt_center" headers="Goal Threat">0.65</td>
<td class="gt_row gt_center" headers="Chance Creation">0.21</td>
<td class="gt_row gt_center" headers="Ball Progression">0.20</td>
<td class="gt_row gt_center" headers="Overall">0.36</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Kingsley Coman</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Bayern Munich</td>
<td class="gt_row gt_left" headers="League">Bundesliga</td>
<td class="gt_row gt_center" headers="Goal Threat">0.38</td>
<td class="gt_row gt_center" headers="Chance Creation">0.36</td>
<td class="gt_row gt_center" headers="Ball Progression">0.31</td>
<td class="gt_row gt_center" headers="Overall">0.35</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="Player">Mohamed Salah</td>
<td class="gt_row gt_left" headers="Position">FW</td>
<td class="gt_row gt_left" headers="Team">Liverpool</td>
<td class="gt_row gt_left" headers="League">Premier League</td>
<td class="gt_row gt_center" headers="Goal Threat">0.56</td>
<td class="gt_row gt_center" headers="Chance Creation">0.27</td>
<td class="gt_row gt_center" headers="Ball Progression">0.21</td>
<td class="gt_row gt_center" headers="Overall">0.34</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="Player">Kevin De Bruyne</td>
<td class="gt_row gt_left" headers="Position">MF</td>
<td class="gt_row gt_left" headers="Team">Manchester City</td>
<td class="gt_row gt_left" headers="League">Premier League</td>
<td class="gt_row gt_center" headers="Goal Threat">0.25</td>
<td class="gt_row gt_center" headers="Chance Creation">0.49</td>
<td class="gt_row gt_center" headers="Ball Progression">0.27</td>
<td class="gt_row gt_center" headers="Overall">0.34</td>
</tr>
</tbody><tfoot class="gt_sourcenotes">
<tr class="odd">
<td colspan="8" class="gt_sourcenote" style="text-align: left;">Source: FBref Via {worldfootballR}</td>
</tr>
</tfoot>

</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>The old rule was that any metric not broken by Lionel Messi being so far ahead of everyone else is wrong, but Messi isn’t quite the freak of nature he once was. Nonetheless, Messi’s name being near the top of the ratings is a good sign, as is Mbappé and Haaland flanking him at the top. At a glance, there are few surprises in Table&nbsp;5.</p>
<p>Kingsley Coman making it into the top ten feels generous, but perhaps the biggest issue is the three Ligue 1 players in the top five. While those three players are exceptional, they seem to be rated a little too high. I think this points to the inevitable league effects compromising the ratings. The big five leagues have been treated equally and we know that isn’t really the case (Ligue 1 is probably the weakest of the five). A more precise approach would involve weighting by league strength, but that’s complicated and I don’t want to do it.</p>
<p>Nonetheless, I think the ratings look pretty reasonable, and when we split the top ten overall desirability scores into their component parts, visualised below, we can see how the three offensive components are balanced.</p>
<div class="cell">
<details class="code-fold">
<summary>Plot Code (Click to Expand)</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1">offensive_rating <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb13-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb13-3">  tidyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(</span>
<span id="cb13-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cols =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>,  </span>
<span id="cb13-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"component"</span>, </span>
<span id="cb13-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span></span>
<span id="cb13-7">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb13-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb13-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">component =</span> </span>
<span id="cb13-10">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(</span>
<span id="cb13-11">        component, </span>
<span id="cb13-12">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">levels =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Goal Threat"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Chance Creation"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ball Progression"</span>)</span>
<span id="cb13-13">        )</span>
<span id="cb13-14">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb13-15">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reorder</span>(Player, Overall), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> value, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> component)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb13-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_col</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">position =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">position_dodge2</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">reverse =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-17">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_hline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">yintercept =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey20"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coord_flip</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_x_discrete</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">labels =</span> scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">label_wrap</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_fill_manual</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#026E99"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#D93649"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#FCCE26"</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb13-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> </span>
<span id="cb13-23">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Component Desirability Scores for the Offensive Ratings' Best Players"</span>,</span>
<span id="cb13-24">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> </span>
<span id="cb13-25">      stringr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_wrap</span>(</span>
<span id="cb13-26">        glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(</span>
<span id="cb13-27">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The component desirability scores for the top ten players in the "</span>,</span>
<span id="cb13-28">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"offensive ratings in the big five leagues for the 2022/23 season. "</span>,</span>
<span id="cb13-29">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The overall ratings are a weighted average of the desirability scores "</span>,</span>
<span id="cb13-30">          <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"for goal threat (50%), chance creation (25%), and ball progression (25%)."</span></span>
<span id="cb13-31">          ),</span>
<span id="cb13-32">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span></span>
<span id="cb13-33">      ),</span>
<span id="cb13-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Desirability"</span>,</span>
<span id="cb13-35">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">caption =</span> </span>
<span id="cb13-36">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visualisation: Paul Johnson  |  Data: FBref Via {worldfootballR}"</span></span>
<span id="cb13-37">    ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb13-38">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span>(</span>
<span id="cb13-39">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.major.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb13-40">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.ticks.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_blank</span>(),</span>
<span id="cb13-41">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text.y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(</span>
<span id="cb13-42">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colour =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey30"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rel</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.15</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hjust =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, </span>
<span id="cb13-43">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">margin =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">r =</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">l =</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lineheight =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb13-44">      )</span>
<span id="cb13-45">    )</span></code></pre></div></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2024-02-22-football-ratings-using-desirability-functions/index_files/figure-html/offensive-components-1.png" class="img-fluid figure-img" alt="A bar plot showing the component desirability scores (goal threat, chance creation, and ball progression) for the ten best players according to the offensive ratings. The overall offensive ratings are calculated using a weighted average of desirability scores, with goal threat given 50% of the weight, and chance creation and ball progression given 25% each. As a result, the majority of the top then players have particularly high scores for goal threat, with only a few players with comparatively high chance creation scores (Messi, Neymar, and Kevin De Bruyne), and no players having particularly large ball progression scores. " width="672"></p>
</figure>
</div>
</div>
</div>
</section>
</section>
<section id="limitations" class="level2">
<h2 class="anchored" data-anchor-id="limitations">Limitations</h2>
<p>I think the appeal of desirability functions is their simplicity, but this is also a constraint. As the complexity of the multivariate optimisation problem increases, the solutions will need to scale similarly. While desirability functions are a quick and easy optimisation method that can perform well in many contexts, I don’t think they’re suitable when dealing with the most complex, multidimensional problems. Developing a precise, reliable rating system for offensive players would probably involve doing something more complicated than desirability functions!</p>
<p>Scaling can improve the performance of desirability functions when dealing with complex optimisation problems, but deciding when and how to use them is difficult. It is more of an art than a science. Consequentially, scaling features risk encouraging searching for results that feel good. If you have theory-driven expectations of the weighted combination of a set of variables, you stand a better chance of avoiding results that confirm your biases but it is difficult to validate desirability functions outside of eyeballing the results and deciding whether they seem right.</p>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>I am generally pretty sceptical of player rating systems in football. Capturing a multidimensional context like this is difficult using a single measure of player performance. And yet here I am, developing a player rating system that attempts to do exactly that! In my defense, I have at least limited these ratings to offense, which makes it slightly better<sup>3</sup>, and it’s a lot easier to rate players over an entire season than a single match. But I’d take these results with a big pinch of salt. I would include several caveats if I released these ratings into the wild, for the non-nerds (there is no chance anyone but nerds is reading this). These ratings are going to be pretty noisy! That said, I don’t think the results are complete garbage, which meets the high standard I set for my work.</p>
<p>Hopefully, these ratings illustrate how desirability functions work and demonstrate that they could be appropriate in many situations. You don’t see desirability functions used very often, but they are quick and easy, and they can be pretty effective.</p>
</section>




<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Preview image by <a href="https://unsplash.com/@dancristianpaduret">Dan Cristian Pădureț</a> on <a href="https://unsplash.com/photos/a-blackboard-with-a-bunch-of-diagrams-on-it-h3kuhYUCE9A">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>



</div></section><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-derringer1980" class="csl-entry">
Derringer, George, and Ronald Suich. 1980. <span>“Simultaneous Optimization of Several Response Variables.”</span> <em>Journal of Quality Technology</em> 12 (4): 214–19.
</div>
<div id="ref-harrington1965" class="csl-entry">
Harrington, E. C. 1965. <span>“The Desirability Function.”</span> <em>Industrial Quality Control</em> 21: 494–98.
</div>
<div id="ref-kuhn2016" class="csl-entry">
Kuhn, Max. 2016. <em>The Desirability Package</em>. <a href="https://cran.r-project.org/web/packages/desirability/vignettes/desirability.pdf">https://cran.r-project.org/web/packages/desirability/vignettes/desirability.pdf</a>.
</div>
<div id="ref-kuhn2023" class="csl-entry">
Kuhn, Max. 2023. <em>Desirability Functions for Multiparameter Optimization - /<span class="nocase">desirability2/</span></em>. <a href="https://desirability2.tidymodels.org/">https://desirability2.tidymodels.org/</a>.
</div>
<div id="ref-kuhn2019" class="csl-entry">
Kuhn, Max, and Kjell Johnson. 2019. <em>Feature Engineering and Selection: A Practical Approach for Predictive Models</em>. Taylor &amp; Francis. <a href="https://bookdown.org/max/FES/">https://bookdown.org/max/FES/</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>With each variable <img src="https://latex.codecogs.com/png.latex?X_i"> being simultaneously optimised, where <img src="https://latex.codecogs.com/png.latex?i"> represents each individual variable, each must be individually optimised using a desirability function that approaches 1 when <img src="https://latex.codecogs.com/png.latex?X_i"> is optimal and approaches 0 when <img src="https://latex.codecogs.com/png.latex?X_i"> is unacceptable. The optimisation function for minimising <img src="https://latex.codecogs.com/png.latex?X_i"> <span class="citation" data-cites="kuhn2016">(Kuhn 2016)</span> is given by:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AD_%7BX_i%7D%5E%7Bmin%7D%20=%0A%5Cbegin%7Bcases%7D%0A%20%200%20&amp;%20%5Ctext%7Bif%20%7D%20X_i%20%3E%20B_i%20%5C%5C%0A%20%20%5Cleft(%5Cfrac%7BB_i%20-%20X_i%7D%7BB_i%20-%20A_i%7D%5Cright)%5E%7Bs_i%7D%20&amp;%20%5Ctext%7Bif%20%7D%20A_i%20%5Cleq%20X_i%20%5Cleq%20B_i%20%5C%5C%0A%20%201%20&amp;%20%5Ctext%7Bif%20%7D%20X_i%20%3C%20A_i%0A%5Cend%7Bcases%7D%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?A_i"> and <img src="https://latex.codecogs.com/png.latex?B_i"> specify the minimum and maximum value that each variable <img src="https://latex.codecogs.com/png.latex?X_i"> can reach, and <img src="https://latex.codecogs.com/png.latex?s_i"> is a scaling feature that makes it easier (<img src="https://latex.codecogs.com/png.latex?s%20%3E%201">) or harder (<img src="https://latex.codecogs.com/png.latex?s%20%3C%201">) for each variable <img src="https://latex.codecogs.com/png.latex?X_i"> to achieve maximal desirability.</p>
<p>Similarly, the optimisation function for maximising variable <img src="https://latex.codecogs.com/png.latex?X_i"> <span class="citation" data-cites="kuhn2016">(Kuhn 2016)</span> is:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AD_%7BX_i%7D%5E%7Bmax%7D%20=%0A%5Cbegin%7Bcases%7D%0A%20%200%20&amp;%20%5Ctext%7Bif%20%7D%20X_i%20%3C%20A_i%20%5C%5C%0A%20%20%5Cleft(%5Cfrac%7BX_i%20-%20A_i%7D%7BB_i%20-%20A_i%7D%5Cright)%5E%7Bs_i%7D%20&amp;%20%5Ctext%7Bif%20%7D%20A_i%20%5Cleq%20X_i%20%5Cleq%20B_i%20%5C%5C%0A%20%201%20&amp;%20%5Ctext%7Bif%20%7D%20X_i%20%3E%20B_i%0A%5Cend%7Bcases%7D%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?A_i">, <img src="https://latex.codecogs.com/png.latex?B_i">, and <img src="https://latex.codecogs.com/png.latex?s_i"> are again the minimum and maximum values and the scaling feature.↩︎</p></li>
<li id="fn2"><p>The arithmetic mean is the typical mean average value that people are used to seeing, which sums all values and divides the sum by the sample size, <img src="https://latex.codecogs.com/png.latex?n">, while the geometric mean multiplies all values, before taking the <img src="https://latex.codecogs.com/png.latex?n">th root (the <img src="https://latex.codecogs.com/png.latex?n"> being the number of values multiplied) of that product. Both arithmetic and geometric mean are measures of central tendency, but geometric mean is more robust when dealing with non-independent values, less responsive to outliers, and more capable of handling skewed data.↩︎</p></li>
<li id="fn3"><p>Defensive event data does not reflect performance and is more of a measure of team and player style.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2024" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2024. <span>“Developing Offensive Ratings Using
Desirability Functions.”</span> February 22. <a href="https://paulrjohnson.net/blog/2024-02-22-football-ratings-using-desirability-functions/">https://paulrjohnson.net/blog/2024-02-22-football-ratings-using-desirability-functions/</a>.
</div></div></section></div> ]]></description>
  <category>Optimisation</category>
  <category>Football Analytics</category>
  <category>R</category>
  <guid>https://paulrjohnson.net/blog/2024-02-22-football-ratings-using-desirability-functions/</guid>
  <pubDate>Thu, 22 Feb 2024 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2024-02-22-football-ratings-using-desirability-functions/math.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>A Cheatsheet for Building Multilevel Models in R</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2022-11-01-multilevel-model-r-cheatsheet/</link>
  <description><![CDATA[ 





<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>Some minor changes have been made to this blog post, cleaning up some unclear and confusing language/phrasing, and adding additional resources for learning about multilevel regression.</p>
</div>
</div>
<p>Multilevel models (MLMs) are hard. Some part of the difficulty is due to the fact that multilevel data structures add an extra layer of complexity conceptually and mathematically, and therefore the appropriate model structure for this kind of data is also more complex. However, there’s plenty about them that just seems needlessly hard.</p>
<p>Oh would you like to make a multilevel model or a hierarchical model? But have you considered a generalized linear mixed effects model? What about a variance component model? WHAT DO YOU MEAN THEY’RE THE SAME THING?<sup>1</sup>! That can’t possibly be true. Why would anyone in statistics or the sciences make anything needlessly convoluted and use different names for the same concepts? Thankfully things are much simpler when it comes to discussing fixed and random effects. Just a couple concepts with precise meaning and usage in every field… Wait, what? Oh you’ve got be fucking kidding me.</p>
<p>So I thought I’d try and make things a little easier for anyone taking their first steps into this fresh hell, and for anyone (like me) that has a mushy, liquefied brain and needs a refresher any time they haven’t looked at something every single day for the last two years.</p>
<p>I’m not going to write a full introduction, or a detailed how-to for constructing multilevel models, because a) that sounds long as hell and b) there are much smarter people than I that have already done these things (resources are linked at the end of the post). This will just serve as a quick explainer of what MLMs are, when you need them, and the syntax for constructing the most basic (and most common) types of MLMs in R. The goal is to keep this relatively short and make it accessible for folks without intensive statistics backgrounds. Therefore, I will attempt to keep the notation to the minimum, explaining model structures and using examples to illustrate. I have included <em>some</em> notation, but I’ve kept it hidden to make this cheatsheet<sup>2</sup> a little bit less intimidating. If you fancy your chances, you can expand the notation sections.</p>
<p>I won’t go into the details about fitting, interpreting, and validating multilevel models here, but I will possibly turn this into a series, and if so I will get in to it in the next blog post. LFG!!!</p>
<section id="what-are-multilevel-models" class="level2">
<h2 class="anchored" data-anchor-id="what-are-multilevel-models">What are Multilevel Models?</h2>
<p>A common feature of many real-world questions that practitioners might study is that there are multiple “levels” around which the data is structured. A dataset may contain observations at a population-level, with a higher-level variable that specifies a group that those observations belong to (for example, patients being treated by a certain doctor or in a certain hospital, or political parties operating in different countries). Figure&nbsp;1 below is a visual representation of how multilevel data might be structured.</p>
<div class="cell" data-eval="true" data-layout-align="center">
<div class="cell-output-display">
<div id="fig-multilevel-data" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-multilevel-data-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>
<pre class="mermaid mermaid-js" data-label="fig-multilevel-data">graph TB
  A([Group 1]) --&gt; B[Unit 1]
  A --&gt; C[Unit 2]
  A --&gt; D[Unit 3]
  E([Group 2]) --&gt; F[Unit 4]
  E --&gt; G[Unit 5]
  E --&gt; H[Unit 6]
  I([Group 3]) --&gt; J[Unit 7]
  I --&gt; K[Unit 8]
  I --&gt; L[Unit 9]
</pre>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-multilevel-data-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: A Hierarchical Grouping Structure
</figcaption>
</figure>
</div>
</div>
</div>
<p>Assuming that the grouping variable is relevant to the outcome being studied, this means that some observations will be correlated with each other, or clustered around the groups they belong to, which invites bias into any model that doesn’t account for this clustering. Multilevel models are regression models that handle data which is structured in groups<sup>3</sup>.</p>
<details>
<summary>
Notation
</summary>
<p>There are a few different ways that you might see multilevel models represented notationally, but when talking about the most general form of MLMs, the easiest way is using matrix notation:</p>
<p><img src="https://latex.codecogs.com/png.latex?Y%20=%20%5Calpha%20+%20X%5Cbeta%20+%20Z%5Cgamma%20+%20%5Cepsilon"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?Y"> is a vector of observed values in the outcome variable, <img src="https://latex.codecogs.com/png.latex?X"> is a matrix of predictors and <img src="https://latex.codecogs.com/png.latex?Z"> is a matrix that refers to group-level deviation of the predictors (either in terms of the intercept or slope). <img src="https://latex.codecogs.com/png.latex?%5Calpha"> refers to the global intercept, <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> represents the vector of fixed effects parameters, <img src="https://latex.codecogs.com/png.latex?%5Cgamma"> represents the vector of random effects, and <img src="https://latex.codecogs.com/png.latex?%5Cepsilon"> refers to the model’s error term.</p>
<p>However, I think it is generally easier to think about multilevel models in terms of the different levels that are being estimated in the model, and instead, throughout this blog post, I will give the level 1 and level 2 formulas for each model (we won’t go deeper than two levels for now, because I’m not a total monster).</p>
</details>
<section id="its-mlms-all-the-way-down" class="level3">
<h3 class="anchored" data-anchor-id="its-mlms-all-the-way-down">It’s MLMs All The Way Down</h3>
<p>There is lots of confusing and sometimes contradictory terminology that is used when talking about multilevel models.</p>
<section id="fixed-random-effects" class="level4">
<h4 class="anchored" data-anchor-id="fixed-random-effects">Fixed &amp; Random Effects</h4>
<p>When discussing the ways that an effect can occur at different levels in a multilevel model, people will often refer to fixed and random effects. Fixed effects are those that are fixed across groups, or that are the same for every cluster, while the random effects are those that deviate between groups. The fixed and random effects could refer to either the intercept or the slope, as these can both vary between groups, and can in some cases both vary at the same time.</p>
<p>However, as <a href="https://statmodeling.stat.columbia.edu/2005/01/25/why_i_dont_use/">Andrew Gelman has argued</a>, these terms are sometimes used to refer to slightly different things, and this can lead to some confusion. So whenever you see someone refer to fixed or random effects, be aware that there may be some variance in how these terms are being used.</p>
<p>An alternative terminology, that possibly carries less confusion, is population- and group-level effects. When the variable is constant across groups/clusters and the effect varies at a unit-level (fixed-effect), this is referred to as a population-level effect. However, when the variable’s effect varies across groups/clusters (random-effect) then it is a group-level effect.</p>
<p>For the remainder of this blog post I will use this population- and group-level terminology.</p>
</section>
<section id="linear-mixed-models-vs-multilevel-models" class="level4">
<h4 class="anchored" data-anchor-id="linear-mixed-models-vs-multilevel-models">Linear Mixed Models vs Multilevel Models</h4>
<p>There are some slight differences between what a linear mixed model might refer to<sup>4</sup>, and what a hierarchical or multilevel model<sup>5</sup> might refer to, but on the whole I think it is safe to treat them (generally speaking) as the same thing, with an understanding that multilevel models are any models where there are grouping structures that lead to the data violating the independence assumption, and hierarchical grouping structures are just one type of such structure.</p>
<p>An example of a context where you might see a grouping structure that isn’t hierarchical/nested is data where individuals are measured repeatedly, like, for example, a dataset containing repeated polling of individual’s views on a political candidate or issue (panel data). In this case, there is no hierarchical structure, but the grouping structure is the individual.</p>
</section>
</section>
</section>
<section id="multilevel-model-syntax-in-r" class="level2">
<h2 class="anchored" data-anchor-id="multilevel-model-syntax-in-r">Multilevel Model Syntax in R</h2>
<p>The good thing about the R syntax I detail in this section is that it is the same for <a href="https://github.com/lme4/lme4/"><strong>lme4</strong></a>, the main package for frequentist multilevel models, and the same for <a href="https://paul-buerkner.github.io/brms/"><strong>brms</strong></a> and <a href="https://mc-stan.org/rstanarm/"><strong>rstanarm</strong></a>, two of the most popular packages for computing Bayesian multilevel models.</p>
<p>The basic structure of multilevel models in R is very similar to typical <code>lm()</code> formulae, using <code>y ~ x1 + x2 ... + xn</code>, but in addition to this, the MLM syntax accounts for a grouping structure in the data using the pipe: |.</p>
<p>Below are some examples of simple multilevel model structures, where <code>x</code> refers to a unit-level variable and <code>g</code> refers to the group variable. Figure&nbsp;2 demonstrates visually the multilevel models that will be covered.</p>
<div id="fig-mlm" class="quarto-float quarto-figure quarto-figure-center anchored" alt="An image of the differences between varying intercepts, varying slopes, and varying intercepts and slopes. The varying intercepts illustration is five parallel lines that have the same gradient (slopes) but different starting points (intercepts), while the varying slopes lines all start from the same point but the lines all have different gradients. Finally, the varying intercepts and slopes have different starting points and gradients.">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-mlm-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://paulrjohnson.net/blog/2022-11-01-multilevel-model-r-cheatsheet/multilevel_data.webp" class="img-fluid figure-img" alt="An image of the differences between varying intercepts, varying slopes, and varying intercepts and slopes. The varying intercepts illustration is five parallel lines that have the same gradient (slopes) but different starting points (intercepts), while the varying slopes lines all start from the same point but the lines all have different gradients. Finally, the varying intercepts and slopes have different starting points and gradients.">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-mlm-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Multilevel Data Structures (Source: <a href="http://www.stat.columbia.edu/~gelman/arm/">Gelman &amp; Hill (2006)</a>)
</figcaption>
</figure>
</div>
<section id="varyings-intercepts" class="level3">
<h3 class="anchored" data-anchor-id="varyings-intercepts">Varyings Intercepts</h3>
<p>The simplest kind of model you can specify with a grouping structure is one which models a grouping structure with deviance from the global intercept, but no unit-level predictors. This means that the intercept is allowed to vary between groups (for example, patient outcomes in different hospitals), around the mean intercept of all groups (the global intercept). This is often referred to as a null model, or a varying (random) intercepts model.</p>
<p>This can be specified as such:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1">y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> g)</span></code></pre></div></div>
</div>
<p>The <code>1</code> outside of the brackets here specifies the fixed mean global intercept, and the <code>(1|g1)</code> specifies that the grouping structure produces intercepts that vary for each group.</p>
<details>
<summary>
Notation
</summary>
<p><img src="https://latex.codecogs.com/png.latex?y_%7Bij%7D%20=%20%5Calpha_%7Bj%7D%20+%20%20%5Cepsilon_%7Bij%7D"></p>
<p><img src="https://latex.codecogs.com/png.latex?%5Calpha_%7Bj%7D"> refers to the intercept (<img src="https://latex.codecogs.com/png.latex?%5Calpha">) for every group (<img src="https://latex.codecogs.com/png.latex?j">), meaning that every group <img src="https://latex.codecogs.com/png.latex?j"> has its own intercept. The formula for <img src="https://latex.codecogs.com/png.latex?%5Calpha_%7Bj%7D"> can be written as follows:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Calpha_%7Bj%7D%20=%20%5Cgamma_%7B00%7D%20+%20%5Cmu_%7B0j%7D"></p>
<p>This formula is the group level intercept variance, explaining the <img src="https://latex.codecogs.com/png.latex?j">th group’s deviation from the mean global intercept, with <img src="https://latex.codecogs.com/png.latex?%5Cgamma_%7B00%7D"> representing the mean global intercept, and <img src="https://latex.codecogs.com/png.latex?%5Cmu_%7B0j%7D"> representing the deviance from the mean intercept.</p>
</details>
<section id="adding-population-effects" class="level4">
<h4 class="anchored" data-anchor-id="adding-population-effects">Adding Population Effects</h4>
<p>While the previous model only included a group-level effect that caused deviance from the global intercept, there was no population-level effect in the model. If we add a population-level effect <img src="https://latex.codecogs.com/png.latex?x"> to the model, we get the following:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> g)</span></code></pre></div></div>
</div>
<p>This is a pretty typical multilevel model that you’ll see plenty of examples of in the real-world and find plenty of use for when implementing MLMs yourself.</p>
<details>
<summary>
Notation
</summary>
<p><img src="https://latex.codecogs.com/png.latex?y_%7Bij%7D%20=%20%5Calpha_%7Bj%7D%20+%20%5Cbeta_%7B1j%7Dx_%7Bij%7D%20+%20%5Cepsilon_%7Bij%7D"></p>
<p>This is the level one formula for the value of <img src="https://latex.codecogs.com/png.latex?y"> indexed by <img src="https://latex.codecogs.com/png.latex?i"> units and <img src="https://latex.codecogs.com/png.latex?j"> groups.</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Calpha_%7Bj%7D"> refers to the intercept (<img src="https://latex.codecogs.com/png.latex?%5Calpha_%7B%7D">) for every group (<img src="https://latex.codecogs.com/png.latex?j">), meaning that every group <img src="https://latex.codecogs.com/png.latex?j"> has its own intercept. The formula for <img src="https://latex.codecogs.com/png.latex?%5Calpha_%7Bj%7D"> can be written as follows:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Calpha_%7Bj%7D%20=%20%5Cgamma_%7B00%7D%20+%20%5Cmu_%7B0j%7D"></p>
<p>And the formula for <img src="https://latex.codecogs.com/png.latex?%5Cbeta_%7B1j%7D"> is:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cbeta_%7B1j%7D%20=%20%5Cgamma_%7B10%7D"></p>
<p>These two formulas are the second level of the model, with <img src="https://latex.codecogs.com/png.latex?%5Calpha_j"> explaining the <img src="https://latex.codecogs.com/png.latex?j">th group’s deviation from the global intercept, when there are varying intercepts, with <img src="https://latex.codecogs.com/png.latex?%5Cgamma_%7B00%7D"> representing the global_intercept, and <img src="https://latex.codecogs.com/png.latex?%5Cmu_%7B0j%7D"> representing the deviance from the mean intercept, and <img src="https://latex.codecogs.com/png.latex?%5Cbeta_%7B1j%7D"> explaining the unit-level variance of <img src="https://latex.codecogs.com/png.latex?x">, with <img src="https://latex.codecogs.com/png.latex?%5Cgamma_%7B10%7D"> representing the population-effect for the slope of <img src="https://latex.codecogs.com/png.latex?x">.</p>
</details>
</section>
</section>
<section id="varying-slopes" class="level3">
<h3 class="anchored" data-anchor-id="varying-slopes">Varying Slopes</h3>
<p>Sometimes there will be an expectation that the grouping structure has no effect on the intercept, but that the slope will vary between groups (though this kind of model is generally less common). The following model structure will do the job, in those instances:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> g)</span></code></pre></div></div>
</div>
<p>The default structure in multilevel modelling is to include a varying intercept, which is represented by the 1 that sits inside the brackets in the code, (1|g). If you don’t want to include a varying intercept, then a 0 is required to override this default.</p>
<p>While possibly less common than a varying intercepts model, I think it is also useful to understand how a varying slopes model is structured, in order to get a better understanding of how MLMs work both conceptually and technically.</p>
<details>
<summary>
Notation
</summary>
<p>If the intercepts are fixed and the slopes vary, then the formula would be slightly different to the one presented earlier:</p>
<p><img src="https://latex.codecogs.com/png.latex?y_%7Bij%7D%20=%20%5Calpha_j%20+%20%5Cbeta_%7B1j%7Dx_i%20+%20%5Cepsilon_%7Bij%7D"></p>
<p>The differences lie in the second level formulas:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Calpha_j"> would be written as:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Calpha_j%20=%20%5Cgamma_%7B00%7D"></p>
<p>While the formulas for <img src="https://latex.codecogs.com/png.latex?%5Cbeta_%7B1j%7D"> would be written as:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cbeta_%7B1j%7D%20=%20%5Cgamma_%7B10%7D%20+%20%5Cmu_%7B1j%7D"></p>
<p>The difference here is that the <img src="https://latex.codecogs.com/png.latex?%5Calpha_j"> no longer has a <img src="https://latex.codecogs.com/png.latex?%5Cmu_%7B0j%7D"> term, because there is no group-level deviation around the global intercept, while <img src="https://latex.codecogs.com/png.latex?%5Cbeta_%7B1j%7D"> has a <img src="https://latex.codecogs.com/png.latex?%5Cmu_%7B1j%7D"> term, representing the <img src="https://latex.codecogs.com/png.latex?j">th group’s deviation from the global mean of the slope.</p>
</details>
</section>
<section id="varying-intercepts-slopes" class="level3">
<h3 class="anchored" data-anchor-id="varying-intercepts-slopes">Varying Intercepts &amp; Slopes</h3>
<p>And once you’ve figured out how to build a model that varies either the intercepts or the slopes, you can then let it all hang out and just let the groups do whatever the hell they want, in the form of both varying intercepts AND slopes.</p>
<p>The syntax for this kind of structured madness is as follows:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># correlated intercepts and slopes</span></span>
<span id="cb4-2">y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> g)</span>
<span id="cb4-3"></span>
<span id="cb4-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># uncorrelated intercepts and slopes</span></span>
<span id="cb4-5">y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">||</span> g)</span></code></pre></div></div>
</div>
<p>I think the previous section, detailing the structure and syntax of a varying slopes model, really helps figure things out when presented in conjunction with this model structure. The incremental changes that lead to different types of models should help to identify which components do what.</p>
<details>
<summary>
Notation
</summary>
<p>As you might expect, the formula for a multilevel model with both varying intercepts and slopes will look like a combination of the previous two examples:</p>
<p><img src="https://latex.codecogs.com/png.latex?y_%7Bij%7D%20=%20%5Calpha_%7Bj%7D%20+%20%5Cbeta_%7B1j%7Dx_i%20+%20%5Cepsilon_%7Bij%7D"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?%5Calpha_%7Bj%7D"> (the intercept) can be expanded as:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Calpha_%7Bj%7D%20=%20%5Cgamma_%7B00%7D%20+%20%5Cmu_%7B0j%7D"></p>
<p>and where <img src="https://latex.codecogs.com/png.latex?%5Cbeta_%7B1j%7D"> (the slope) can be expanded as:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cbeta_%7B1j%7D%20=%20%5Cgamma_%7B10%7D%20+%20%5Cmu_%7B1j%7D"></p>
<p>Hopefully by now the multilevel model structure is starting to make some sense. The distinction between the previous models and this model formula, that makes it a varying intercepts and slopes model, is the fact that there is a term for the variance from the global mean in both the second-level formula for the intercept (<img src="https://latex.codecogs.com/png.latex?%5Cmu_%7B0j%7D">) and the slope ((<img src="https://latex.codecogs.com/png.latex?%5Cmu_%7B1j%7D">)).</p>
</details>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>So I’ve laid out the basic structure of multilevel modelling, hopefully making it easier to figure out the syntax in R, and build some simple MLMs. Things can quickly get more and more complicated when you start adding multiple grouping structures, or as you add multiple predictors and interactions, but the basics laid out in this article should be enough to get you started building multilevel models. In future blog posts (making some strong assumptions about my commitment to this bit) I will take a look at how to fit and interpret these simple multilevel models, using simulated data.</p>
<p>There’s lots of ways you can specify a multilevel model that involve vast complex grouping structures nested between each other or crossed with population-level effects. However, more often than not, I think you will get away with just using a simple structure, particularly the varying intercepts model. This will get you most of the way there, especially while you’re learning your way with multilevel modelling. Once you’re more comfortable with the idea conceptually and technically? You can start to make a real mess!</p>
<p>Given how complex things can get with MLMs, this cheatsheet is obviously only scratching the surface. Therefore, in the interest of not leaving anyone with a thirst-for-the-learn hanging, here’s a few resources to help along the way:</p>
<ul>
<li><a href="https://www.learn-mlms.com/">Shaw &amp; Flake - Introduction to Multilevel Modelling</a></li>
<li><a href="http://www.stat.columbia.edu/~gelman/arm/">Gelman &amp; Hill - Data Analysis Using Regression and Multilevel/Hierarchical Models</a></li>
<li><a href="http://www.stat.columbia.edu/~gelman/armm/">Gelman et al.&nbsp;- Applied Regression and Multilevel Models</a><sup>6</sup></li>
<li><a href="https://paul-buerkner.github.io/brms/articles/index.html"><strong>brms</strong> Vignettes</a></li>
<li><a href="https://www.andrewheiss.com/blog/2021/12/01/multilevel-models-panel-data-guide/">Heiss - A Guide to Working with Country-Year Panel Data and Bayesian Multilevel Models</a></li>
<li><a href="https://m-clark.github.io/mixed-models-with-R">Clark - Mixed Models with R</a></li>
<li><a href="https://rpsychologist.com/r-guide-longitudinal-lme-lmer">Magnusson - Using R and lme/lmer to Fit Different Two- and Three-Level Longitudinal Models</a></li>
</ul>
</section>




<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Preview image by <a href="https://unsplash.com/@gecko81de">Patrick Baum</a> on <a href="https://unsplash.com/photos/bottom-view-of-glass-building-EOzW3UVBKSI">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>


</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>There are some minor distinctions, but the terms are often used interchangeably.↩︎</p></li>
<li id="fn2"><p>Does a blog post get to call itself a cheatsheet?↩︎</p></li>
<li id="fn3"><p>There are alternative ways to handle clustered data, such as cluster-robust standard errors, but I won’t cover that here. If you’re interested in learning about these methods, I’d recommend the discussion in <a href="https://www.learn-mlms.com/03-module-3.html#cluster-robust-standard-errors">Chapter 3 of Introduction to Multilevel Modelling</a>, or this <a href="https://mldscenter.maryland.gov/egov/Publications/ResearchSeries/Clustered%20Data,%20Are%20Multilevel%20Models%20Really%20Necessary.pdf">overview</a> that is linked in the discussion.↩︎</p></li>
<li id="fn4"><p>A linear mixed model can refer to any model that contains a group/clustering structure, and it does not have to be a group that is organised hierarchically, or nested.↩︎</p></li>
<li id="fn5"><p>Hierarchical/multilevel models suggest that there might be a vertical hierarchy that explains the grouping structure in the data, for example, student test results are nested within a class or school grouping structure.↩︎</p></li>
<li id="fn6"><p>ARMM hasn’t been published (released?) yet, but it is billed as the updated and expanded second edition of Gelman &amp; Hill’s book. It’s worth keeping an eye out for when this is released, because I’m sure it will be an excellent resource.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2022" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2022. <span>“A Cheatsheet for Building Multilevel Models
in R.”</span> November 1. <a href="https://paulrjohnson.net/blog/2022-11-01-multilevel-model-r-cheatsheet/">https://paulrjohnson.net/blog/2022-11-01-multilevel-model-r-cheatsheet/</a>.
</div></div></section></div> ]]></description>
  <category>Multilevel Regression</category>
  <category>Statistics</category>
  <category>R</category>
  <guid>https://paulrjohnson.net/blog/2022-11-01-multilevel-model-r-cheatsheet/</guid>
  <pubDate>Tue, 01 Nov 2022 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2022-11-01-multilevel-model-r-cheatsheet/hierarchy.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Rendering Mermaid Diagrams on a Hugo Website Using Quarto</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2022-09-17-rendering-mermaid-diagrams-using-quarto-and-hugo/</link>
  <description><![CDATA[ 





<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>Having ported my site over to Quarto in entirety, this blog post no longer applies to the site as is. There are some inconsistencies with some of the issues it talks about and how the site looks now (for example, there is no longer an option to toggle a dark theme), but the advice in this post should hopefully still work for anyone that is using Quarto with Hugo!</p>
</div>
</div>
<p>I find a lot of the methods for drawing diagrams and flow charts using code to be a bit of a nightmare. I’m not sure what it is, perhaps I’m just a bit stupid, but they always seem a little more convoluted than I can handle. It’s possible that the design is actually of some value when it comes to drawing diagrams that are much larger and more complicated than I am generally dealing with, but in my case, it always seems to be a lot of work for what little I’m trying to do.</p>
<p>The easiest, most intuitive way that I’ve come across is using a JavaScript library called Mermaid. It’s just very easy, and the diagrams look great. Even better is the fact that it works with a lot of Markdown formats, and it’s even one of the diagram formats that Quarto can handle.</p>
<p>One issue that I came across, however, is that Mermaid diagrams don’t render when you’re using Quarto to create Hugo Markdown files for a Hugo website. You do have some simple options to resolve this, such as setting the <code>mermaid-format</code> to PNG or SVG in the article front matter, but with just a little extra work, you can get Mermaid working perfectly on your Hugo website.</p>
<section id="setting-up-hugo-to-support-mermaid" class="level2">
<h2 class="anchored" data-anchor-id="setting-up-hugo-to-support-mermaid">Setting up Hugo to Support Mermaid</h2>
<p>Steps for setting up Hugo to support Mermaid are detailed in the <a href="https://gohugo.io/content-management/diagrams/">Hugo documentation</a>, however that didn’t seem to work for me (producing errors when Netlify tries to publish the site). Instead, I had to take a slightly different approach, which was inspired by Kevin Wu’s <a href="https://kvwu.io/posts/hugo-shortcode/">blog post</a> about using Mermaid with Hugo. This <strong>should</strong> work for others, but if it doesn’t, please lets just assume that it is either Kevin’s fault, or your fault, but definitely not my fault.</p>
<p>First, create a HTML file <code>/layours/partials/mermaid.html</code>, and add the following code, which specifies where to find Mermaid and how it should be loaded (in this case I’ve specified the dark theme, but there’s a few different options):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode html code-with-copy"><code class="sourceCode html"><span id="cb1-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">script</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> src</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">script</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb1-2"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">script</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span>mermaid<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">initialize</span>({<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">startOnLoad</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">theme</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"neutral"</span> })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">script</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span></code></pre></div></div>
<p>Following this, a snippet needs to be added to one of the partial layouts that will be used in your content pages. I added it to the <code>extend_head.html</code> file (which, as the name helpfully suggests, is just an extension of <code>head.html</code>). This snippet just tells Hugo that, when Mermaid is called in the frontmatter, it needs to use the <code>mermaid.html</code> partial you just created.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode html code-with-copy"><code class="sourceCode html"><span id="cb2-1">{{ if .Page.Params.mermaid }}</span>
<span id="cb2-2">{{ partial "mermaid.html" . }}</span>
<span id="cb2-3">{{ end }}</span></code></pre></div></div>
<p>This can either be added to the existing theme partial, located in <code>themes/&lt;theme-name&gt;/layouts/partials</code>, or it can be in the global <code>layouts/partials</code> directory, which will override your theme.</p>
<p>Now, you just have to add <code>mermaid: true</code> to the YAML frontmatter for any page that contains a Mermaid code block, and you’re good to go!</p>
</section>
<section id="rendering-mermaid-using-quarto" class="level2">
<h2 class="anchored" data-anchor-id="rendering-mermaid-using-quarto">Rendering Mermaid Using Quarto</h2>
<p>Once you’ve set Hugo up to handle Mermaid code blocks, you would think it should then render like other code chunks in Quarto, and you would be right. Mermaid is very good.</p>
<p>I find that I sometimes have to render the Quarto document a couple times for Mermaid diagrams to show up, or for changes to render properly, but that’s about the only issue that I’ve come up against.</p>
<section id="flowcharts" class="level3">
<h3 class="anchored" data-anchor-id="flowcharts">Flowcharts</h3>
<p>The diagram I will get the most use out of is flowcharts, and Mermaid makes them really easy.</p>
<div class="cell" data-layout-align="center">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb3-1"><span class="in" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">```{mermaid}</span></span>
<span id="cb3-2">%%| label: fig-mermaid-flowchart</span>
<span id="cb3-3">%%| fig-cap: Wow look how it flows.</span>
<span id="cb3-4">%%| fig-alt: An example flowchart, drawn using Mermaid.</span>
<span id="cb3-5"></span>
<span id="cb3-6">graph LR</span>
<span id="cb3-7">    A([Oooh]) --&gt; B([Would You])</span>
<span id="cb3-8">    B --&gt; C([Look at This])</span>
<span id="cb3-9">    C --&gt; D[Very]</span>
<span id="cb3-10">    C --&gt; E[Fancy]</span>
<span id="cb3-11">    C --&gt; F[Flowchart]</span>
<span id="cb3-12"><span class="in" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">```</span></span></code></pre></div></div>
<div class="cell-output-display">
<div id="fig-mermaid-flowchart" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-mermaid-flowchart-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>
<pre class="mermaid mermaid-js" data-label="fig-mermaid-flowchart">graph LR
    A([Oooh]) --&gt; B([Would You])
    B --&gt; C([Look at This])
    C --&gt; D[Very]
    C --&gt; E[Fancy]
    C --&gt; F[Flowchart]
</pre>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-mermaid-flowchart-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Wow look how it flows.
</figcaption>
</figure>
</div>
</div>
</div>
</section>
<section id="gantt-charts" class="level3">
<h3 class="anchored" data-anchor-id="gantt-charts">Gantt Charts</h3>
<p>If Figure&nbsp;1 isn’t enough to convince you, how about some Gantt charts?</p>
<div class="cell" data-layout-align="center">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb4-1"><span class="in" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">```{mermaid}</span></span>
<span id="cb4-2">%%| label: fig-mermaid-gantt</span>
<span id="cb4-3">%%| fig-cap: Oh you real fancy huh?</span>
<span id="cb4-4">%%| fig-alt: An example Gantt chart, drawn using Mermaid.</span>
<span id="cb4-5"></span>
<span id="cb4-6">%<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">%</span>{init: {<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">theme</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span>: <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">default</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span>, <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">themeVariables</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span>: { <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">textColor</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span>: <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">#798189</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span>}}}%%</span>
<span id="cb4-7">gantt</span>
<span id="cb4-8">    title Big Ol<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> Gantts</span></span>
<span id="cb4-9"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">    dateFormat  YYYY-MM-DD</span></span>
<span id="cb4-10"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">    section Section</span></span>
<span id="cb4-11"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">    Some Normal Tasks : done, a1, 2022-09-01, 15d</span></span>
<span id="cb4-12"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">    But Wait, There</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span>s More! :after a1, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>d</span>
<span id="cb4-13">    section And ANOTHER</span>
<span id="cb4-14">    Deary Me, It<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">'</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">s Never Ending : crit, 2022-10-01, 20d</span></span>
<span id="cb4-15"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">    I Hate This Project : 14d</span></span>
<span id="cb4-16"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">```</span></span></code></pre></div></div>
<div class="cell-output-display">
<div id="fig-mermaid-gantt" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-mermaid-gantt-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>
<pre class="mermaid mermaid-js" data-label="fig-mermaid-gantt">%%{init: {'theme': 'default', 'themeVariables': { 'textColor': '#798189'}}}%%
gantt
    title Big Ol' Gantts
    dateFormat  YYYY-MM-DD
    section Section
    Some Normal Tasks : done, a1, 2022-09-01, 15d
    But Wait, There's More! :after a1, 20d
    section And ANOTHER
    Deary Me, It's Never Ending : crit, 2022-10-01, 20d
    I Hate This Project : 14d
</pre>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-mermaid-gantt-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Oh you real fancy huh?
</figcaption>
</figure>
</div>
</div>
</div>
<p>The dark and light theme my Hugo site uses doesn’t handle the Gantt chart as well as the other Mermaid diagrams. If I use the neutral Mermaid theme, it doesn’t show as clearly when using the dark Hugo theme, and vice versa with the dark Mermaid theme and light Hugo theme. This isn’t ideal, but you can <a href="https://mermaid-js.github.io/mermaid/#/theming?id=theme-variables-reference-table">customise the appearance</a> of your Mermaid diagrams too.</p>
<p>I’ve stuck with the neutral Mermaid theme for the rest of the site because it seems to be the best fit for flowcharts with the two different Hugo themes, and flowcharts are the diagrams I’m going to be using Mermaid for most often on this site. However, for Figure&nbsp;2 I’ve customised the appearance a little, using <code>%%init%%</code>, specifying the default theme and a grey text colour that works slightly better (though it’s still not brilliant).</p>
</section>
<section id="git-graphs" class="level3">
<h3 class="anchored" data-anchor-id="git-graphs">Git Graphs</h3>
<p>So you’ve got Figure&nbsp;1 to wow people with your idea and Figure&nbsp;2 to manage the project, but now you need some git graphs to show how you broke everything.</p>
<div class="cell" data-layout-align="center">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb5-1"><span class="in" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">```{mermaid}</span></span>
<span id="cb5-2">%%| label: fig-mermaid-git</span>
<span id="cb5-3">%%| fig-cap: Git a load of this!</span>
<span id="cb5-4">%%| fig-alt: An example Git graph, drawn using Mermaid.</span>
<span id="cb5-5"></span>
<span id="cb5-6">gitGraph</span>
<span id="cb5-7">  commit</span>
<span id="cb5-8">  commit</span>
<span id="cb5-9">  branch develop</span>
<span id="cb5-10">  checkout develop</span>
<span id="cb5-11">  commit</span>
<span id="cb5-12">  commit</span>
<span id="cb5-13">  checkout main</span>
<span id="cb5-14">  merge develop</span>
<span id="cb5-15">  commit</span>
<span id="cb5-16">  commit</span>
<span id="cb5-17"><span class="in" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">```</span></span></code></pre></div></div>
<div class="cell-output-display">
<div id="fig-mermaid-git" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-mermaid-git-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>
<pre class="mermaid mermaid-js" data-label="fig-mermaid-git">gitGraph
  commit
  commit
  branch develop
  checkout develop
  commit
  commit
  checkout main
  merge develop
  commit
  commit
</pre>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-mermaid-git-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: Git a load of this!
</figcaption>
</figure>
</div>
</div>
</div>
</section>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>And that’s about all you need to do. Think of all the amazing diagrams you’re going to create and show the world? I, on the other hand, am going to continue to make minimal diagrams that are completely uninspiring. Have fun!</p>
</section>



<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Preview image by <a href="https://unsplash.com/@daniewizard">Daniella Garcia</a> on <a href="https://unsplash.com/photos/woman-in-black-and-white-bikini-lying-on-white-ceramic-bathtub-jJn9fVPtaNI">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>


</div></section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2022" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2022. <span>“Rendering Mermaid Diagrams on a Hugo Website
Using Quarto.”</span> September 17. <a href="https://paulrjohnson.net/blog/2022-09-17-rendering-mermaid-diagrams-using-quarto-and-hugo/">https://paulrjohnson.net/blog/2022-09-17-rendering-mermaid-diagrams-using-quarto-and-hugo/</a>.
</div></div></section></div> ]]></description>
  <category>Mermaid</category>
  <category>Hugo</category>
  <category>Quarto</category>
  <category>Markdown</category>
  <guid>https://paulrjohnson.net/blog/2022-09-17-rendering-mermaid-diagrams-using-quarto-and-hugo/</guid>
  <pubDate>Sat, 17 Sep 2022 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2022-09-17-rendering-mermaid-diagrams-using-quarto-and-hugo/mermaid.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Setting up a Hugo Website with Quarto</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2022-09-11-setting-up-hugo-website-with-quarto/</link>
  <description><![CDATA[ 





<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>Having ported my site over to Quarto in entirety, this blog post no longer applies to the site as is. This post should hopefully still work for anyone that is using Quarto with Hugo!</p>
</div>
</div>
<p>Like every other nerd that likes R and has used RMarkdown more than one time in their entire life, I am now in the process of transitioning to using Quarto, and I want to let the world know! I wanted to make good use of Quarto, including utilising the really nice job it does with rendering R, Python, Julia, and JavaScript (not that I’m writing a lot of Julia or JavaScript) and outputting it in a HTML document. However, I didn’t want to give up this lovely website I had already put together using Hugo. What a conundrum… Well, it turns out it’s relatively easy to use Quarto with a Hugo site. These folks really have thought of everything!</p>
<p>This isn’t a tutorial for building a Hugo website or building a website from scratch with Quarto. These are more involved processes (though neither are incredibly difficult). If that’s what you’re looking for, here are some links that might point you in the right direction.</p>
<p>Hugo Tutorials:</p>
<ul>
<li><a href="https://gohugo.io/getting-started/quick-start/">Hugo - Quick Start</a></li>
<li><a href="https://www.freecodecamp.org/news/your-first-hugo-blog-a-practical-guide/">freeCodeCamp - How to Create Your First Hugo Blog</a></li>
</ul>
<p>Quarto Tutorials:</p>
<ul>
<li><a href="https://quarto.org/docs/websites/">Quarto - Creating a Website</a></li>
<li><a href="https://beamilz.com/posts/2022-06-05-creating-a-blog-with-quarto/en/">Bea Milz - Creating a Blog with Quarto in 10 Steps</a></li>
<li><a href="https://albert-rapp.de/posts/13_quarto_blog_writing_guide/13_quarto_blog_writing_guide.html">Albert Rapp - The Ultimate Guide to Starting a Quarto Blog</a></li>
</ul>
<p>No, my ambitions with this blog post are considerably less ambitious. I just want to show you how to set your existing Hugo website up so that you can use Quarto to write your blog posts (and any other pages).</p>
<section id="setting-up-hugo-for-quarto-files" class="level2">
<h2 class="anchored" data-anchor-id="setting-up-hugo-for-quarto-files">Setting Up Hugo for Quarto Files</h2>
<p>The first step is to make some changes to your ‘config.toml’ file so that it doesn’t try and publish your Quarto documents, whether they are in qmd or ipynb format. You need to add the following code to the file:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode toml code-with-copy"><code class="sourceCode toml"><span id="cb1-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">ignoreFiles</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">.qmd$"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">.ipynb$"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span></span></code></pre></div></div>
<p>I added it to the opening section of the config file, with the baseUrl, title, theme etc.</p>
<p>You also need to add some configuration to the markup section of the config file, in order to make sure Hugo handles raw HTML appropriately, because R and Python will sometimes give HTML as an output rather than Markdown.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode toml code-with-copy"><code class="sourceCode toml"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">[markup.goldmark.renderer]</span></span>
<span id="cb2-2">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">unsafe</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">true</span></span></code></pre></div></div>
<p>This is essentially everything you need to get your Hugo website set up to deal with Quarto without losing its mind.</p>
</section>
<section id="creating-blog-posts" class="level2">
<h2 class="anchored" data-anchor-id="creating-blog-posts">Creating Blog Posts</h2>
<p>This is the part that I expected to at least be a little bit harder than it turned out to be. Once you have set your config file up, you can now create new posts (and any other pages) in pretty much the same way you did in the before times. In my case, all the blog posts are stored under ‘content/posts’, and it’s the same deal now in this exciting new Quarto world.</p>
<p>Blog posts are written in a qmd file, with the YAML front matter looking much the same as the typical Markdown posts for Hugo sites, with tags, categories, keywords etc., and <code>format: hugo</code> added so that Quarto knows how to render the file. This can be also be added to a ’_quarto.yml’ file, as I have done, if you are treating the site as a Quarto project.</p>
<p>Once you’ve done all this, you can render your Quarto files and it will produce Markdown files that Hugo will publish as blog posts.</p>
</section>
<section id="dont-forget-to-render" class="level2">
<h2 class="anchored" data-anchor-id="dont-forget-to-render">Don’t Forget to Render</h2>
<p>The biggest problem I’ve faced with this process, in the short time since making the change, is that I am a stupid person and that I sometimes do stupid things.</p>
<p>When you’ve written your posts in a qmd file you have to remember to render them as and when you make changes that you want to deploy. I have already managed to forget to do that on a couple occasions, pushing changes that I haven’t rendered, resulting in qmd files that don’t line up with the md file, and therefore don’t show on the site. Think of all the funny things you might write that people won’t get to see, and it’s all your fault. Get in the shame cube!</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://paulrjohnson.net/blog/2022-09-11-setting-up-hugo-website-with-quarto/shame_cube.webp" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:60.0%" alt="A 3D animation from the music video for the song Bumble, by Rx, showing a man sat on the floor with his knees to his chest, as a box labelled Shame Cube is lowered down to cover him."></p>
</figure>
</div>
</section>
<section id="wrapping-up" class="level2">
<h2 class="anchored" data-anchor-id="wrapping-up">Wrapping Up</h2>
<p>The rendering issue isn’t ideal, because as much as I’d like to believe that I will eventually remember that I need to render before I publish posts, I happen to know that I am a buffoon, so I am certain that I will forget enough that it’s going to be a bit of a nuisance.</p>
<p>This should be something that I can resolve by setting up a GitHub Actions workflow to render files when pushed to the repository. It’s not something I’ve done just yet, mostly because it is 8pm on a Sunday and I can’t be bothered to take that extra step right now. But maybe I’ll write another post about that when I get round to it. Because everything is content and everybody is posting.</p>
<p>However, everything else is exceptionally smooth, and very easy to set up. It takes a matter of minutes to make the change and now your Hugo site can be used with Quarto, making it so much easier to write about and incorporate R, Python, and other programming languages in your blog posts. Great success!</p>
</section>


<div id="quarto-appendix" class="default"><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>


</div></section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2022" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2022. <span>“Setting up a Hugo Website with
Quarto.”</span> September 11. <a href="https://paulrjohnson.net/blog/2022-09-11-setting-up-hugo-website-with-quarto/">https://paulrjohnson.net/blog/2022-09-11-setting-up-hugo-website-with-quarto/</a>.
</div></div></section></div> ]]></description>
  <category>Hugo</category>
  <category>Quarto</category>
  <category>Markdown</category>
  <guid>https://paulrjohnson.net/blog/2022-09-11-setting-up-hugo-website-with-quarto/</guid>
  <pubDate>Sun, 11 Sep 2022 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2022-09-11-setting-up-hugo-website-with-quarto/hugo.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Resources for Learning Bayesian Statistics</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2022-05-10-learning-bayesian-statistics/</link>
  <description><![CDATA[ 





<p>As a social scientist turned data scientist, my graduate school training taught me a lot of frequentist statistics that has served me well in my career since. However, there’s one thing that frequentist statistics can’t solve, and that’s my lack of a personality. For that, we’ve got Bayesian statistics, the perfect substitute.</p>
<p>I’ve spent the last year or so gradually trying to become more Bayesian in my approach to statistical reasoning and analysis, and while there’s quite a few really good resources for supporting that journey, it can be a little difficult to know where to start. I wanted someone to give me a short reading list that would save me trying to work out which books to use and in what order. In an attempt to fill that gap, I’ve put together a list of resources that I’ve come across and found to be pretty solid. I’ve not worked through each and every one of these cover to cover, but I’ve interacted with them enough to think they’re useful and that someone might be able to learn a lot from them.</p>
<p>Where possible I’ve tried to find stuff that is free and open-source, but that hasn’t been possible in every single case. But in each case I have at least found a freely available resource that is made available by the authors, whether it be the book itself, a video series, or a series of articles.</p>
<section id="becoming-more-bayesian" class="level2">
<h2 class="anchored" data-anchor-id="becoming-more-bayesian">Becoming More Bayesian</h2>
<p>These first resources are good starting points for anyone looking to start learning more about Bayesian statistics. They’ve all got plenty of detail, but they focus on making the intuition of Bayesianism a little more approachable.</p>
<section id="statistical-rethinking" class="level3">
<h3 class="anchored" data-anchor-id="statistical-rethinking">Statistical Rethinking</h3>
<p>I think the starting point for everybody, and an all-round great resource for anyone interested in statistics, is Richard McElreath’s <a href="https://xcelab.net/rm/statistical-rethinking/"><em>Statistical Rethinking</em></a>. If you read only one of these books, make it <em>Statistical Rethinking</em>. It’s a great read for anybody interested in statistics and quantitative research.</p>
<p>The focus of <em>Statistical Rethinking</em> is utilizing Bayesian statistics for scientific reasoning/thinking and causal inference. It’s a really great read, in part because it is really accessible while also being pretty thorough too. I particularly like his consistent focus on how these tools apply to scientific models.</p>
<p>Not only is it available as a book, but Richard also makes a <a href="https://www.youtube.com/playlist?list=PLDcUM9US4XdMROZ57-OIRtIK0aOynbgZN">lecture series</a> available on YouTube which can serve as an accompaniment to the book, or can even stand on its own as a good learning resource.</p>
</section>
<section id="students-guide-to-bayesian-statistics" class="level3">
<h3 class="anchored" data-anchor-id="students-guide-to-bayesian-statistics">Student’s Guide to Bayesian Statistics</h3>
<p>Ben Lambert’s <a href="https://ben-lambert.com/a-students-guide-to-bayesian-statistics/"><em>A Student’s Guide to Bayesian Statistics</em></a> is a really good dive into the statistics that underpin Bayesian analysis, and the implementation of the statistical methods. It’s not light on notation, but it does introduce new concepts by first explaining the intuition before laying it out mathematically. I think this book pairs very well with <em>Statistical Rethinking</em>, as they take slightly different approaches, and between the two you cover tons of ground.</p>
<p>You can buy the book on <a href="https://www.amazon.co.uk/Students-Guide-Bayesian-Statistics/dp/1473916364/">Amazon</a> but it isn’t freely available anywhere (that I’ve found). Ben does offer a free <a href="https://youtu.be/P_og8H-VkIY">YouTube course</a> and <a href="https://ben-lambert.com/bayesian-lecture-slides/">lecture notes</a> that mirror the book’s content though. The YouTube course doesn’t offer the kind of detail that the book does, but it is still pretty good.</p>
</section>
<section id="introduction-to-empirical-bayes" class="level3">
<h3 class="anchored" data-anchor-id="introduction-to-empirical-bayes">Introduction to Empirical Bayes</h3>
<p>If you’re looking for something to help you apply Bayesian statistics to a real-world situation, or you’re the kind of learner that needs a relatable hook to help you make sense of things (this is me), then David Robinson’s <a href="http://varianceexplained.org/r/empirical-bayes-book/"><em>Introduction to Empirical Bayes</em></a> is the perfect starting point. David applies Empirical Bayes methods (Bayesian approaches where the prior is estimated from the data) in a baseball context, specifically simulating batting averages. Baseball isn’t really the focus of David’s work here, but it serves as a really good medium for couching some quite complicated concepts in terms that people can understand, and thanks to this (and David’s excellent communication of the concepts), it is a really good opening gambit for anyone interested in Bayesian statistics.</p>
<p>The <em>Introduction to Empirical Bayes</em> book started out as a series of <a href="http://varianceexplained.org/statistics/beta_distribution_and_baseball/">blog posts</a> on David’s website, <a href="http://varianceexplained.org">Variance Explained</a>, and those blog posts are all still freely available, but his e-book also includes an extra chapter, some additional materials across several other chapters, and some minor edits and changes to help simplify things. The book is also available at a “pay-what-you-want” price, which means you can choose to pay nothing, if you can’t afford to pay more, but for those that can, the suggested price is $9.95 (~£8).</p>
<p>I don’t think that David’s e-book/blog posts are the most thorough of the resources listed here, but they’re also not trying to be. Instead, they’re a really good plain(ish)-English explanation of Bayesian concepts, applied to examples that should help a lot of people intuit them a little easier. The use of Empirical Bayes serves as a good first step in the direction of Bayesian approaches, and it is also a good way to learn some really useful methods in real-world data analysis. If you find that some of the other resources are a little hard to wrap your head round, I’d read all of his posts (or buy his book if you can afford to) first, because it might help lay the groundwork for your learning journey.</p>
</section>
<section id="think-bayes" class="level3">
<h3 class="anchored" data-anchor-id="think-bayes">Think Bayes</h3>
<p>The vast majority of the resources listed here use R for implementation. I think that’s because the packages for computing Bayesian models in R are much easier to navigate than their alternatives in Python. However, if you’re coming at this as someone with limited or no knowledge of R and no interest in changing that, then <a href="https://www.allendowney.com/wp/">Allen Downey</a>’s <a href="http://allendowney.github.io/ThinkBayes2/index.html"><em>Think Bayes</em></a> is worth a look. <em>Think Bayes</em> takes a code-first approach to teaching Bayesian concepts, rather than using notation and illustrating ideas using concepts like calculus. For anyone that uses Python and would learn better through concepts being explained through code, this book is a great start.</p>
</section>
</section>
<section id="building-a-stronger-understanding" class="level2">
<h2 class="anchored" data-anchor-id="building-a-stronger-understanding">Building a Stronger Understanding</h2>
<p>The following resources would serve as great next steps for someone looking to build on their understanding of Bayesianism, whether it be an extremely thorough exploration of the mathematics underpinning the methods, or detailed documentation of the code for the computation of Bayesian methods.</p>
<section id="bayesian-data-analysis" class="level3">
<h3 class="anchored" data-anchor-id="bayesian-data-analysis">Bayesian Data Analysis</h3>
<p>Everything <a href="https://statmodeling.stat.columbia.edu/">Andrew Gelman</a> does is good, and <a href="http://www.stat.columbia.edu/~gelman/book/"><em>Bayesian Data Analysis</em></a> (co-authored with John B. Carlin, Hal S. Stern, David B. Dunson, Aki Vehtari, and Donald B. Rubin) is yet more proof of that. It’s a really extensive book covering the fundamentals of Bayesian inference, analysis, and methods.</p>
<p>I think <em>Bayesian Data Analysis</em> might be a little heavier going if you’re just starting out, but the book is also supplemented by an <a href="https://avehtari.github.io/BDA_course_Aalto/">online course</a> made available by <a href="https://users.aalto.fi/~ave/">Aki Vehtari</a>, with lecture slides and videos to help bridge any gaps in understanding.</p>
<p>The book and the course are excellent resources for those looking to build on foundational knowledge (perhaps developed using the earlier resources). It’s probably the most thorough of all the resources here, so if you’re comfortable with mathematical notation and only want to read one book, this might be your best bet.</p>
</section>
<section id="stan-documentation" class="level3">
<h3 class="anchored" data-anchor-id="stan-documentation">Stan Documentation</h3>
<p>Stan is a probabilistic programming language for implementing Bayesian statistical models. It’s the language that underpins the computation of Bayesian methods, and there are interfaces that make it accessible in a number of different languages, including R, Python, and Julia (for those of you looking to intimidate your peers).</p>
<p>The <a href="https://mc-stan.org/users/documentation/">Stan documentation</a>, and the documentation for the R interface to Stan, <a href="https://mc-stan.org/rstan/">RStan</a>, and the Python equivalent, <a href="https://pystan.readthedocs.io/en/latest/">PyStan</a> are good resources for learning how to implement a variety of Bayesian models.</p>
</section>
</section>
<section id="beyond-bayes" class="level2">
<h2 class="anchored" data-anchor-id="beyond-bayes">Beyond Bayes</h2>
<p>Finally, there are books that are worth a mention because they are really good resources that, while not focused entirely on Bayesian statistics, do a great job of placing Bayesian approaches in the context of wider statistical methods.</p>
<section id="regression-and-other-stories" class="level3">
<h3 class="anchored" data-anchor-id="regression-and-other-stories">Regression and Other Stories</h3>
<p>More Gelman. I have no regrets! <a href="https://avehtari.github.io/ROS-Examples/"><em>Regression and Other Stories</em></a> is co-authored with Jennifer Hill and Aki Vehtari, and it will serve you brilliantly if you’re looking to learn about Bayesian approaches while also covering the frequentist methods too. It is a book that focuses on the application of regression to real-world problems and the challenges users will face in the process.</p>
<p>While the focus of the book is regression, it incorporates Bayesian inference and methods across the book, and this might be useful to anyone wanting a broader education in statistical analysis that includes Bayesian approaches.</p>
</section>
<section id="probabilistic-machine-learning" class="level3">
<h3 class="anchored" data-anchor-id="probabilistic-machine-learning">Probabilistic Machine Learning</h3>
<p>If you’re looking to apply your newly developed Bayesian principles to machine learning, then <a href="https://probml.github.io/pml-book/book1.html"><em>Probabilistic Machine Learning: An Introduction</em></a> by <a href="https://www.cs.ubc.ca/~murphyk/">Kevin Patrick Murphy</a> is a great start.</p>
<p>It’s not specifically a Bayesian machine learning book, but probabilistic machine learning incorporates a lot of Bayesian principles, and there’s plenty of explicitly Bayesian tools in the book too. If you’ve cracked several of the resources in this list and are looking to take your next step, I think this would be a great direction.</p>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>I think that having a good understanding of Bayes rule is really important for anyone working in or around statistics, because it helps inform the way you reason about statistics, and it helps you interrogate your approach to analysis in a more thorough manner. Getting a good intuition for Bayesian thinking is relatively simple, but if you’re looking to go a little further, it does require a bit of work. I think there are tons of really good resources out there to take those next steps, but I don’t think they’re as easy to track down as they could be. Hopefully this list will bridge that gap for a few people.</p>
</section>


<div id="quarto-appendix" class="default"><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>


</div></section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2022" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2022. <span>“Resources for Learning Bayesian
Statistics.”</span> May 10. <a href="https://paulrjohnson.net/blog/2022-05-10-learning-bayesian-statistics/">https://paulrjohnson.net/blog/2022-05-10-learning-bayesian-statistics/</a>.
</div></div></section></div> ]]></description>
  <category>Bayesian Statistics</category>
  <category>Statistics</category>
  <guid>https://paulrjohnson.net/blog/2022-05-10-learning-bayesian-statistics/</guid>
  <pubDate>Tue, 10 May 2022 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2022-05-10-learning-bayesian-statistics/bayes.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Combining Tidymodels &amp; Caret for Machine Learning in R</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2022-05-07-combining-tidymodels-and-caret/</link>
  <description><![CDATA[ 





<p>The two main approaches to building machine learning models in R are <a href="https://github.com/topepo/caret/"><strong>caret</strong></a> and <a href="https://www.tidymodels.org/"><strong>tidymodels</strong></a>. Having tried both, I found that I struggled to pick my favorite. There’s elements of both that made more intuitive sense to me than the other. I think it’s a product of having become very familiar with the <strong>tidyverse</strong>, particularly <strong>dplyr</strong>, for data wrangling, but still using a lot of Base R functions for statistical modeling.</p>
<p>The process for prepping the data for a machine learning model seems to make a ton of sense to me when done in <strong>tidymodels</strong> (using <a href="https://recipes.tidymodels.org/"><strong>recipes</strong></a> and <a href="https://rsample.tidymodels.org/"><strong>rsample</strong></a>), but the equivalent process using <strong>caret</strong> felt a little clunky. However, specifying and training models using <strong>caret</strong> made a lot of sense to my broken brain.</p>
<p>Anyway, I recently discovered something that is probably entirely unremarkable to everyone else, and that probably shouldn’t have taken me by surprise… You can just combine the two! You can split and preprocess your data using the <strong>tidymodels</strong> framework before defecting to <strong>caret</strong> for the next steps. What a time to be alive.</p>
<section id="predicting-diabetes-using-random-forest" class="level2">
<h2 class="anchored" data-anchor-id="predicting-diabetes-using-random-forest">Predicting Diabetes Using Random Forest</h2>
<p>Because I’m not a savage, I won’t leave you without a simple worked example. We’ll use <a href="https://hutsons-hacks.info/">Gary Hutson</a>’s really useful <a href="https://cran.r-project.org/web/packages/MLDataR/vignettes/MLDataR.html"><strong>MLDataR</strong></a> package to grab a toy diabetes dataset, cleaning the variable names using <a href="http://sfirke.github.io/janitor/"><strong>janitor</strong></a>, and converting the target variable, <em>diabetic_class</em>, to a factor.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import packages</span></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">suppressPackageStartupMessages</span>({</span>
<span id="cb1-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(dplyr)</span>
<span id="cb1-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(caret)</span>
<span id="cb1-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(recipes)</span>
<span id="cb1-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(randomForest)</span>
<span id="cb1-7">})</span>
<span id="cb1-8"></span>
<span id="cb1-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># load data</span></span>
<span id="cb1-10">diabetes_raw <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> MLDataR<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>diabetes_data</span>
<span id="cb1-11"></span>
<span id="cb1-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># clean data</span></span>
<span id="cb1-13">df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb1-14">  diabetes_raw <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-15">  janitor<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">clean_names</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb1-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">diabetic_class =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.factor</span>(diabetic_class))</span></code></pre></div></div>
</div>
<section id="traintest-splits" class="level3">
<h3 class="anchored" data-anchor-id="traintest-splits">Train/Test Splits</h3>
<p>Having done this, we can use <strong>rsample</strong> to split the data into a train and test set.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set random seed</span></span>
<span id="cb2-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">456</span>)</span>
<span id="cb2-3"></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># split train/test data</span></span>
<span id="cb2-5">train_test_split <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb2-6">  rsample<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">initial_split</span>(df, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">strata =</span> diabetic_class, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prop =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb2-7"></span>
<span id="cb2-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># create train/test sets</span></span>
<span id="cb2-9">train_df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> rsample<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">training</span>(train_test_split)</span>
<span id="cb2-10">test_df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> rsample<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">testing</span>(train_test_split)</span></code></pre></div></div>
</div>
</section>
<section id="data-preprocessing" class="level3">
<h3 class="anchored" data-anchor-id="data-preprocessing">Data Preprocessing</h3>
<p>The next step is a little more involved, and is where I think <strong>tidymodels</strong> really excels. Using the <strong>recipes</strong> package, we can specify all the preprocessing steps needed for the dataset, such that the data will then be ready for training a machine learning model.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># preprocessing</span></span>
<span id="cb3-2">model_recipe <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb3-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">recipe</span>(diabetic_class <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> ., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> train_df) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-4">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># combine low frequency factor levels</span></span>
<span id="cb3-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_other</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all_nominal</span>(), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">threshold =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-6">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># remove predictors with zero variance</span></span>
<span id="cb3-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_nzv</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all_predictors</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-8">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># normalize numeric variables (sigma = 1, mu = 0)</span></span>
<span id="cb3-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_normalize</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all_numeric</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb3-10">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># convert nominal variables to numeric binary variables</span></span>
<span id="cb3-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_dummy</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all_nominal</span>(), <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all_outcomes</span>(), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">one_hot =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
</div>
<p>You can check that all the preprocessing steps are working as expected by using <em>prep()</em> and <em>juice()</em>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># check preprocessing results</span></span>
<span id="cb4-2">model_recipe <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prep</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">juice</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb4-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glimpse</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Rows: 364
Columns: 32
$ age                    &lt;dbl&gt; -0.67696788, -1.18732268, -1.52755921, 1.619628…
$ diabetic_class         &lt;fct&gt; Negative, Negative, Negative, Negative, Negativ…
$ gender_Female          &lt;dbl&gt; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ gender_Male            &lt;dbl&gt; 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ excess_urination_No    &lt;dbl&gt; 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ excess_urination_Yes   &lt;dbl&gt; 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ polydipsia_No          &lt;dbl&gt; 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,…
$ polydipsia_Yes         &lt;dbl&gt; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,…
$ weight_loss_sudden_No  &lt;dbl&gt; 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,…
$ weight_loss_sudden_Yes &lt;dbl&gt; 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,…
$ fatigue_No             &lt;dbl&gt; 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0,…
$ fatigue_Yes            &lt;dbl&gt; 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1,…
$ polyphagia_No          &lt;dbl&gt; 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1,…
$ polyphagia_Yes         &lt;dbl&gt; 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,…
$ genital_thrush_No      &lt;dbl&gt; 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0,…
$ genital_thrush_Yes     &lt;dbl&gt; 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1,…
$ blurred_vision_No      &lt;dbl&gt; 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,…
$ blurred_vision_Yes     &lt;dbl&gt; 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,…
$ itching_No             &lt;dbl&gt; 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0,…
$ itching_Yes            &lt;dbl&gt; 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1,…
$ irritability_No        &lt;dbl&gt; 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1,…
$ irritability_Yes       &lt;dbl&gt; 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,…
$ delay_healing_No       &lt;dbl&gt; 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,…
$ delay_healing_Yes      &lt;dbl&gt; 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,…
$ partial_psoriasis_No   &lt;dbl&gt; 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,…
$ partial_psoriasis_Yes  &lt;dbl&gt; 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,…
$ muscle_stiffness_No    &lt;dbl&gt; 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,…
$ muscle_stiffness_Yes   &lt;dbl&gt; 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,…
$ alopecia_No            &lt;dbl&gt; 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0,…
$ alopecia_Yes           &lt;dbl&gt; 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1,…
$ obesity_No             &lt;dbl&gt; 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,…
$ obesity_Yes            &lt;dbl&gt; 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,…</code></pre>
</div>
</div>
<p>If everything looks alright, you can take the <em>model_recipe</em> object that you’ve created and use it as the model formula that you would otherwise have to specify in the <strong>caret</strong> <em>train()</em> function.</p>
</section>
<section id="model-training" class="level3">
<h3 class="anchored" data-anchor-id="model-training">Model Training</h3>
<p>For the rest of the process, you can switch over to <strong>caret</strong>, first using the <em>trainControl()</em> function to specify the training parameters and then the <em>train()</em> function for the model training.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set random seed</span></span>
<span id="cb6-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">456</span>)</span>
<span id="cb6-3"></span>
<span id="cb6-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># control parameters for model training</span></span>
<span id="cb6-5">ctrl <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb6-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">trainControl</span>(</span>
<span id="cb6-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cv"</span>,</span>
<span id="cb6-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">number =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb6-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">classProbs =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,</span>
<span id="cb6-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">summaryFunction =</span> twoClassSummary</span>
<span id="cb6-11">  )</span>
<span id="cb6-12"></span>
<span id="cb6-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># train random forest model</span></span>
<span id="cb6-14">rf_mod <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb6-15">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">train</span>(</span>
<span id="cb6-16">    model_recipe,</span>
<span id="cb6-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> train_df,</span>
<span id="cb6-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rf"</span>,</span>
<span id="cb6-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tunelength =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>,</span>
<span id="cb6-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">metric =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ROC"</span>,</span>
<span id="cb6-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">trControl =</span> ctrl,</span>
<span id="cb6-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">importance =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb6-23">  )</span></code></pre></div></div>
</div>
<p>Having trained the random forest model, you can check the performance, and see what parameters were chosen in the tuning process.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># check results</span></span>
<span id="cb7-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(rf_mod)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Random Forest 

364 samples
 16 predictor
  2 classes: 'Negative', 'Positive' 

Recipe steps: other, nzv, normalize, dummy 
Resampling: Cross-Validated (5 fold) 
Summary of sample sizes: 292, 291, 291, 291, 291 
Resampling results across tuning parameters:

  mtry  ROC        Sens       Spec     
   2    0.9947186  0.9500000  0.9372727
  16    0.9865188  0.9428571  0.9326263
  31    0.9839791  0.9428571  0.9235354

ROC was used to select the optimal model using the largest value.
The final value used for the model was mtry = 2.</code></pre>
</div>
</div>
<p>Not bad! The best performing model has an ROC of 0.995 and both the sensitivity and specificity are ~0.95. Pretty solid for a quick and easy model.</p>
</section>
<section id="test-predictions" class="level3">
<h3 class="anchored" data-anchor-id="test-predictions">Test Predictions</h3>
<p>To really test the model’s performance, we want to see how it copes with the test data that it hasn’t seen.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># make predictions on test data</span></span>
<span id="cb9-2">rf_predict <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(rf_mod, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> test_df, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"prob"</span>)</span>
<span id="cb9-3">rf_class <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(rf_mod, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> test_df, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"raw"</span>)</span>
<span id="cb9-4"></span>
<span id="cb9-5">preds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb9-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(rf_predict, rf_class) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb9-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb9-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Positive =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(Positive, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">digits =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>),</span>
<span id="cb9-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Negative =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(Negative, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">digits =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb9-10">  )</span></code></pre></div></div>
</div>
<p>Finally, we can produce a confidence matrix for a more intuitive look at how the model is performing on the test set.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1">cm_class <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> test_df[, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(test_df) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"diabetic_class"</span>)]</span>
<span id="cb10-2"></span>
<span id="cb10-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">confusionMatrix</span>(</span>
<span id="cb10-4">  rf_class,</span>
<span id="cb10-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.factor</span>(cm_class<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>diabetic_class),</span>
<span id="cb10-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">positive =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Positive"</span></span>
<span id="cb10-7">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Confusion Matrix and Statistics

          Reference
Prediction Negative Positive
  Negative       57        1
  Positive        3       95
                                         
               Accuracy : 0.9744         
                 95% CI : (0.9357, 0.993)
    No Information Rate : 0.6154         
    P-Value [Acc &gt; NIR] : &lt;2e-16         
                                         
                  Kappa : 0.9455         
                                         
 Mcnemar's Test P-Value : 0.6171         
                                         
            Sensitivity : 0.9896         
            Specificity : 0.9500         
         Pos Pred Value : 0.9694         
         Neg Pred Value : 0.9828         
             Prevalence : 0.6154         
         Detection Rate : 0.6090         
   Detection Prevalence : 0.6282         
      Balanced Accuracy : 0.9698         
                                         
       'Positive' Class : Positive       
                                         </code></pre>
</div>
</div>
<p>The results are pretty good for a very quick model. How exciting. Lets pretend that it’s because I’m a brilliant data scientist rather than it being due to the very clean, balanced toy dataset we used.</p>
</section>
</section>
<section id="wrapping-up" class="level2">
<h2 class="anchored" data-anchor-id="wrapping-up">Wrapping Up</h2>
<p>So there you have it, if you’re in the same position as me and you’re struggling to pick between <strong>tidymodels</strong> and <strong>caret</strong>, because both frameworks offer something you like, you can just combine the two and make Frankenstein’s framework.</p>
<p>Ultimately, despite this blog post, I’m probably going to stick with <strong>tidymodels</strong> (why am I like this?). I think that I’m going to force myself to get used to the <strong>tidymodels</strong> framework end-to-end because a) it is receiving tons of development so it’s probably going to continue to get better and bigger, and will be leading the way for the foreseeable future, and b) because in reality I think the explicit way that you structure each step is probably sensible, even if it confuses me a bit.</p>
<p>But it’s nice to know that I’ve got options.</p>
</section>



<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Preview image by <a href="https://unsplash.com/@rocknrollmonkey">Rock’n Roll Monkey</a> on <a href="https://unsplash.com/photos/blue-plastic-robot-toy-R4WCbazrD1g">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>


</div></section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2022" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2022. <span>“Combining Tidymodels &amp; Caret for Machine
Learning in R.”</span> May 7. <a href="https://paulrjohnson.net/blog/2022-05-07-combining-tidymodels-and-caret/">https://paulrjohnson.net/blog/2022-05-07-combining-tidymodels-and-caret/</a>.
</div></div></section></div> ]]></description>
  <category>Machine Learning</category>
  <category>Caret</category>
  <category>Tidymodels</category>
  <category>R</category>
  <guid>https://paulrjohnson.net/blog/2022-05-07-combining-tidymodels-and-caret/</guid>
  <pubDate>Sat, 07 May 2022 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2022-05-07-combining-tidymodels-and-caret/robot.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Make More Packages!</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2022-02-19-make-more-packages/</link>
  <description><![CDATA[ 





<p>Having learned R in an academic context, I wasn’t exposed to programming in a linear path that taught me the basics of programming theory and application. I learned how to carry out statistical analysis using R, and my interaction with packages was that they would help me get the job done without having to do everything manually. As a result, package development has always intimidated me a little bit. It seemed like the responsibility of much smarter people that know what they’re doing, and that can build packages that can help me figure out what I’m doing too.</p>
<p>To be fair, that was probably an accurate description of my situation for… a good few years of my time using R. But practice makes you less bad at things, and over time I’ve gone from being someone that uses R like it’s a boiling pot of oil that they’re about to chuck a fistful of frozen chips at for the first time, to someone that has full confidence that they can’t do any damage because they’ve already burned the house down anyway.</p>
<p>That is (mostly) a lie. I’m now (mostly) good at what I do. But that didn’t stop package development being a process that intimidated me.</p>
<p>However, I recently made the jump into some basic package development as a result of working on an internal package that I am helping to develop. While it wasn’t being built entirely from scratch, this package was a good opportunity for me to play around with some cool functions and learn about package infrastructure. Having done so, I realised that the process is actually pretty painless.</p>
<p>To follow-up on what I’d learned, I decided to build my own (stupid but funny) package from scratch, and made <a href="https://github.com/Paulj1989/nice"><strong>nice</strong></a>.</p>
<p>Now, I thought I would write this short blog post detailing the process for creating a very basic package, in the hope that it might help someone else overcome an imagined barrier to entry. I will run through the process of setting up a package, adding some simple functions, and then building out the basic infrastructure with documentation and testing, using <strong>nice</strong> as an example.</p>
<section id="initial-setup" class="level2">
<h2 class="anchored" data-anchor-id="initial-setup">Initial Setup</h2>
<p>In order to build a basic package from scratch, you should only need to rely on four different packages that will aid you in setting everything up, building the correct infrastructure, and documenting and testing your functions.</p>
<p>The packages you need:</p>
<ul>
<li><a href="https://devtools.r-lib.org/"><strong>devtools</strong></a></li>
<li><a href="https://usethis.r-lib.org/"><strong>usethis</strong></a></li>
<li><a href="https://roxygen2.r-lib.org/"><strong>roxygen2</strong></a></li>
<li><a href="https://testthat.r-lib.org/"><strong>testthat</strong></a></li>
</ul>
<p><strong>devtools</strong> is responsible for the majority of the functions you’ll need to build and maintain a package and <strong>usethis</strong> handles the initial setup of the project, while <strong>roxygen2</strong> helps you document your package, and <strong>testthat</strong> simplifies unit testing.</p>
</section>
<section id="functions" class="level2">
<h2 class="anchored" data-anchor-id="functions">Functions</h2>
<p>Packages are effectively just a way of housing and distributing functions. If you’re making a package, you’ll need some functions! They don’t need to be wildly complex. They just need to work, and ideally they would be reasonably useful too. However, in the absence of useful functions, we’ve got an example of a funny function instead:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1">check <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x) {</span>
<span id="cb1-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">69</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.69</span>)) {</span>
<span id="cb1-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Nice!"</span>)</span>
<span id="cb1-4">  } <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> {</span>
<span id="cb1-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Not very nice."</span>)</span>
<span id="cb1-6">  }</span>
<span id="cb1-7">}</span></code></pre></div></div>
</div>
<p>This is very simple. All it is doing is checking if an object <em>x</em> matches either the number 69 or 0.69. If it does, then it returns “Nice!”, and if it doesn’t, it returns “Not very nice.”. If you’re just looking to build a basic package as a means of learning how to do so, this is all you need! You can build on this iteratively, as you become more confident with package development, or come up with other useful functions your package should include.</p>
<p>I think it is generally best practice to dedicate a different file to each individual function, though it’s not absolutely necessary. If you choose to, you can store all your functions in one file, and this might be a sensible approach if you’re creating a package that contains all your miscellaneous functions. However, for anything a little more meaty than that, I think the best approach is to split out everything into files for each function. That makes it easier for someone (likely including yourself) to navigate the source code.</p>
</section>
<section id="documentation" class="level2">
<h2 class="anchored" data-anchor-id="documentation">Documentation</h2>
<p>The next step is to document your package, so anyone using it will have some guidance on what they’re doing and why. Documentation doesn’t need to be complicated, though if the function it is documenting is pretty complex, it should probably go into plenty of detail to help anyone trying to use it. In the <strong>nice</strong> example, the functions are super simple, so there’s no sense in overdoing the docs either.</p>
<p>You need to add comments at the beginning of your function script which explain what the function does, details any of the required parameters for the function to run, and give some examples of usage. In order for <strong>roxygen2</strong> to recognise the comments that need to be turned into documentation, you have to add #’ in front of them.</p>
<p>Below is a basic example of what is needed, corresponding to the <strong>nice</strong> check function above:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' Checking whether your R output is really nice</span></span>
<span id="cb2-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'</span></span>
<span id="cb2-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @keywords nice</span></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @export</span></span>
<span id="cb2-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @examples</span></span>
<span id="cb2-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' check(69)</span></span>
<span id="cb2-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'</span></span></code></pre></div></div>
</div>
<p>Having done this, devtools will process the documentation so that it all works as expected:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">devtools<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">document</span>()</span></code></pre></div></div>
</div>
<p>You can get a look at your documentation by calling <code>?function</code> like you normally would. In this case, calling <code>?check</code> returns the documentation for the <strong>nice</strong> check function.</p>
</section>
<section id="testing" class="level2">
<h2 class="anchored" data-anchor-id="testing">Testing</h2>
<p>In order to reduce the likelihood that your package becomes a mess of errors, it is important to test it. The best way of doing this is automating your tests, to make everything reproducible, and reduce your own opportunities to do anything stupid!</p>
<p>To set up your tests, the following creates a new script for all tests of the particular function(s) you’re working on.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">usethis<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">use_test</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"name"</span>)</span></code></pre></div></div>
</div>
<p>An example of a basic test:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">test_that</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"check returns correct type of response"</span>, {</span>
<span id="cb5-2">  nice <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">check</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">69</span>)</span>
<span id="cb5-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">expect_type</span>(nice, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"character"</span>)</span>
<span id="cb5-4">})</span></code></pre></div></div>
</div>
<p>This test is, as it describes, checking that <code>check()</code> is returning the right type of output when it runs. The test creates an object called <code>nice</code> that contains the output from the <code>check()</code> function, when the input it receives is 69. The test expects the object to be of type character, and if that is so, then it will pass the test. If you want to build further tests for this particular function, you could check that the function correctly recognises whether the input is nice or not, and returns the correct response.</p>
<p>This would look as follows:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">test_that</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"check returns correct positive response"</span>, {</span>
<span id="cb6-2">  nice <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">check</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">69</span>)</span>
<span id="cb6-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">expect_equal</span>(nice, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Nice!"</span>)</span>
<span id="cb6-4">})</span></code></pre></div></div>
</div>
<p>Once you have set up some tests that you want to use to check your functions, you can run those tests by calling on devtools:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1">devtools<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">test</span>()</span></code></pre></div></div>
</div>
<p>This will run through each test and check that it returns the expected output. If it doesn’t it will show that it has failed, and show you where exactly that failure has occurred, in order to help you fix it. If it has worked, then you’re all good!</p>
</section>
<section id="further-reading" class="level2">
<h2 class="anchored" data-anchor-id="further-reading">Further Reading</h2>
<p>This was a very, very quick run-through on how to create a basic package, just to get started, but if you want to make something that is a little more useful than some dumb function to check if your outputs are nice, then there’s plenty of resources for how to take your packages from basics to CRAN and beyond.</p>
<p>The starting point, as is often the case, is Hadley Wickham. Hadley Wickham and Jenny Bryan’s <a href="https://r-pkgs.org/index.html"><em>R Packages</em></a> is an excellent resource for learning to make some killer packages. And if you’re looking to learn how to build the kind of functions that belong in those killer packages, then Hadley Wickham’s <a href="https://adv-r.hadley.nz/"><em>Advanced R</em></a> will get you most of the way there.</p>
</section>



<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Preview image by <a href="https://unsplash.com/@jiaweizhao">Jiawei Zhao</a> on <a href="https://unsplash.com/photos/tuxedo-cat-in-brown-cardboard-box-W-ypTC6R7_k">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>


</div></section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2022" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2022. <span>“Make More Packages!”</span> February 19. <a href="https://paulrjohnson.net/blog/2022-02-19-make-more-packages/">https://paulrjohnson.net/blog/2022-02-19-make-more-packages/</a>.
</div></div></section></div> ]]></description>
  <category>Packages</category>
  <category>R</category>
  <guid>https://paulrjohnson.net/blog/2022-02-19-make-more-packages/</guid>
  <pubDate>Sat, 19 Feb 2022 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2022-02-19-make-more-packages/package.webp" medium="image" type="image/webp"/>
</item>
<item>
  <title>Making Myself Accountable</title>
  <dc:creator>Paul Johnson</dc:creator>
  <link>https://paulrjohnson.net/blog/2022-01-17-making-myself-accountable/</link>
  <description><![CDATA[ 





<p>One of my goals when setting up this site was to use the blog section reasonably frequently to share some of my work and share anything particularly interesting that I’ve learned in my development as a data scientist. There hasn’t been much sharing going on. I’d like to think that isn’t because I haven’t done or learned anything interesting (…), I just haven’t found the time to share it.</p>
<p>I’m the ideas man. No one told me I’d also have to be the one to finish the ideas too. That seems deeply unfair.</p>
<p>But having realized that everything I’ve thought about sharing either hasn’t made it out of my head, or has been shared with friends in the form of a dumb joke, I’m looking to set myself some goals that will make the blog a little more active. So I’m using this space as an opportunity to hold myself accountable to my own fantastical intentions.</p>
<p>Over the course of the next 12 months, I’m going to try and average a blog post a month, around data science generally, and anything cool that I’m either learning or doing.</p>
<p>Given that everything is posting and everyone is a poster, it’s time I put some hours in at the content factory. New Year, New Me.</p>



<div id="quarto-appendix" class="default"><section id="acknowledgments" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Acknowledgments</h2><div class="quarto-appendix-contents">

<p>Preview image by <a href="https://unsplash.com/@jacklucassmith">Jack Lucas Smith</a> on <a href="https://unsplash.com/photos/white-and-black-police-car-on-road-during-daytime-UqvSeGmFYBs">Unsplash</a>.</p>
</div></section><section id="support" class="level2 appendix"><h2 class="anchored quarto-appendix-heading">Support</h2><div class="quarto-appendix-contents">

<p>If you enjoyed this blog post and would like to support my work, you can <a href="https://www.buymeacoffee.com/paulj1989">buy me a coffee or a beer or give me a tip</a> as a thank you.</p>


</div></section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-johnson2022" class="csl-entry quarto-appendix-citeas">
Johnson, Paul. 2022. <span>“Making Myself Accountable.”</span> January
17. <a href="https://paulrjohnson.net/blog/2022-01-17-making-myself-accountable/">https://paulrjohnson.net/blog/2022-01-17-making-myself-accountable/</a>.
</div></div></section></div> ]]></description>
  <category>Me Me Me</category>
  <category>Updates</category>
  <guid>https://paulrjohnson.net/blog/2022-01-17-making-myself-accountable/</guid>
  <pubDate>Mon, 17 Jan 2022 00:00:00 GMT</pubDate>
  <media:content url="https://paulrjohnson.net/blog/2022-01-17-making-myself-accountable/police.webp" medium="image" type="image/webp"/>
</item>
</channel>
</rss>
