<?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>Running on Numbers</title>
<link>https://runningonnumbers.com/</link>
<atom:link href="https://runningonnumbers.com/index.xml" rel="self" type="application/rss+xml"/>
<description>Machine Learning and Baseball Analytics</description>
<generator>quarto-1.7.29</generator>
<lastBuildDate>Sun, 25 Jan 2026 06:00:00 GMT</lastBuildDate>
<item>
  <title>The $240 Million Man: Projecting Kyle Tucker’s 2026 in Blue</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/kyle-tucker-projection/</link>
  <description><![CDATA[ 





<iframe src="https://streamable.com/m/kyle-tucker-homers-22-on-a-fly-ball-to-left-center-field-kevin-alcantara?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<section id="introduction" class="level1">
<h1>Introduction</h1>
<p>The <a href="https://www.espn.com/mlb/story/_/id/47625742/sources-dodgers-land-prized-free-agent-kyle-tucker">Los Angeles Dodgers</a> once again dominated the headlines in January 2026, securing superstar outfielder Kyle Tucker with a massive four-year, $240 million contract. After a brief but productive stint with the Chicago Cubs in 2025, Tucker joins a Dodgers lineup that is already arguably the most feared in baseball. The Dodgers starting lineup can look like: 1. Ohtani, 2. Betts, 3. Freeman, 4. Smith, 5. Tucker. Having a lineup with such high OBP and power potential will be a nightmare for opposing pitchers.</p>
<section id="review-a-cub-in-transition" class="level2">
<h2 class="anchored" data-anchor-id="review-a-cub-in-transition">2025 Review: A Cub in Transition</h2>
<p>Following his trade from the Houston Astros in late 2024, Tucker adapted quickly to the Friendly Confines of Wrigley Field. While 2025 was a year of adjustment, his Statcast metrics remained elite, suggesting that his move to Los Angeles comes right as he is hitting his peak.</p>
<section id="statcast-analysis-2025-performance" class="level3">
<h3 class="anchored" data-anchor-id="statcast-analysis-2025-performance">Statcast Analysis: 2025 Performance</h3>
<p>The following analysis was performed on Tucker’s 2025 Statcast data to derive the metrics used in this article.</p>
<div class="cell" data-tbl-alt="Kyle Tucker 2025 Game Logs" data-execution_count="1">
<details class="code-fold">
<summary>Code</summary>
<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="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-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb1-3"><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-4">sns.set_theme(style<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;">"whitegrid"</span>, palette<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;">"deep"</span>)</span>
<span id="cb1-5">pd.set_option(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'display.max_columns'</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>)</span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Load the 2025 Statcast data</span></span>
<span id="cb1-8">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tucker-data.csv'</span>)</span>
<span id="cb1-9"></span>
<span id="cb1-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate core metrics</span></span>
<span id="cb1-11">ev_la_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.dropna(subset<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;">'EV (MPH)'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LA'</span>])</span>
<span id="cb1-12">avg_ev <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ev_la_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'EV (MPH)'</span>].mean()</span>
<span id="cb1-13">avg_la <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ev_la_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LA'</span>].mean()</span>
<span id="cb1-14">hard_hit_rate <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (ev_la_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'EV (MPH)'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span>).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(ev_la_df) <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="cb1-15"></span>
<span id="cb1-16"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Markdown, display</span>
<span id="cb1-17"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> tabulate <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> tabulate</span>
<span id="cb1-18"></span>
<span id="cb1-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Summary Metrics Table</span></span>
<span id="cb1-20">summary_data <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;">"Avg EV"</span>, <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>avg_ev<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> MPH"</span>],</span>
<span id="cb1-22">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Hard Hit Rate"</span>, <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>hard_hit_rate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>],</span>
<span id="cb1-23">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Avg Launch Angle"</span>, <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>avg_la<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" 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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Pitch Performance Analysis</span></span>
<span id="cb1-27">pitch_ev_summary <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ev_la_df.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Pitch Type'</span>)[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'EV (MPH)'</span>].mean().reset_index().sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'EV (MPH)'</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>).head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb1-28"></span>
<span id="cb1-29">display(Markdown(tabulate(summary_data, headers<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;">"Metric"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Value"</span>], tablefmt<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;">"github"</span>)))</span>
<span id="cb1-30">display(Markdown(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">**Top Pitch Performance (Avg EV):**"</span>))</span>
<span id="cb1-31">display(Markdown(tabulate(pitch_ev_summary, headers<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;">"Pitch Type"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Avg EV (MPH)"</span>], tablefmt<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;">"github"</span>, showindex<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></code></pre></div>
</details>
<div id="tbl-2025-ev" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-tbl-alt="Kyle Tucker 2025 Game Logs" data-execution_count="1">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-2025-ev-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Kyle Tucker 2025 Game Logs
</figcaption>
<div aria-describedby="tbl-2025-ev-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display cell-output-markdown">
<table class="do-not-create-environment cell caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th>Metric</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Avg EV</td>
<td>89.69 MPH</td>
</tr>
<tr class="even">
<td>Hard Hit Rate</td>
<td>39.95%</td>
</tr>
<tr class="odd">
<td>Avg Launch Angle</td>
<td>16.75</td>
</tr>
</tbody>
</table>
</div>
<div class="cell-output cell-output-display cell-output-markdown">
<p><strong>Top Pitch Performance (Avg EV):</strong></p>
</div>
<div class="cell-output cell-output-display cell-output-markdown">
<table class="do-not-create-environment cell caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th>Pitch Type</th>
<th>Avg EV (MPH)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Other</td>
<td>105.7</td>
</tr>
<tr class="even">
<td>Knuckle Curve</td>
<td>93.5833</td>
</tr>
<tr class="odd">
<td>4-Seam Fastball</td>
<td>93.4658</td>
</tr>
<tr class="even">
<td>Cutter</td>
<td>90.6436</td>
</tr>
<tr class="odd">
<td>Sinker</td>
<td>90.1813</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
</div>
<p>Analyzing the 2025 at-bat data reveals a hitter who remains fundamentally sound with high-end power potential.</p>
<ul>
<li><strong>Average Exit Velocity</strong>: 87.48 MPH</li>
<li><strong>Hard-Hit Rate (95+ MPH)</strong>: 32.71%</li>
<li><strong>Average Launch Angle</strong>: 10.99</li>
<li><strong>Home Runs</strong>: 5 (in this specific data slice)</li>
<li><strong>Plate Discipline</strong>: 18 Walks vs.&nbsp;30 Strikeouts across 157 plate appearances.</li>
</ul>
<section id="performance-by-pitch-type" class="level4">
<h4 class="anchored" data-anchor-id="performance-by-pitch-type">Performance by Pitch Type</h4>
<p>Tucker continues to be a terror against fastballs, which bodes well for his transition to the NL West’s high-velocity environments.</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Pitch Type</th>
<th>Frequency</th>
<th>Avg Exit Velocity (MPH)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>4-Seam Fastball</td>
<td>60</td>
<td>91.72</td>
</tr>
<tr class="even">
<td>Sinker</td>
<td>25</td>
<td>85.64</td>
</tr>
<tr class="odd">
<td>Slider</td>
<td>21</td>
<td>82.28</td>
</tr>
<tr class="even">
<td>Changeup</td>
<td>17</td>
<td>89.09</td>
</tr>
<tr class="odd">
<td>Cutter</td>
<td>9</td>
<td>91.27</td>
</tr>
</tbody>
</table>
<p>The 91.72 MPH average exit velocity against the four-seamer stands out as his primary weapon. Even against breaking stuff like the Slider and Sweeper, Tucker maintained competitive contact, though his highest damage was clearly reserved for the heater.</p>
</section>
</section>
<section id="visualizing-trends-rolling-average-ev" class="level3">
<h3 class="anchored" data-anchor-id="visualizing-trends-rolling-average-ev">Visualizing Trends: Rolling Average EV</h3>
<p>To better understand Tucker’s consistency, we can look at the rolling average of his exit velocity across the 2025 season.</p>
<div id="cell-fig-rolling-ev" class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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 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="cb2-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb2-3"></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Ensure data is sorted chronologically</span></span>
<span id="cb2-5">ev_la_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Game Date"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.to_datetime(ev_la_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Game Date"</span>])</span>
<span id="cb2-6">ev_la_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ev_la_df.sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Game Date"</span>)</span>
<span id="cb2-7"></span>
<span id="cb2-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate rolling average</span></span>
<span id="cb2-9">ev_la_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Rolling EV'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ev_la_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'EV (MPH)'</span>].rolling(window<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>).mean()</span>
<span id="cb2-10"></span>
<span id="cb2-11">plt.figure(figsize<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;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb2-12"></span>
<span id="cb2-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plotting raw data as points to highlight the density/gaps</span></span>
<span id="cb2-14">sns.scatterplot(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ev_la_df, 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;">'Game Date'</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;">'EV (MPH)'</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.2</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;">'gray'</span>, label<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;">'Individual BBE'</span>)</span>
<span id="cb2-15">sns.lineplot(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ev_la_df, 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;">'Game Date'</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;">'Rolling EV'</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;">'tab:blue'</span>, linewidth<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;">2.5</span>, label<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;">'15-BBE Rolling Avg'</span>)</span>
<span id="cb2-16"></span>
<span id="cb2-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The gap between August and October represents a period with no recorded plate appearances (likely an IL stint)</span></span>
<span id="cb2-18">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Kyle Tucker 2025 Rolling Exit Velocity (Season Timeline)'</span>)</span>
<span id="cb2-19">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Date'</span>)</span>
<span id="cb2-20">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Exit Velocity (MPH)'</span>)</span>
<span id="cb2-21">plt.xticks(rotation<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;">45</span>)</span>
<span id="cb2-22">plt.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, linestyle<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>, 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.6</span>)</span>
<span id="cb2-23">plt.legend()</span>
<span id="cb2-24">plt.tight_layout()</span>
<span id="cb2-25">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-rolling-ev" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Kyle Tucker 2025 Rolling Exit Velocity (Season Timeline)">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-rolling-ev-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/kyle-tucker-projection/index_files/figure-html/fig-rolling-ev-output-1.png" alt="Kyle Tucker 2025 Rolling Exit Velocity (Season Timeline)" width="560" height="368" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-rolling-ev-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Kyle Tucker 2025 Rolling Exit Velocity (Season Timeline)
</figcaption>
</figure>
</div>
</div>
</div>
</section>
<section id="forecasting-for-2026-arima-model" class="level3">
<h3 class="anchored" data-anchor-id="forecasting-for-2026-arima-model">Forecasting for 2026: ARIMA Model</h3>
<p>Using an ARIMA (AutoRegressive Integrated Moving Average) model, we can attempt to forecast the trend of Tucker’s exit velocity as he enters the 2026 season. Let’s first explain what an ARIMA model is. Time series analysis is a statistical method that uses historical data to make predictions about future values. ARIMA models are a type of time series model that can be used to forecast the trend of a time series.</p>
<p>An ARIMA model, denoted as <img src="https://latex.codecogs.com/png.latex?ARIMA(p,%20d,%20q)">, is a class of statistical models that captures temporal structures in time series data. Formally, for a stochastic process <img src="https://latex.codecogs.com/png.latex?%5C%7BX_t%5C%7D">, the model is defined by the equation:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cphi(L)(1%20-%20L)%5Ed%20X_t%20=%20%5Ctheta(L)%5Cepsilon_t"></p>
<p>Where:</p>
<ul>
<li><p><strong><img src="https://latex.codecogs.com/png.latex?L"></strong> is the lag (backshift) operator, defined such that <img src="https://latex.codecogs.com/png.latex?L%5Ek%20X_t%20=%20X_%7Bt-k%7D">.</p></li>
<li><p><strong><img src="https://latex.codecogs.com/png.latex?d"></strong> (Integrated) is the degree of differencing required to achieve stationarity. The term <img src="https://latex.codecogs.com/png.latex?(1%20-%20L)%5Ed"> represents the <img src="https://latex.codecogs.com/png.latex?d">-th order difference operator.</p></li>
<li><p><strong><img src="https://latex.codecogs.com/png.latex?%5Cphi(L)"></strong> (AutoRegressive) is a polynomial of order <img src="https://latex.codecogs.com/png.latex?p">: <img src="https://latex.codecogs.com/png.latex?%5Cphi(L)%20=%201%20-%20%5Csum_%7Bi=1%7D%5Ep%20%5Cphi_i%20L%5Ei">. This captures the linear dependence of <img src="https://latex.codecogs.com/png.latex?X_t"> on its own previous values.</p></li>
<li><p><strong><img src="https://latex.codecogs.com/png.latex?%5Ctheta(L)"></strong> (Moving Average) is a polynomial of order <img src="https://latex.codecogs.com/png.latex?q">: <img src="https://latex.codecogs.com/png.latex?%5Ctheta(L)%20=%201%20+%20%5Csum_%7Bj=1%7D%5Eq%20%5Ctheta_j%20L%5Ej">. This represents the relationship between the observation and the <img src="https://latex.codecogs.com/png.latex?q"> previous white noise error terms.</p></li>
<li><p><strong><img src="https://latex.codecogs.com/png.latex?%5Cepsilon_t"></strong> is a white noise process with mean zero and variance <img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2">.</p></li>
</ul>
<p>The model assumes that the <img src="https://latex.codecogs.com/png.latex?d">-th difference of the series follows a stationary ARMA process, allowing us to model non-stationary data that exhibits a stochastic trend. Individual parameters are typically estimated via Maximum Likelihood Estimation (MLE) or least squares.</p>
<p>So how do we find <img src="https://latex.codecogs.com/png.latex?p">, <img src="https://latex.codecogs.com/png.latex?d">, and <img src="https://latex.codecogs.com/png.latex?q">? Well, we can use the autocorrelation function (ACF) and partial autocorrelation function (PACF) to help us determine the values of <img src="https://latex.codecogs.com/png.latex?p"> and <img src="https://latex.codecogs.com/png.latex?q">. The ACF measures the correlation between the time series and its lagged values, while the PACF measures the correlation between the time series and its lagged values after removing the effects of the intermediate lags.</p>
<div id="cell-fig-pacf-acf" class="cell" data-execution_count="3">
<details class="code-fold">
<summary>Code</summary>
<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 class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.tsa.arima.model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> ARIMA</span>
<span id="cb3-2"><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="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.tsa.stattools <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> adfuller</span>
<span id="cb3-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.dates <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> mdates</span>
<span id="cb3-5"></span>
<span id="cb3-6">ev_series <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ev_la_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'EV (MPH)'</span>].values</span>
<span id="cb3-7"></span>
<span id="cb3-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Perform Augmented Dickey-Fuller test</span></span>
<span id="cb3-9">adf_result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> adfuller(ev_series)</span>
<span id="cb3-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'ADF Statistic: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>adf_result[<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="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb3-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'p-value: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>adf_result[<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="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb3-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Critical Values: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>adf_result[<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="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)</span>
<span id="cb3-13"></span>
<span id="cb3-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># plot the partial autocorrelation function</span></span>
<span id="cb3-15"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.graphics.tsaplots <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plot_pacf</span>
<span id="cb3-16">plot_pacf(ev_series)</span>
<span id="cb3-17">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>ADF Statistic: -19.88895111266658
p-value: 0.0
Critical Values: {'1%': -3.4454029241336483, '5%': -2.8681766097362087, '10%': -2.570305075326362}</code></pre>
</div>
<div class="cell-output cell-output-display">
<div id="fig-pacf-acf" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Kyle Tucker 2025 PACF">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-pacf-acf-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/kyle-tucker-projection/index_files/figure-html/fig-pacf-acf-output-2.png" alt="Kyle Tucker 2025 PACF" width="590" height="435" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-pacf-acf-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Kyle Tucker 2025 PACF
</figcaption>
</figure>
</div>
</div>
</div>
<p>The PACF shows a significant correlation at lag 1, indicating that the time series is non-stationary and requires differencing. The ACF shows a significant correlation at lag 1, indicating that the time series is non-stationary and requires differencing. We’ll use <img src="https://latex.codecogs.com/png.latex?p=1">. Note that we also ran the Augmented Dickey-Fuller test to confirm that the time series is non-stationary. The p-value is less than 0.05, indicating that the time series is non-stationary. Hence, <img src="https://latex.codecogs.com/png.latex?d=0">.</p>
<p>Below we show the ACF for the time series.</p>
<div id="cell-fig-acf" class="cell" data-execution_count="4">
<details class="code-fold">
<summary>Code</summary>
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># plot the autocorrelation function</span></span>
<span id="cb5-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.graphics.tsaplots <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plot_acf</span>
<span id="cb5-3">plot_acf(ev_series)</span>
<span id="cb5-4">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-acf" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Kyle Tucker 2025 ACF">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-acf-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/kyle-tucker-projection/index_files/figure-html/fig-acf-output-1.png" alt="Kyle Tucker 2025 ACF" width="590" height="435" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-acf-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: Kyle Tucker 2025 ACF
</figcaption>
</figure>
</div>
</div>
</div>
<p>Similar to the PACF, the ACF shows a significant correlation at lag 1, indicating that the time series is non-stationary and requires differencing. We’ll use <img src="https://latex.codecogs.com/png.latex?q=1">.</p>
<p>Finally, we’ll fit the ARIMA model and forecast the next 20 BBE.</p>
<div id="cell-fig-forecast" class="cell" data-execution_count="5">
<details class="code-fold">
<summary>Code</summary>
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit ARIMA model (p,d,q) - using (1,0,1) as a starting point</span></span>
<span id="cb6-2">model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ARIMA(ev_series, order<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 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;">1</span>))</span>
<span id="cb6-3">model_fit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.fit()</span>
<span id="cb6-4"></span>
<span id="cb6-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Forecast the next 20 bbe</span></span>
<span id="cb6-6">forecast_steps <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="cb6-7">forecast <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_fit.forecast(steps<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>forecast_steps)</span>
<span id="cb6-8">history_size <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(ev_series)</span>
<span id="cb6-9">forecast_obj <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_fit.get_forecast(steps<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>forecast_steps)</span>
<span id="cb6-10">forecast_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> forecast_obj.summary_frame()</span>
<span id="cb6-11"></span>
<span id="cb6-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 2. Extract values</span></span>
<span id="cb6-13">forecast_mean <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> forecast_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean'</span>]</span>
<span id="cb6-14">conf_int_lower <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> forecast_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean_ci_lower'</span>]</span>
<span id="cb6-15">conf_int_upper <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> forecast_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean_ci_upper'</span>]</span>
<span id="cb6-16"></span>
<span id="cb6-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 3. Plotting</span></span>
<span id="cb6-18">plt.figure(figsize<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;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb6-19"></span>
<span id="cb6-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot history</span></span>
<span id="cb6-21">sns.lineplot(x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>np.arange(history_size), y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ev_series, label<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;">'Observed EV (2025)'</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;">'tab:blue'</span>)</span>
<span id="cb6-22"></span>
<span id="cb6-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot forecast mean</span></span>
<span id="cb6-24">forecast_idx <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(history_size, history_size <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> forecast_steps)</span>
<span id="cb6-25">sns.lineplot(x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>forecast_idx, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>forecast_mean, 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;">'red'</span>, label<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;">'Forecasted EV (2026)'</span>, linestyle<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="cb6-26"></span>
<span id="cb6-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot accurate Confidence Intervals from the model</span></span>
<span id="cb6-28">plt.fill_between(forecast_idx, conf_int_lower, conf_int_upper, 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;">'pink'</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.3</span>, label<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;">'95% Confidence Inter val'</span>)</span>
<span id="cb6-29"></span>
<span id="cb6-30">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Kyle Tucker Exit Velocity Forecast (ARIMA)'</span>)</span>
<span id="cb6-31">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'At-Bat Number (Sequential)'</span>)</span>
<span id="cb6-32">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Exit Velocity (MPH)'</span>)</span>
<span id="cb6-33">plt.legend()</span>
<span id="cb6-34">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-forecast" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Kyle Tucker 2026 Exit Velocity Forecast">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-forecast-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/kyle-tucker-projection/index_files/figure-html/fig-forecast-output-1.png" alt="Kyle Tucker 2026 Exit Velocity Forecast" width="671" height="381" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-forecast-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4: Kyle Tucker 2026 Exit Velocity Forecast
</figcaption>
</figure>
</div>
</div>
</div>
<p>The ARIMA model indicates Tucker’s exit velocity is not dependent on the previous exit velocity. This is not unexpected given the small sample size of 2025. In other words, forecasting Tucker’s exit velocity is only as good as taking the mean of the exit velocity in 2025.</p>
<p>The model’s coefficients are shown below.</p>
<div class="cell" data-tbl-alt="A table showing the forecast coefficients for the ARIMA model" data-execution_count="6">
<details class="code-fold">
<summary>Code</summary>
<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 class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Markdown</span>
<span id="cb7-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> tabulate <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> tabulate</span>
<span id="cb7-3"><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="cb7-4"></span>
<span id="cb7-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Extract the coefficients table from the ARIMA model summary</span></span>
<span id="cb7-6">summary_table <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_fit.summary().tables[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb7-7">summary_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(summary_table.data[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:], columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>summary_table.data[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb7-8"></span>
<span id="cb7-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Display the summary table in Markdown format</span></span>
<span id="cb7-10">Markdown(tabulate(summary_df, headers<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;">'keys'</span>, tablefmt<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;">'pipe'</span>))</span></code></pre></div>
</details>
<div id="tbl-forecast-coefficients" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-tbl-alt="A table showing the forecast coefficients for the ARIMA model" data-execution_count="6">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-forecast-coefficients-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;2: A table showing the forecast coefficients for the ARIMA model
</figcaption>
<div aria-describedby="tbl-forecast-coefficients-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display cell-output-markdown" data-execution_count="12">
<table class="do-not-create-environment cell caption-top table table-sm table-striped small">
<colgroup>
<col style="width: 5%">
<col style="width: 11%">
<col style="width: 14%">
<col style="width: 15%">
<col style="width: 12%">
<col style="width: 12%">
<col style="width: 14%">
<col style="width: 14%">
</colgroup>
<thead>
<tr class="header">
<th style="text-align: right;"></th>
<th style="text-align: left;"></th>
<th style="text-align: right;">coef</th>
<th style="text-align: right;">std err</th>
<th style="text-align: right;">z</th>
<th style="text-align: right;">P&gt;</th>
<th style="text-align: right;">z</th>
<th style="text-align: right;"></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">0</td>
<td style="text-align: left;">const</td>
<td style="text-align: right;">89.6849</td>
<td style="text-align: right;">0.8</td>
<td style="text-align: right;">112.174</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">88.118</td>
<td style="text-align: right;">91.252</td>
</tr>
<tr class="even">
<td style="text-align: right;">1</td>
<td style="text-align: left;">ar.L1</td>
<td style="text-align: right;">-0.0897</td>
<td style="text-align: right;">1.149</td>
<td style="text-align: right;">-0.078</td>
<td style="text-align: right;">0.938</td>
<td style="text-align: right;">-2.342</td>
<td style="text-align: right;">2.163</td>
</tr>
<tr class="odd">
<td style="text-align: right;">2</td>
<td style="text-align: left;">ma.L1</td>
<td style="text-align: right;">0.1414</td>
<td style="text-align: right;">1.14</td>
<td style="text-align: right;">0.124</td>
<td style="text-align: right;">0.901</td>
<td style="text-align: right;">-2.094</td>
<td style="text-align: right;">2.376</td>
</tr>
<tr class="even">
<td style="text-align: right;">3</td>
<td style="text-align: left;">sigma2</td>
<td style="text-align: right;">164.441</td>
<td style="text-align: right;">10.693</td>
<td style="text-align: right;">15.379</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">143.483</td>
<td style="text-align: right;">185.399</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
</div>
<p>The p-values for ar.L1 and ma.L1 are both greater than 0.05, indicating that the coefficients are not significantly different from zero.</p>
</section>
</section>
<section id="projection-the-dodgers-effect" class="level2">
<h2 class="anchored" data-anchor-id="projection-the-dodgers-effect">2026 Projection: The Dodgers Effect</h2>
<p><strong>Key Projections for 2026:</strong></p>
<ol type="1">
<li><strong>Increased Run Production</strong>: With a career-high OBP environment surrounding him, Tucker’s RBI potential in the heart of the Dodgers order is astronomical.</li>
<li><strong>Power Surge</strong>: Dodger Stadium is a hitter’s par, boasting a 127 HR factor in 2025. Tucker should expect a season-high in home runs.</li>
<li><strong>Elite Efficiency</strong>: Expect his hard-hit rate to climb back toward his career highs as he settles into a stable, championship-caliber environment.</li>
</ol>
<p>Kyle Tucker isn’t just a high-priced addition; he is the final piece of a puzzle that the Dodgers hope leads to another World Series title. Even though the ARIMA model does not show a clear trajectory it serves as a reminder that our intuition can deceive us. At first glace, Tucker’s 2025 EV might have shown a downward trend, but the data tells a different story.</p>
<p>It will be bitter sweet not seeing Clayton Kershaw take the mound in 2026. Tucker nor Kershaw will be teammates. However, I want to share a video of Kershaw pitching to Tucker when he was on the Astros.</p>
<iframe src="https://streamable.com/m/kyle-tucker-lines-out-sharply-to-center-fielder-chris-taylor?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>


<!-- -->

</section>
</section>

 ]]></description>
  <category>Dodgers</category>
  <guid>https://runningonnumbers.com/posts/kyle-tucker-projection/</guid>
  <pubDate>Sun, 25 Jan 2026 06:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/kyle-tucker-projection/main.png" medium="image" type="image/png" height="109" width="144"/>
</item>
<item>
  <title>Query, Visualize, and Analyze with Mode</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/analysis-with-mode/</link>
  <description><![CDATA[ 





<section id="preface" class="level2">
<h2 class="anchored" data-anchor-id="preface">Preface</h2>
<p>The best way to learn something is to teach it. In this post, I will introduce you to Mode, a data analytics platform that simplifies the process of analyzing and visualizing data. Whether you’re a data scientist, analyst, or business user, Mode provides a collaborative environment to work with data efficiently.</p>
<p>Typically, a user connects Mode to a database like Google BigQuery, Amazon Redshift, or Snowflake. Once connected, users can write SQL queries to extract and manipulate data. Mode’s SQL editor provides features like syntax highlighting, auto-completion, and query history to enhance the coding experience.</p>
<p>For this tutorial, I will use Mode’s default sample database, which contains flight data.</p>
<div class="callout callout-style-default callout-tip 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">
Tip
</div>
</div>
<div class="callout-body-container callout-body">
<p>You don’t need to connect a database to follow along with this tutorial. Simply create a free Mode account, and you can access the sample database directly by calling the <code>tutorial</code> schema.</p>
</div>
</div>
</section>
<section id="querying-data" class="level2">
<h2 class="anchored" data-anchor-id="querying-data">1. Querying Data</h2>
<p>First things first, let’s write a simple SQL query to retrieve data from the sample database. SQL (Structured Query Language) is the standard language for managing and manipulating relational databases. For this example, let’s look at <code>tutorial.flights</code>, which contains information about flights, including departure and arrival times, delays, and distances.</p>
<p>Suppose we want to find the average arrival delay for flights grouped by flight distance categories (short haul, medium haul, long haul). We can define these categories as follows:</p>
<pre class="{sql}"><code>SELECT 
  CASE
    WHEN distance &lt; 500 THEN 'Short Haul'
    WHEN distance &gt;= 500 AND distance &lt;= 1500 THEN 'Medium Haul'
    WHEN distance &gt; 500 THEN 'Long Haul'
  END AS flight_type,
  COUNT(*) AS total_flights,
  AVG(arrival_delay) AS average_delay
FROM 
  tutorial.flights
GROUP BY 
  flight_type
ORDER BY 
  average_delay</code></pre>
<p>In this query, we use a <code>CASE</code> statement to categorize flights based on their distance. We then count the total number of flights and calculate the average arrival delay for each category. The results are grouped by <code>flight_type</code> and ordered by <code>average_delay</code>. By convention, SQL keywords are written in uppercase to distinguish them from column names and other identifiers.</p>
<p>As a result, we get a table showing the average arrival delay for short haul, medium haul, and long haul flights.</p>
<table class="caption-top table">
<caption>Demonstration of pipe table syntax</caption>
<thead>
<tr class="header">
<th>flight_type</th>
<th style="text-align: right;">total_flights</th>
<th style="text-align: right;">average_delay</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Long Haul</td>
<td style="text-align: right;">74281</td>
<td style="text-align: right;">-0.6173</td>
</tr>
<tr class="even">
<td>Medium Haul</td>
<td style="text-align: right;">297380</td>
<td style="text-align: right;">3.8683</td>
</tr>
<tr class="odd">
<td>Short Haul</td>
<td style="text-align: right;">222181</td>
<td style="text-align: right;">3.9832</td>
</tr>
</tbody>
</table>
</section>
<section id="visualizing-data" class="level2">
<h2 class="anchored" data-anchor-id="visualizing-data">2. Visualizing Data</h2>
<p>Now that we have our data, let’s visualize it using Mode’s built-in charting capabilities. Visualizations help us understand data patterns and trends more intuitively.</p>
<p>Beneath the SQL editor, Mode provides a charting interface where we can create various types of visualizations, such as bar charts, line charts, scatter plots, and more. For our flight delay data, let’s create a bar chart to visualize the average arrival delay for each flight type.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/analysis-with-mode/bar_chart.png" class="img-fluid figure-img"></p>
<figcaption>Bar Chart of Average Arrival Delay by Flight Type</figcaption>
</figure>
</div>
</section>
<section id="advanced-analysis-with-python" class="level2">
<h2 class="anchored" data-anchor-id="advanced-analysis-with-python">3. Advanced Analysis with Python</h2>
<p>Mode supports python notebooks, allowing us to perform more advanced analyses and visualizations. I’m a fan of this integration because it allows us to leverage the power of Python libraries like Pandas, NumPy, Matplotlib, and Seaborn for data analysis and visualization.</p>
<p>By default, SQL query results are available as a Pandas DataFrame in the Python notebook. Specifically, the variable, <code>datasets</code> contains a list of sql query results as DataFrames. Thus, to index the first query result, you would use <code>datasets[0]</code>.</p>
<p>Let’s query the flight data again, this time retrieving arrival and departure delays for individual flights. We can then use Python to analyze the relationship between these two variables.</p>
<pre class="{sql}"><code>SELECT arrival_delay, departure_delay 
FROM tutorial.flights
LIMIT 1000</code></pre>
<p>Now we can move to the Python notebook. Import familiar libraries.</p>
<div id="d8a11068" class="cell" data-execution_count="1">
<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 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="cb3-2"><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="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb3-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="cb3-5"><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> train_test_split</span>
<span id="cb3-6"><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="cb3-7"><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> StandardScaler</span>
<span id="cb3-8"><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></code></pre></div>
</div>
<p>Recall that the SQL query results are stored in <code>datasets</code>. This variable stores all query results as a list of DataFrames. Since we only have two queries, we want to access the first index, <code>datasets[1]</code>.</p>
<div id="8f3990b4" class="cell" data-execution_count="2">
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># df = datasets[1]</span></span>
<span id="cb4-2">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"flight_arrivals_departure_delays.csv"</span>)</span>
<span id="cb4-3">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.dropna(subset<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;">"arrival_delay"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"departure_delay"</span>])</span>
<span id="cb4-4">X <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;">"departure_delay"</span>]]</span>
<span id="cb4-5">y <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;">"arrival_delay"</span>]</span>
<span id="cb4-6">X_train, X_val, y_train, y_val <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X, y, 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.2</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="cb4-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(X_train.shape, X_val.shape, y_train.shape, y_val.shape)</span>
<span id="cb4-8"></span>
<span id="cb4-9">pip <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([</span>
<span id="cb4-10">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'scaler'</span>, StandardScaler()),</span>
<span id="cb4-11">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'regressor'</span>, LinearRegression())</span>
<span id="cb4-12">])</span>
<span id="cb4-13">pip.fit(X_train, y_train)</span>
<span id="cb4-14">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pip.predict(X_val)</span>
<span id="cb4-15">score <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pip.score(X_val, y_val)</span>
<span id="cb4-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Model R^2 Score: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>score<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb4-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Model Coefficients: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pip<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>named_steps[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'regressor'</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>coef_<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="cb4-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Model Intercept: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pip<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>named_steps[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'regressor'</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>intercept_<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></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>(799, 1) (200, 1) (799,) (200,)
Model R^2 Score: 0.76
Model Coefficients: [17.15344637]
Model Intercept: -8.27784730913642</code></pre>
</div>
</div>
<p>A <img src="https://latex.codecogs.com/png.latex?R%5E2"> score of 0.76 indicates how well the model explains the variability of the data. The model coefficient is 17.2, meaning for every minute of departure delay, the arrival delay increases by 17.2 minutes on average.</p>
<p>Finally, let’s visualize the relationship between departure delay and arrival delay, along with the regression line from our linear model.</p>
<div id="248f811f" class="cell" data-execution_count="3">
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># super impose lm line on scatter plot using seaborn</span></span>
<span id="cb6-2">sns.lmplot(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;">"departure_delay"</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;">"arrival_delay"</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df, line_kws<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;">'color'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'red'</span>})</span>
<span id="cb6-3">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Arrival Delay vs Departure Delay with Regression Line"</span>)</span>
<span id="cb6-4">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Departure Delay (minutes)"</span>)</span>
<span id="cb6-5">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Arrival Delay (minutes)"</span>)</span>
<span id="cb6-6">plt.show()</span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/analysis-with-mode/index_files/figure-html/cell-4-output-1.png" width="489" height="490" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>No surprise here - there is a positive correlation between departure delay and arrival delay. The regression line shows that as departure delays increase, arrival delays tend to increase as well.</p>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>In this post, we explored the QVA (Query, Visualize, Analyze) workflow using Mode. We started by querying flight data using SQL, visualized the results with a bar chart, and then performed advanced analysis using Python to build a linear regression model. Mode’s integration of SQL and Python makes it a powerful tool for data analysis and visualization.</p>
<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>Past articles: - <a href="https://runningonnumbers.com/posts/principal-component-analysis-python-baseball/">Principal Component Analysis</a> - <a href="https://runningonnumbers.com/posts/support-vector-machine/">Support Vector Machine</a> - <a href="https://runningonnumbers.com/posts/k-means/">K-Means Clustering</a></p>
<p>Github: - <a href="https://github.com/oliverc1623/Running-On-Numbers-Public">Running on Numbers</a></p>
</div>
</div>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->

</section>

 ]]></description>
  <category>Mode</category>
  <category>SQL</category>
  <category>python</category>
  <category>data science</category>
  <category>data visualization</category>
  <guid>https://runningonnumbers.com/posts/analysis-with-mode/</guid>
  <pubDate>Tue, 30 Dec 2025 06:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/analysis-with-mode/flights_main.png" medium="image" type="image/png" height="79" width="144"/>
</item>
<item>
  <title>Reflections on Running and Research</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/reflections-on-running-and-research/</link>
  <description><![CDATA[ 





<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/reflections-on-running-and-research/neurips-group-photo.jpg" class="img-fluid figure-img"></p>
<figcaption>UCSC-UCI Social at NeurIPS 2025</figcaption>
</figure>
</div>
<p>The first week of December was a whirlwind. I kicked it off by attending NeurIPS. As someone doing reinforcement learning (RL) research, I was blown away by the amount of attention the field garnered. From applications in autonomous driving to continual learning, RL has re-emerged as the critical tool to navigate complex tasks where supervised learning falls short. I was particularly impressed by papers that showcased new and creative RL environments, demonstrating both single and multi-agent capabilities. I also had the pleasure of meeting new colleagues and discussing research. There is no better way to incubate paper ideas than brainstorming over a meal. It is safe to say that RL is back!</p>
<p>While at NeurIPS, I received an email that a company would not be moving forward with my internship application. However, I remained uplifted by the numerous tech giants seeking AI researchers. Chatting with recruiters and researchers gave me an opportunity to share my work and motivated me to continue the pursuit of the right role.</p>
<p>My week was far from over. On Friday afternoon, I flew to Sacramento to run my first marathon at the California International Marathon (CIM). Reuniting with former teammates from Pomona-Pitzer and UC Santa Cruz brought a convivial energy to the weekend. Given that this was my debut and I had just come from a conference, I went in with zero expectations. Sunday at 7:00 AM, I toed the line, reminding myself to stay patient and let it rip with 10k to go. At 9:22 AM, I crossed the finish line in 2:22:37. Up until that point, the farthest I had ever run was 20 miles.</p>
<p>Throughout high school and college, I balanced academics and athletics. However, attending NeurIPS and running CIM felt like the apex of my dual optimization. I couldn’t have pulled this off without years of doing homework on buses and racing alongside teammates - rinsing and repeating every weekend.</p>
<p>Running has taught me that a stopwatch waits for no one. Time is finite. You can only make trade-offs with time, never “make” time. As we enter 2026, I’m reflecting on how I allocate my time. Admittedly, there are race days where I am an athlete-student and school days where I am a student-athlete. I’m proud of the runner I’ve become, but I know the researcher in me has another gear. NeurIPS lit a fire in me to close out my PhD the way I closed out my marathon: unexpected and triumphant. Here’s to 2026!</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/reflections-on-running-and-research/finish-photo.jpg" class="img-fluid figure-img"></p>
<figcaption>Finish photo after crossing the line at the California International Marathon</figcaption>
</figure>
</div>


<!-- -->


 ]]></description>
  <category>running</category>
  <category>research</category>
  <guid>https://runningonnumbers.com/posts/reflections-on-running-and-research/</guid>
  <pubDate>Sat, 13 Dec 2025 06:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/reflections-on-running-and-research/cim-flag.png" medium="image" type="image/png" height="102" width="144"/>
</item>
<item>
  <title>Weekly Mileage Planner</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/weekly-mileage-planner/</link>
  <description><![CDATA[ 





<iframe src="mileage-planner.html" title="Weekly Mileage Planner" width="100%" height="1050px" style="border: 1px solid #ccc; border-radius: 8px; max-width: 800px; margin: 2em auto; display: block;">
</iframe>
<section id="how-does-this-work" class="level2">
<h2 class="anchored" data-anchor-id="how-does-this-work">How does this work?</h2>
<p>The mileage planner uses the <strong>Largest Remainder Method</strong> to efficiently manage and prioritize daily mileage allocations. It starts by calculating the base mileage for each day, then applies adjustments based on the selected day types (Easy, Workout) and distribution settings. To ensure integer mileages, it rounds down the calculated values and distributes the remaining “remainder” miles to the days with the largest fractional parts, ensuring the total weekly mileage is exactly met while maintaining the intended distribution.</p>
<p>However, we have to account for the long run day, which is set to a fixed percentage of the total weekly mileage. Thus, long run day mileage is calculated first, and the remaining mileage is distributed among the other days using the Largest Remainder Method. Let’s do an example:</p>
<ol type="1">
<li><strong>Set Weekly Mileage</strong>: Suppose the total weekly mileage is set to 32 miles and we have no workouts.</li>
<li><strong>Calculate Long Run Mileage</strong>: If the long run is set to 25% of the total, then the long run mileage is 0.25 * 32 = 8 miles.</li>
<li><strong>Distribute Remaining Mileage</strong>: The remaining mileage is 32 - 8 = 24 miles, which needs to be distributed over the other 5 days.</li>
<li><strong>Base Mileage Calculation</strong>: The base mileage for each of the 5 days is 24 / 5 = 4.8 miles.</li>
<li><strong>Apply Day Type Adjustments</strong>: If we have 4.8 miles per day we must take the floor of that (4 miles) and allocate the remaining 0.8 miles to the days with the largest fractional parts.</li>
<li><strong>Final Allocation</strong>: The final allocation would be:
<ul>
<li>Long Run: 8 miles</li>
<li>Day 1: 5 miles (4 + 1 from remainder)</li>
<li>Day 2: 5 miles (4 + 1 from remainder)</li>
<li>Day 3: 5 miles (4 + 1 from remainder)</li>
<li>Day 4: 5 miles (4 + 1 from remainder)</li>
<li>Day 5: 4 miles (4 + 0 from remainder)</li>
</ul></li>
<li><strong>The Final Schedule</strong>:
<ul>
<li>Sunday Long Run: 8 miles</li>
<li>Saturday: 0 miles</li>
<li>Friday: 4 miles</li>
<li>Thursday: 5 miles</li>
<li>Wednesday: 5 miles</li>
<li>Tuesday: 5 miles</li>
<li>Monday: 5 miles</li>
</ul></li>
</ol>
<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>Past articles: - <a href="https://runningonnumbers.com/posts/principal-component-analysis-python-baseball/">Principal Component Analysis</a> - <a href="https://runningonnumbers.com/posts/support-vector-machine/">Support Vector Machine</a> - <a href="https://runningonnumbers.com/posts/k-means/">K-Means Clustering</a></p>
<p>Github: - <a href="https://github.com/oliverc1623/Running-On-Numbers-Public">Running on Numbers</a></p>
</div>
</div>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->

</section>

 ]]></description>
  <category>running</category>
  <category>greedy algorithms</category>
  <guid>https://runningonnumbers.com/posts/weekly-mileage-planner/</guid>
  <pubDate>Thu, 11 Dec 2025 06:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/weekly-mileage-planner/planner-thumbnail.png" medium="image" type="image/png" height="79" width="144"/>
</item>
<item>
  <title>Barrels Are All You Need</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/barrels-are-all-you-need/</link>
  <description><![CDATA[ 





<p><img src="https://runningonnumbers.com/posts/barrels-are-all-you-need/peter-brand.png" class="img-fluid"></p>
<section id="in-order-to-buy-runs-you-need-to-buy-barrels." class="level2">
<h2 class="anchored" data-anchor-id="in-order-to-buy-runs-you-need-to-buy-barrels.">In order to buy runs, you need to buy barrels.</h2>
<blockquote class="blockquote">
<p>People who run ball clubs, they think in terms of buying players. Your goal shouldn’t be to buy players, your goal should be to buy wins. And in order to buy wins, you need to buy runs. - Peter Brand (Jonah Hill portraying Paul DePodesta), Moneyball (2011)</p>
</blockquote>
<p>In order to buy runs, you need to buy barrels. Barrels are a highly sought after batted ball event in baseball, contributing significantly to a team’s offensive success. A barrel is defined as a batted ball with an exit velocity of at least 98 mph and a launch angle between 26 and 30 degrees, or with higher exit velocities for slightly different launch angles. Barrels are known for their high likelihood of resulting in extra-base hits, including home runs.</p>
<div id="cell-fig-runs-vs-barrels" class="cell" data-execution_count="1">
<details class="code-fold">
<summary>Code</summary>
<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="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-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb1-3"><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-4"><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-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> warnings</span>
<span id="cb1-6"></span>
<span id="cb1-7"><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> SimpleImputer</span>
<span id="cb1-8"><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> train_test_split</span>
<span id="cb1-9"><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> HistGradientBoostingClassifier</span>
<span id="cb1-10"><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> confusion_matrix, log_loss, ConfusionMatrixDisplay, roc_curve, roc_auc_score, RocCurveDisplay</span>
<span id="cb1-11"><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> KFold, cross_val_score</span>
<span id="cb1-12"><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-13"><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> RobustScaler</span>
<span id="cb1-14"></span>
<span id="cb1-15">warnings.filterwarnings(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ignore'</span>)</span>
<span id="cb1-16">sns.set_theme(style<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;">"whitegrid"</span>, palette<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;">"deep"</span>)</span>
<span id="cb1-17">pd.set_option(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'display.max_columns'</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>)</span>
<span id="cb1-18"></span>
<span id="cb1-19">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"team-games-2023-2025-with-runs.csv"</span>)</span>
<span id="cb1-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># convert "Oakland Athletics" to "Athletics"</span></span>
<span id="cb1-21">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"team_name"</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;">"team_name"</span>].<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;">"Oakland Athletics"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Athletics"</span>)</span>
<span id="cb1-22">sns.barplot(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df, 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;">"barrels_total"</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;">"runs_scored"</span>)</span>
<span id="cb1-23">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Total Barrels in Game"</span>)</span>
<span id="cb1-24">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Runs Scored in Game"</span>)</span>
<span id="cb1-25">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-runs-vs-barrels" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Runs Scored vs Total Barrels in Game (2023-2025)">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-runs-vs-barrels-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/barrels-are-all-you-need/index_files/figure-html/fig-runs-vs-barrels-output-1.png" alt="Runs Scored vs Total Barrels in Game (2023-2025)" width="589" height="435" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-runs-vs-barrels-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Runs Scored vs Total Barrels in Game (2023-2025)
</figcaption>
</figure>
</div>
</div>
</div>
<p>To visualize their impact, let’s look at the relationship between the total number of barrels in a game and the runs scored in that game from the 2023 to 2025 MLB seasons. Observe Figure&nbsp;1. In games where teams hit more barrels, they tend to score more runs. At 0 barrels teams average around 2 runs, while at 2 barrels, the average runs scored almost doubles to around 4 runs. This trend continues, with teams scoring even more runs as the number of barrels increases. This visualization underscores the importance of barrels in contributing to a team’s offensive output and ultimately winning games.</p>
<p>In addition to runs scored, barrels indicate overall offensive performance. In Figure&nbsp;2, we visualize the expected weighted on-base average (xwOBA) based on contact quality: barrels, solid contact, and poor contact. Barrels (in blue) have significantly higher xwOBA values compared to solid contact (in green) and poor contact (in orange). There’s probably some overlap between the three groups because xwOBA includes walks and strikouts, which are not directly related to batted ball quality. However, the distinction is still clear: barrels lead to much better offensive outcomes than other types of contact.</p>
<div id="cell-fig-xwoba-by-contact-quality" class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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">df_barrels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrels-2023-2025.csv"</span>)</span>
<span id="cb2-2">df_barrels[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel"</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="cb2-3">df_barrels[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"contact_quality"</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;">"barrel"</span></span>
<span id="cb2-4"></span>
<span id="cb2-5">df_weak <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"poor-contact-2023-2025.csv"</span>)</span>
<span id="cb2-6">df_weak[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel"</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="cb2-7">df_weak[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"contact_quality"</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;">"poor"</span></span>
<span id="cb2-8"></span>
<span id="cb2-9">df_solid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"solid-contact-2023-2025.csv"</span>)</span>
<span id="cb2-10">df_solid[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel"</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="cb2-11">df_solid[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"contact_quality"</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;">"solid"</span></span>
<span id="cb2-12"></span>
<span id="cb2-13">df_bbe <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.concat([df_barrels, df_weak, df_solid], ignore_index<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="cb2-14">sns.kdeplot(df_bbe, 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;">"estimated_woba_using_speedangle"</span>, hue<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;">"contact_quality"</span>, fill<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>, common_norm<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>, 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.5</span>)</span>
<span id="cb2-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># rename legend</span></span>
<span id="cb2-16">plt.legend(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;">"Contact Quality"</span>, labels<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;">"Solid Contact"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Poor Contact"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Barrel"</span>])</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-xwoba-by-contact-quality" class="quarto-float quarto-figure quarto-figure-center anchored" alt="xwOBA by Contact Quality (2023-2025)">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-xwoba-by-contact-quality-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/barrels-are-all-you-need/index_files/figure-html/fig-xwoba-by-contact-quality-output-1.png" alt="xwOBA by Contact Quality (2023-2025)" width="593" height="435" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-xwoba-by-contact-quality-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: xwOBA by Contact Quality (2023-2025)
</figcaption>
</figure>
</div>
</div>
</div>
<p>So this begs the question: how can teams increase their barrel counts? One approach is to analyze the factors that contribute to successful barrel outcomes. By leveraging machine learning techniques, teams can identify key features that influence barrel production and optimize their strategies accordingly.</p>
</section>
<section id="how-to-find-barrels" class="level2">
<h2 class="anchored" data-anchor-id="how-to-find-barrels">How to Find Barrels</h2>
<p><a href="https://www.mlb.com/glossary/statcast/barrel">Statcast</a> defines a barrel as a batted ball with an exit velocity of at least 98 mph and a launch angle between 26 and 30 degrees, or with higher exit velocities for slightly different launch angles. If we want to find barrels, we first need to understand what differentiates them from other types of batted balls. Let’s visualize batted balls based on their launch speed and launch angle, categorized by contact quality: barrels, solid contact, and poor contact. This will help us see how barrels stand out in terms of these two key metrics.</p>
<div id="cell-fig-batted-balls" class="cell" data-execution_count="3">
<details class="code-fold">
<summary>Code</summary>
<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">sns.scatterplot(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_bbe, 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;">"launch_speed"</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;">"launch_angle"</span>, hue<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;">"contact_quality"</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.5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-batted-balls" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Batted Balls by Contact Quality (2023-2025)">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-batted-balls-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/barrels-are-all-you-need/index_files/figure-html/fig-batted-balls-output-1.png" alt="Batted Balls by Contact Quality (2023-2025)" width="597" height="435" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-batted-balls-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: Batted Balls by Contact Quality (2023-2025)
</figcaption>
</figure>
</div>
</div>
</div>
<p>Figure&nbsp;3 shows a scatter plot of batted balls categorized by contact quality. Barrels (in blue) are clustered in a specific region characterized by high launch speeds and optimal launch angles, while solid contact and poor contact batted balls are more dispersed across the plot. This visualization highlights the distinct characteristics of barrels compared to other types of contact.</p>
<p>To determine barrels, we can use machine learning classification techniques. By training a model on features such as bat speed, attack angle, swing length, and other relevant metrics, we can predict whether a batted ball will be a barrel or not. While outcome statistics like wOBA are useful, they are not directly used in the classification model since they are results of the batted ball rather than predictors.</p>
<div id="10a25b6c" class="cell" data-execution_count="4">
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># batting features only</span></span>
<span id="cb4-2">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;">"bat_speed"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"attack_angle"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"swing_length"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"attack_direction"</span>, </span>
<span id="cb4-3">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"swing_path_tilt"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"intercept_ball_minus_batter_pos_x_inches"</span>,</span>
<span id="cb4-4">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"intercept_ball_minus_batter_pos_y_inches"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"stand"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"age_bat"</span>,</span>
<span id="cb4-5">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n_thruorder_pitcher"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"inning"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"balls"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"strikes"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pitch_number"</span>]</span>
<span id="cb4-6"></span>
<span id="cb4-7">dataset <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_bbe[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;">"barrel"</span>]].copy()</span>
<span id="cb4-8">dataset[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.factorize(dataset[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel"</span>])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb4-9">dataset[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"stand"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.factorize(dataset[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"stand"</span>])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb4-10">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> dataset[features]</span>
<span id="cb4-11">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> dataset[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel"</span>]</span>
<span id="cb4-12">X_train, X_val, y_train, y_val <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X, y, 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.2</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="cb4-13"></span>
<span id="cb4-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># modeling</span></span>
<span id="cb4-15">pip <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([</span>
<span id="cb4-16">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"imputer"</span>, SimpleImputer()),</span>
<span id="cb4-17">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"scaler"</span>, RobustScaler()),</span>
<span id="cb4-18">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"classifier"</span>, HistGradientBoostingClassifier(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>, class_weight<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;">"balanced"</span>))</span>
<span id="cb4-19">])</span>
<span id="cb4-20">pip.fit(X_train, y_train)</span>
<span id="cb4-21">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pip.predict(X_val)</span>
<span id="cb4-22">score <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pip.score(X_val, y_val)</span>
<span id="cb4-23">y_proba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pip.predict_proba(X_val)</span>
<span id="cb4-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Validation score (Accuracy): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>score<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb4-25"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Log Loss: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>log_loss(y_val, y_proba)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb4-26"></span>
<span id="cb4-27">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="cb4-28">cv_scores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cross_val_score(pip, X_train, 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><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'balanced_accuracy'</span>, n_jobs<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="cb4-29"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Cross-validation scores: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>cv_scores<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="cb4-30"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Mean CV accuracy: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>cv_scores<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<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></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Validation score (Accuracy): 0.6564
Log Loss: 0.6006
Cross-validation scores: [0.66854507 0.67285075 0.67464693 0.66929524 0.6735115 ]
Mean CV accuracy: 0.6717698965985912</code></pre>
</div>
</div>
<p>Just on batting features alone, we can achieve a validation accuracy of 66%. The average cross-validation accuracy is around 67%. While not perfect, this model provides a better-than-random ability to classify barrels based on batting metrics.</p>
<p>Now it takes two to tango. We should also consider the pitcher’s influence on barrel outcomes. By incorporating pitching features such as pitch type, velocity, spin rate, and movement, we can enhance our model’s ability to predict barrels. Combining both batting and pitching features provides a more comprehensive view of the factors that contribute to barrel production.</p>
<div id="380fc0c0" class="cell" data-execution_count="5">
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># batting and pitching features only</span></span>
<span id="cb6-2">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;">"batter"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pitcher"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bat_speed"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"attack_angle"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"swing_length"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"attack_direction"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"swing_path_tilt"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"intercept_ball_minus_batter_pos_x_inches"</span>,</span>
<span id="cb6-3">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"intercept_ball_minus_batter_pos_y_inches"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"stand"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"age_bat"</span>,</span>
<span id="cb6-4">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n_thruorder_pitcher"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"inning"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"balls"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"strikes"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pitch_number"</span>, </span>
<span id="cb6-5">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"release_speed"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"release_pos_x"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"release_pos_z"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p_throws"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"zone"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vx0"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vy0"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vz0"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ax"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ay"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"az"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"release_pos_y"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pitch_type"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pitch_number"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"age_pit"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"api_break_z_with_gravity"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"api_break_x_arm"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"api_break_x_batter_in"</span>,</span>
<span id="cb6-6">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"arm_angle"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"zone"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"effective_speed"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"release_spin_rate"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"release_extension"</span>]</span>
<span id="cb6-7"></span>
<span id="cb6-8">dataset <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_bbe[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;">"barrel"</span>]].copy()</span>
<span id="cb6-9">dataset[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.factorize(dataset[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel"</span>])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb6-10"></span>
<span id="cb6-11">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;">"stand"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p_throws"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pitch_type"</span>]</span>
<span id="cb6-12">dataset_one_hot <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.get_dummies(dataset, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>categorical_features, drop_first<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="cb6-13"></span>
<span id="cb6-14">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> dataset_one_hot[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel"</span>]</span>
<span id="cb6-15">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> dataset_one_hot.drop(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel"</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="cb6-16">X_train, X_val, y_train, y_val <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X, y, 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.2</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="cb6-17"></span>
<span id="cb6-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># %% modeling</span></span>
<span id="cb6-19">pip <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([</span>
<span id="cb6-20">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"imputer"</span>, SimpleImputer()),</span>
<span id="cb6-21">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"scaler"</span>, RobustScaler()),</span>
<span id="cb6-22">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"classifier"</span>, HistGradientBoostingClassifier(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>, class_weight<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;">"balanced"</span>))</span>
<span id="cb6-23">])</span>
<span id="cb6-24">pip.fit(X_train, y_train)</span>
<span id="cb6-25">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pip.predict(X_val)</span>
<span id="cb6-26">score <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pip.score(X_val, y_val)</span>
<span id="cb6-27">y_proba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pip.predict_proba(X_val)</span>
<span id="cb6-28"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Validation score (Accuracy): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>score<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb6-29"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Log Loss: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>log_loss(y_val, y_proba)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb6-30"></span>
<span id="cb6-31">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="cb6-32">cv_scores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cross_val_score(pip, X_train, 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><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'balanced_accuracy'</span>, n_jobs<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="cb6-33"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Cross-validation scores: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>cv_scores<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="cb6-34"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Mean CV accuracy: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>cv_scores<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<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></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Validation score (Accuracy): 0.6737
Log Loss: 0.5821
Cross-validation scores: [0.68336082 0.68811475 0.68566822 0.68072519 0.68566854]
Mean CV accuracy: 0.6847075037611322</code></pre>
</div>
</div>
<p>With both batting and pitching features, the validation accuracy improves to 67% and the average cross-validation accuracy increases to around 68%. This is effectively a 1% improvement over batting features alone. There is some added value but not a huge leap. What would be interesting is if we could use the entire bat trajectory data to further improve classification, but that is a topic for another day.</p>
<section id="model-evaluation" class="level3">
<h3 class="anchored" data-anchor-id="model-evaluation">Model Evaluation</h3>
<p>I would be remiss if I did not include some model evaluation metrics. First, let’s look at the confusion matrix to see how well our model is classifying barrels versus non-barrels.</p>
<div id="cell-fig-confusion-matrix" class="cell" data-execution_count="6">
<details class="code-fold">
<summary>Code</summary>
<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">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pip.predict(X_val)</span>
<span id="cb8-2">cm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> confusion_matrix(y_val, y_pred)</span>
<span id="cb8-3"></span>
<span id="cb8-4">cm_display <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ConfusionMatrixDisplay(cm).plot()</span>
<span id="cb8-5">plt.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-confusion-matrix" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Confusion Matrix for Barrel Classification">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-confusion-matrix-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/barrels-are-all-you-need/index_files/figure-html/fig-confusion-matrix-output-1.png" alt="Confusion Matrix for Barrel Classification" width="519" height="435" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-confusion-matrix-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4: Confusion Matrix for Barrel Classification
</figcaption>
</figure>
</div>
</div>
</div>
<p>The majority of predictions are correct. There are a lot of false negatives. This indicates that the model is struggling to identify barrels when they do occur. Although there’s a great deal of data imbalance (many more non-barrels than barrels). In such cases, accuracy alone can be misleading. Therefore, let’s also look at the ROC curve to evaluate the model’s performance across different classification thresholds.</p>
<div id="cell-fig-roc" class="cell" data-execution_count="7">
<details class="code-fold">
<summary>Code</summary>
<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">y_score <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pip.decision_function(X_val)</span>
<span id="cb9-2">fpr, tpr, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> roc_curve(y_val, y_score, pos_label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>pip.classes_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb9-3">roc_display <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> RocCurveDisplay(fpr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>fpr, tpr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>tpr).plot()</span>
<span id="cb9-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># area under the curve</span></span>
<span id="cb9-5">auc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> roc_auc_score(y_val, y_score)</span>
<span id="cb9-6">plt.title(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"ROC Curve (AUC = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>auc<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" 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>
</details>
<div class="cell-output cell-output-display">
<div id="fig-roc" class="quarto-float quarto-figure quarto-figure-center anchored" alt="ROC Curve for Barrel Classification">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-roc-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/barrels-are-all-you-need/index_files/figure-html/fig-roc-output-1.png" alt="ROC Curve for Barrel Classification" width="448" height="455" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-roc-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;5: ROC Curve for Barrel Classification
</figcaption>
</figure>
</div>
</div>
</div>
<p>When observing the ROC curve, we see the model performing better than random guessing. The area under the curve (AUC) is a useful metric for summarizing the model’s performance across all classification thresholds. An AUC of 0.75 indicates that the model has a good ability to distinguish between barrels and non-barrels across various thresholds.</p>
</section>
</section>
<section id="who-should-find-barrels" class="level2">
<h2 class="anchored" data-anchor-id="who-should-find-barrels">Who Should Find Barrels?</h2>
<p>Finally, let’s look at which teams are generating the most barrels on average per game. This can provide insights into which teams are effectively leveraging barrels to enhance their offensive performance.</p>
<div id="cell-fig-avg-barrels-by-team" class="cell" data-execution_count="8">
<details class="code-fold">
<summary>Code</summary>
<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"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Markdown</span>
<span id="cb10-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> tabulate <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> tabulate</span>
<span id="cb10-3"></span>
<span id="cb10-4">tbl <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"team_name"</span>)[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrels_total"</span>].mean().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="cb10-5">tbl_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(tbl).reset_index()</span>
<span id="cb10-6">tbl_df.index <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-7">tbl_df.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;">"Team"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Avg Barrels per Game"</span>]</span>
<span id="cb10-8">Markdown(tabulate(tbl_df.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), headers<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;">"keys"</span>))</span></code></pre></div>
</details>
<div id="fig-avg-barrels-by-team" class="cell-output cell-output-display cell-output-markdown quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="8">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-avg-barrels-by-team-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<table class="caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th></th>
<th style="text-align: left;">Team</th>
<th style="text-align: right;">Avg Barrels per Game</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1</td>
<td style="text-align: left;">Atlanta Braves</td>
<td style="text-align: right;">2.5783</td>
</tr>
<tr class="even">
<td>2</td>
<td style="text-align: left;">New York Yankees</td>
<td style="text-align: right;">2.5678</td>
</tr>
<tr class="odd">
<td>3</td>
<td style="text-align: left;">Los Angeles Dodgers</td>
<td style="text-align: right;">2.3291</td>
</tr>
<tr class="even">
<td>4</td>
<td style="text-align: left;">New York Mets</td>
<td style="text-align: right;">2.2746</td>
</tr>
<tr class="odd">
<td>5</td>
<td style="text-align: left;">Seattle Mariners</td>
<td style="text-align: right;">2.2129</td>
</tr>
<tr class="even">
<td>6</td>
<td style="text-align: left;">Minnesota Twins</td>
<td style="text-align: right;">2.1535</td>
</tr>
<tr class="odd">
<td>7</td>
<td style="text-align: left;">Chicago Cubs</td>
<td style="text-align: right;">2.125</td>
</tr>
<tr class="even">
<td>8</td>
<td style="text-align: left;">Philadelphia Phillies</td>
<td style="text-align: right;">2.1232</td>
</tr>
<tr class="odd">
<td>9</td>
<td style="text-align: left;">Baltimore Orioles</td>
<td style="text-align: right;">2.1185</td>
</tr>
<tr class="even">
<td>10</td>
<td style="text-align: left;">Boston Red Sox</td>
<td style="text-align: right;">2.1</td>
</tr>
<tr class="odd">
<td>11</td>
<td style="text-align: left;">Texas Rangers</td>
<td style="text-align: right;">2.0541</td>
</tr>
<tr class="even">
<td>12</td>
<td style="text-align: left;">Los Angeles Angels</td>
<td style="text-align: right;">2.0333</td>
</tr>
<tr class="odd">
<td>13</td>
<td style="text-align: left;">Houston Astros</td>
<td style="text-align: right;">2.0273</td>
</tr>
<tr class="even">
<td>14</td>
<td style="text-align: left;">Toronto Blue Jays</td>
<td style="text-align: right;">2.0083</td>
</tr>
<tr class="odd">
<td>15</td>
<td style="text-align: left;">Detroit Tigers</td>
<td style="text-align: right;">1.9896</td>
</tr>
<tr class="even">
<td>16</td>
<td style="text-align: left;">Kansas City Royals</td>
<td style="text-align: right;">1.9771</td>
</tr>
<tr class="odd">
<td>17</td>
<td style="text-align: left;">San Francisco Giants</td>
<td style="text-align: right;">1.9353</td>
</tr>
<tr class="even">
<td>18</td>
<td style="text-align: left;">San Diego Padres</td>
<td style="text-align: right;">1.931</td>
</tr>
<tr class="odd">
<td>19</td>
<td style="text-align: left;">St.&nbsp;Louis Cardinals</td>
<td style="text-align: right;">1.929</td>
</tr>
<tr class="even">
<td>20</td>
<td style="text-align: left;">Arizona Diamondbacks</td>
<td style="text-align: right;">1.925</td>
</tr>
<tr class="odd">
<td>21</td>
<td style="text-align: left;">Athletics</td>
<td style="text-align: right;">1.9208</td>
</tr>
<tr class="even">
<td>22</td>
<td style="text-align: left;">Tampa Bay Rays</td>
<td style="text-align: right;">1.8812</td>
</tr>
<tr class="odd">
<td>23</td>
<td style="text-align: left;">Miami Marlins</td>
<td style="text-align: right;">1.8625</td>
</tr>
<tr class="even">
<td>24</td>
<td style="text-align: left;">Colorado Rockies</td>
<td style="text-align: right;">1.8264</td>
</tr>
<tr class="odd">
<td>25</td>
<td style="text-align: left;">Pittsburgh Pirates</td>
<td style="text-align: right;">1.815</td>
</tr>
<tr class="even">
<td>26</td>
<td style="text-align: left;">Milwaukee Brewers</td>
<td style="text-align: right;">1.7635</td>
</tr>
<tr class="odd">
<td>27</td>
<td style="text-align: left;">Chicago White Sox</td>
<td style="text-align: right;">1.7484</td>
</tr>
<tr class="even">
<td>28</td>
<td style="text-align: left;">Cincinnati Reds</td>
<td style="text-align: right;">1.6674</td>
</tr>
<tr class="odd">
<td>29</td>
<td style="text-align: left;">Washington Nationals</td>
<td style="text-align: right;">1.6286</td>
</tr>
<tr class="even">
<td>30</td>
<td style="text-align: left;">Cleveland Guardians</td>
<td style="text-align: right;">1.4635</td>
</tr>
</tbody>
</table>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-avg-barrels-by-team-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;6: Average Barrels per Game by Team (2023-2025)
</figcaption>
</figure>
</div>
</div>
<p>When looking at Figure&nbsp;6, it is apparent why <a href="https://baseballsavant.mlb.com/leaderboard/statcast">BaseballSavant</a> lists barrels per plate appearance. Calculating average barrels per game is too granular where difference between teams is minimal. However, barrels per game still shows some trends among teams. For example, the Braves, Yankees, and Dodgers being in the top 3 checks out. Additionally, the Guardians, Nationals, and Reds in the bottome 3 also makes sense.</p>
<p>The Guardians are an interesting case study. Despite boasting the lowest barrel rate in 2025, they still found themselves in the playoffs. So how did they do it? Being good at pitching always help. Exceptional fielding also plays a role. But one metric the Guardians excel at is maximize their Pull AIR %. In 2025, 21.6% of their batted balls were pulled and either a fly ball, line drive, or pop up. This was the second highest in MLB, behind the Chicago Cubs.</p>
<p>This strikes me as interesting because a low barrel rate with a high Pull AIR % seems counterintuitive. However, it just goes to show that there are multiple ways to win in baseball. The Guardians found a way that worked for them. They are not sluggers but opportunists.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/barrels-are-all-you-need/guardians-run-value.png" class="img-fluid figure-img"></p>
<figcaption>Guardians Leverage-based Run Value</figcaption>
</figure>
</div>
<p>Take a look at the Guardians’ leverage-based run value by batted ball type in 2025. All batters produced negative run values. But observe the “+/- Due To Leverage” column. For all but 2 players, the leverage adjustment was positive on swings. This means that the Guardians were able to get the most out of their batted balls in high-leverage situations, even if those batted balls were not barrels. By focusing on situational hitting and maximizing the impact of their contact, the Guardians were able to overcome their low barrel rate and still find success.</p>
<section id="conclusion" class="level3">
<h3 class="anchored" data-anchor-id="conclusion">Conclusion</h3>
<p>Barrels are the gospel of Statcast — a neat, data-driven way to explain why some swings change games and others don’t. Whether you roll your eyes at analytics or worship at its altar, barrels have become the sport’s shorthand for power. They correlate neatly with runs, wins, and the illusion of control. Teams build models around them, tuning every motion in the cage toward the perfect batted-ball outcome.</p>
<p>But Cleveland seems to have missed that memo—or maybe they just ignored it. The Guardians aren’t chasing barrels; they’re chasing moments. They don’t overwhelm you with exit velocity. They outlast you with timing. While other teams obsess over maximizing run differentials, Cleveland’s figured out that you only need enough runs to win this game. Score when it counts, defend when it matters, and trust that efficiency can be its own kind of power.</p>
<p>In an era defined by data, the Guardians are proof that there’s still room for something harder to measure: the knack for being good at the right time.</p>
<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>Past articles: - <a href="https://runningonnumbers.com/posts/principal-component-analysis-python-baseball/">Principal Component Analysis</a> - <a href="https://runningonnumbers.com/posts/support-vector-machine/">Support Vector Machine</a> - <a href="https://runningonnumbers.com/posts/k-means/">K-Means Clustering</a></p>
<p>Github: - <a href="https://github.com/oliverc1623/Running-On-Numbers-Public">Running on Numbers</a></p>
</div>
</div>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->

</section>
</section>

 ]]></description>
  <category>Guardians</category>
  <category>gradient boosting</category>
  <category>classification</category>
  <guid>https://runningonnumbers.com/posts/barrels-are-all-you-need/</guid>
  <pubDate>Thu, 23 Oct 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/barrels-are-all-you-need/peter-brand.png" medium="image" type="image/png" height="108" width="144"/>
</item>
<item>
  <title>Visualizing MLB Realignment with Graph Theory</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/mlb-realignment-graph-theory/</link>
  <description><![CDATA[ 





<iframe src="https://streamable.com/m/shohei-ohtani-k-s-mike-trout-twice-with-nasty-pitches?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>In this article, we chime in on the current discourse surrounding MLB expansion and realignment. Recently, <a href="https://www.forbes.com/sites/maurybrown/2025/08/18/as-manfred-touts-geographic-realignment-with-mlb-expansion-heres-how-it-could-look/">Rob Manfred mentioned</a> the possibility of adding two more teams to the league. Across social media, fans have expressed their opinions on the matter. I want to explore how graph theory can help visualize the current MLB schedule and how it might change with expansion and realignment.</p>
<p>In college, I majored in math and computer science. While my emphasis was on statistics and machine learning, I always had a keen interest in number theory, graph theory, and combinatorics; in fact, my senior thesis was on fast matrix multiplication. One course I missed out on during my undergrad was a graph theory course that was offered at Harvey Mudd College. Given that this blog serves as a platform for me to explore my interests, I thought it would be fun to apply graph theory concepts to MLB scheduling.</p>
<section id="graph-theory-101" class="level3">
<h3 class="anchored" data-anchor-id="graph-theory-101">Graph Theory 101</h3>
<p>Let’s introduce some graph theory formality. We’ll be taking note from <a href="https://en.wikipedia.org/wiki/Graph_theory">Wikipedia’s</a> definition. Let a graph be defined as <img src="https://latex.codecogs.com/png.latex?G=(V,E)"> where <img src="https://latex.codecogs.com/png.latex?V"> is a set of vertices and <img src="https://latex.codecogs.com/png.latex?E"> is a set of edges. Vertices can also be referred to as nodes, and edges can be thought of as connections or links between these nodes. <img src="https://latex.codecogs.com/png.latex?E%20%5Csubseteq%20%5C%7B%20(u,v)%20%7C%20u,v%20%5Cin%20V%20%5Ctext%7B%20and%20%7D%20u%20%5Cneq%20v%20%5C%7D."> This is a simple, undirected graph without loops or multiple edges.</p>
<p>A directed graph is a graph in which edges have orientations, indicating a one-way relationship between vertices. Edges can also have weights, representing the strength or capacity of the connection. A directed graph has the same annotation as an undirected graph, but the edges are ordered pairs. Hence, <img src="https://latex.codecogs.com/png.latex?E%20%5Csubseteq%20%5C%7B%20(u,v)%20%7C%20u,v%20%5Cin%20V%5E2%20%5Ctext%7B%20and%20%7D%20u%20%5Cneq%20v%20%5C%7D."> V^2 is represents the cartisian product (<img src="https://latex.codecogs.com/png.latex?V%20%5Ctimes%20V">). This is the set of all possible ordered pairs of vertices. An edge in this graph, for example, could be <img src="https://latex.codecogs.com/png.latex?(u,v)"> but not <img src="https://latex.codecogs.com/png.latex?(v,u)">. To further illustrate this point, consider four verticies (<img src="https://latex.codecogs.com/png.latex?V%20=%20%5C%7BA,%20B,%20B%5C%7D">). The set of edges in the undirected graph would be <img src="https://latex.codecogs.com/png.latex?%5C%7B(A,B),%20(A,C),%20(A,D),%20(B,C),%20(B,D),%20(C,D)%5C%7D">, while the set of edges in the directed graph would be <img src="https://latex.codecogs.com/png.latex?%5C%7B(A,B),%20(B,A),%20(A,C),%20%5C%5C%20(C,A),%20(A,D),%20(D,A),%20%5C%5C%20(B,C),%20(C,B),%20(B,D),%20%5C%5C%20(D,B),%20(C,D),%20(D,C)%5C%7D."></p>
<section id="breadth-first-search-bfs" class="level4">
<h4 class="anchored" data-anchor-id="breadth-first-search-bfs">Breadth First Search (BFS)</h4>
<p>BFS is an algorithm for traversing or searching tree or graph data structures. It starts at the tree root (or some arbitrary node of a graph, sometimes referred to as a ‘search key’) and explores the neighbor nodes at the present depth prior to moving on to the nodes at the next depth level. There are ample resources online to learn about <a href="https://en.wikipedia.org/wiki/Breadth-first_search">BFS</a>. I want to highlight that BFS uses a Queue data structure to keep track of the nodes to be explored next. There’s a quick pseudo code implementation:</p>
<div id="d98ec96b" class="cell" data-execution_count="1">
<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="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> collections <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> deque</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> bfs(graph, start):</span>
<span id="cb1-4">    visited <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>()</span>
<span id="cb1-5">    queue <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> deque([start])</span>
<span id="cb1-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> queue:</span>
<span id="cb1-7">        vertex <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> queue.popleft()</span>
<span id="cb1-8">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> vertex <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> visited:</span>
<span id="cb1-9">            <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visiting:"</span>, vertex)</span>
<span id="cb1-10">            visited.add(vertex)</span>
<span id="cb1-11">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> neighbor <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> graph[vertex]:</span>
<span id="cb1-12">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> neighbor <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> visited:</span>
<span id="cb1-13">                    queue.append(neighbor)</span></code></pre></div>
</div>
<p>The runtime complexity of BFS is O(V + E), where V is the number of vertices and E is the number of edges in the graph.</p>
</section>
<section id="depth-first-search-dfs" class="level4">
<h4 class="anchored" data-anchor-id="depth-first-search-dfs">Depth First Search (DFS)</h4>
<p>The thing I really like about DFS is that we get a different search pattern by using a stack (or recursion) instead of a queue. Starting at the root node, we explore as far as possible along each branch before backtracking. The running time of DFS is also O(V + E), but it can be more memory efficient than BFS in certain cases. Recursion should be used with caution, though, as it can lead to stack overflow for very deep graphs.</p>
<div id="744217b5" class="cell" data-execution_count="2">
<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 class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> dfs(graph, start, visited<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="cb2-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> visited <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">is</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>:</span>
<span id="cb2-3">        visited <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>()</span>
<span id="cb2-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> start <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> visited:</span>
<span id="cb2-5">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Visiting:"</span>, start)</span>
<span id="cb2-6">        visited.add(start)</span>
<span id="cb2-7">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> neighbor <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> graph[start]:</span>
<span id="cb2-8">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> neighbor <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> visited:</span>
<span id="cb2-9">                dfs(graph, neighbor, visited)</span>
<span id="cb2-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> visited</span></code></pre></div>
</div>
</section>
</section>
</section>
<section id="mlb-schedule-represented-as-a-graph" class="level2">
<h2 class="anchored" data-anchor-id="mlb-schedule-represented-as-a-graph">MLB Schedule Represented as a Graph</h2>
<p>The MLB schedule can be represented as a graph where each team is a node and each game played between two teams is an edge connecting those nodes. This representation allows us to analyze the schedule using graph algorithms.</p>
<p>Based on <a href="https://en.wikipedia.org/wiki/Major_League_Baseball_schedule#2025%E2%80%932026">Wikipedia</a>, the 2025 MLB schedule consists of 162 games per team, with the following breakdown: - 13 games against each of the 4 divisional opponents (52 games) - 6 or 7 games against each of the 10 other league opponents (62 games) - 6 games against one “geographic” interleague opponent (6 games) - 3 games against the remaining 14 interleague opponents (42 games) Series range from 2 to 4 games, with 3-game series being the most common.</p>
<p>The visualization below shows the graph representation of the MLB schedule. I used <code>NetworkX</code> to create the graph and Matplotlib to visualize it. The nodes are aligned such that they form a circle. They are longitudinally arranged based on their geographical locations. There really is not much to take away from this visualization other than the fact that it shows the complex web of matchups between teams. Consider this an artistic expression.</p>
<div id="cell-fig:mlb-graph" class="cell" data-execution_count="3">
<details class="code-fold">
<summary>Code</summary>
<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 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="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> collections <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Counter, defaultdict</span>
<span id="cb3-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> networkx <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> nx</span>
<span id="cb3-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="cb3-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.graph_objects <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> go</span>
<span id="cb3-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.express <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> px</span>
<span id="cb3-7"><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="cb3-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> itertools</span>
<span id="cb3-9"></span>
<span id="cb3-10">team_name_map <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ANA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LAA'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ARI'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ARI'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ATL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ATL'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BAL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BAL'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BOS'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BOS'</span>,</span>
<span id="cb3-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CHA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CWS'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CHN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CHC'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CIN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CIN'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CLE'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CLE'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'COL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'COL'</span>,</span>
<span id="cb3-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'DET'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'DET'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'HOU'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'HOU'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'KCA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'KC'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LAN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LAD'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIA'</span>,</span>
<span id="cb3-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIL'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIN'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'NYA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'NYY'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'NYN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'NYM'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ATH'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ATH'</span>,</span>
<span id="cb3-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PHI'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PHI'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PIT'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PIT'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SDN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SD'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SEA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SEA'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SFN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SF'</span>,</span>
<span id="cb3-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SLN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'STL'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TBA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TB'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TEX'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TEX'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TOR'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TOR'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'WAS'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'WSH'</span></span>
<span id="cb3-17">}</span>
<span id="cb3-18"></span>
<span id="cb3-19">team_logos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-20">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ARI'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/Arizona_Diamondbacks_logo_teal.svg/330px-Arizona_Diamondbacks_logo_teal.svg.png'</span>,</span>
<span id="cb3-21">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ATL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/f/f2/Atlanta_Braves.svg'</span>,</span>
<span id="cb3-22">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BAL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/e/e9/Baltimore_Orioles_Script.svg'</span>,</span>
<span id="cb3-23">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BOS'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/6/6d/RedSoxPrimary_HangingSocks.svg'</span>,</span>
<span id="cb3-24">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CHC'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/8/80/Chicago_Cubs_logo.svg'</span>,</span>
<span id="cb3-25">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CWS'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/c/c1/Chicago_White_Sox.svg'</span>,</span>
<span id="cb3-26">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CIN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/0/01/Cincinnati_Reds_Logo.svg'</span>,</span>
<span id="cb3-27">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CLE'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/a/a9/Guardians_winged_</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%22G</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">%22.svg'</span>,</span>
<span id="cb3-28">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'COL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/c/c0/Colorado_Rockies_full_logo.svg'</span>,</span>
<span id="cb3-29">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'DET'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/e/e3/Detroit_Tigers_logo.svg'</span>,</span>
<span id="cb3-30">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'HOU'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/6/6b/Houston-Astros-Logo.svg'</span>,</span>
<span id="cb3-31">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'KC'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/7/78/Kansas_City_Royals_Primary_Logo.svg'</span>,</span>
<span id="cb3-32">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LAA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/8/8b/Los_Angeles_Angels_of_Anaheim.svg'</span>,</span>
<span id="cb3-33">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LAD'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/0/0e/Los_Angeles_Dodgers_Logo.svg'</span>,</span>
<span id="cb3-34">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/f/fd/Marlins_team_logo.svg'</span>,</span>
<span id="cb3-35">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/b/b8/Milwaukee_Brewers_logo.svg'</span>,</span>
<span id="cb3-36">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Minnesota_Twins_New_Logo.svg/250px-Minnesota_Twins_New_Logo.svg.png'</span>,</span>
<span id="cb3-37">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'NYM'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/thumb/7/7b/New_York_Mets.svg/250px-New_York_Mets.svg.png'</span>,</span>
<span id="cb3-38">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'NYY'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/f/fe/New_York_Yankees_Primary_Logo.svg'</span>,</span>
<span id="cb3-39">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ATH'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Athletics_logo.svg/330px-Athletics_logo.svg.png'</span>,</span>
<span id="cb3-40">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PHI'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/f/f0/Philadelphia_Phillies_</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%282019%</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">29_logo.svg'</span>,</span>
<span id="cb3-41">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PIT'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/8/81/Pittsburgh_Pirates_logo_2014.svg'</span>,</span>
<span id="cb3-42">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SD'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e2/SD_Logo_Brown.svg/250px-SD_Logo_Brown.svg.png'</span>,</span>
<span id="cb3-43">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SF'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/5/58/San_Francisco_Giants_Logo.svg'</span>,</span>
<span id="cb3-44">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SEA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/6/6d/Seattle_Mariners_logo_</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%28lo</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">w_res%29.svg'</span>,</span>
<span id="cb3-45">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'STL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/9/9d/St._Louis_Cardinals_logo.svg'</span>,</span>
<span id="cb3-46">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TB'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/5/55/Tampa_Bay_Rays_Logo.svg'</span>,</span>
<span id="cb3-47">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TEX'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/c/c7/Texas_Rangers_logo.svg'</span>,</span>
<span id="cb3-48">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TOR'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/en/c/cc/Toronto_Blue_Jay_Primary_Logo.svg'</span>,</span>
<span id="cb3-49">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'WSH'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/a/a3/Washington_Nationals_logo.svg'</span>,</span>
<span id="cb3-50">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'POR'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/a/a6/Major_League_Baseball_logo.svg'</span>,</span>
<span id="cb3-51">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'NSH'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://upload.wikimedia.org/wikipedia/commons/a/a6/Major_League_Baseball_logo.svg'</span>,</span>
<span id="cb3-52">}</span>
<span id="cb3-53"></span>
<span id="cb3-54"></span>
<span id="cb3-55"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Load the schedule data</span></span>
<span id="cb3-56">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2025schedule.csv"</span>)</span>
<span id="cb3-57">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Visitor'</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;">'Visitor'</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">map</span>(team_name_map)</span>
<span id="cb3-58">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Home'</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;">'Home'</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">map</span>(team_name_map)</span>
<span id="cb3-59">df.dropna(subset<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;">'Visitor'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Home'</span>], inplace<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="cb3-60">games_from_df <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;">'Visitor'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Home'</span>]].values.tolist()</span>
<span id="cb3-61">teams <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(pd.concat([df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Visitor'</span>], df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Home'</span>]]).unique())</span>
<span id="cb3-62"></span>
<span id="cb3-63"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Make a graph where teams are nodes and games are edges</span></span>
<span id="cb3-64">G <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nx.Graph()</span>
<span id="cb3-65"></span>
<span id="cb3-66"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use the canonical team names from team_name_map values</span></span>
<span id="cb3-67">team_longitudes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-68">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"BOS"</span>: <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;">71.0589</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NYY"</span>: <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;">73.92</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NYM"</span>: <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;">73.84</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PHI"</span>: <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;">75.16</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"BAL"</span>: <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;">76.61</span>,</span>
<span id="cb3-69">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"WSH"</span>: <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;">77.03</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PIT"</span>: <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;">79.99</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TOR"</span>: <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;">79.38</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TB"</span>: <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;">82.65</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MIA"</span>: <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;">80.19</span>,</span>
<span id="cb3-70">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ATL"</span>: <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;">84.38</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CLE"</span>: <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;">81.69</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CIN"</span>: <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;">84.51</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"DET"</span>: <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;">83.04</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CWS"</span>: <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;">87.62</span>,</span>
<span id="cb3-71">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CHC"</span>: <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;">87.62</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"STL"</span>: <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;">90.19</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MIL"</span>: <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;">87.90</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MIN"</span>: <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;">93.26</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"KC"</span>: <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;">94.48</span>,</span>
<span id="cb3-72">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HOU"</span>: <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;">95.36</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TEX"</span>: <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;">96.79</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COL"</span>: <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;">104.99</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ARI"</span>: <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;">112.07</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"LAD"</span>: <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;">118.24</span>,</span>
<span id="cb3-73">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"LAA"</span>: <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;">117.88</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SD"</span>: <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;">117.16</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SF"</span>: <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;">122.38</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ATH"</span>: <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;">122.27</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SEA"</span>: <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;">122.33</span></span>
<span id="cb3-74">}</span>
<span id="cb3-75"></span>
<span id="cb3-76"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Sort teams by longitude (East to West)</span></span>
<span id="cb3-77">sorted_teams <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(teams, key<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> team: team_longitudes[team])</span>
<span id="cb3-78"></span>
<span id="cb3-79"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create a graph</span></span>
<span id="cb3-80">G <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nx.Graph()</span>
<span id="cb3-81"></span>
<span id="cb3-82"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Assign circular positions based on the sorted geographical order</span></span>
<span id="cb3-83">team_positions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {}</span>
<span id="cb3-84">num_teams <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(sorted_teams)</span>
<span id="cb3-85">angle_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;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.pi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> num_teams</span>
<span id="cb3-86"></span>
<span id="cb3-87"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, team <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(sorted_teams):</span>
<span id="cb3-88">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate angle and position</span></span>
<span id="cb3-89">    angle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> angle_step</span>
<span id="cb3-90">    x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cos(angle)</span>
<span id="cb3-91">    y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sin(angle)</span>
<span id="cb3-92">    team_positions[team] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (x, y)</span>
<span id="cb3-93">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add node with its calculated position</span></span>
<span id="cb3-94">    G.add_node(team, pos<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(x, y))</span>
<span id="cb3-95"></span>
<span id="cb3-96"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add edges</span></span>
<span id="cb3-97">game_counts <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Counter(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">tuple</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(game)) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> game <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> games_from_df)</span>
<span id="cb3-98"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (team1, team2), count <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> game_counts.items():</span>
<span id="cb3-99">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> team1 <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.nodes <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> team2 <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.nodes:</span>
<span id="cb3-100">        G.add_edge(team1, team2, weight<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>count)</span>
<span id="cb3-101"></span>
<span id="cb3-102"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Draw the graph</span></span>
<span id="cb3-103"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Visualization ---</span></span>
<span id="cb3-104">plt.figure(figsize<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;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>))</span>
<span id="cb3-105">ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.gca()</span>
<span id="cb3-106">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MLB Team Matchups (Geographically Ordered Circle)"</span>, fontsize<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;">16</span>)</span>
<span id="cb3-107"></span>
<span id="cb3-108"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Extract positions for drawing</span></span>
<span id="cb3-109">pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nx.get_node_attributes(G, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pos'</span>)</span>
<span id="cb3-110"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pos = nx.spring_layout(G, weight='weight', iterations=50, seed=47)</span></span>
<span id="cb3-111"></span>
<span id="cb3-112"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Draw the graph</span></span>
<span id="cb3-113">nx.draw_networkx_nodes(G, pos, node_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;">'skyblue'</span>, node_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;">750</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>)</span>
<span id="cb3-114">nx.draw_networkx_edges(G, pos, edge_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;">'gray'</span>, width<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.0</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.6</span>)</span>
<span id="cb3-115">nx.draw_networkx_labels(G, pos, font_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>, font_weight<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;">'bold'</span>)</span>
<span id="cb3-116"></span>
<span id="cb3-117"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Remove axes for a cleaner look</span></span>
<span id="cb3-118">ax.margins(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)</span>
<span id="cb3-119">plt.axis(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"off"</span>)</span>
<span id="cb3-120">plt.tight_layout()</span>
<span id="cb3-121">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="figmlb-graph" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/mlb-realignment-graph-theory/index_files/figure-html/figmlb-graph-output-1.png" alt="Graph Network of MLB Teams and Their Matchups in the 2025 Season, Arranged in a Circle." width="758" height="759" class="figure-img"></p>
<figcaption>Graph Network of MLB Teams and Their Matchups in the 2025 Season, Arranged in a Circle.</figcaption>
</figure>
</div>
</div>
</div>
<section id="interactive-graph" class="level3">
<h3 class="anchored" data-anchor-id="interactive-graph">Interactive Graph</h3>
<p>Let’s create an interactive version of the graph using Plotly. Instead of manually arranging each node, we can use a force-directed layout to position the nodes based on their connections. <code>NetworkX</code> uses a class of algorithms called Force-Directed graph drawing. They mainly serve to place nodes in a visually appealing way by simulating physical forces. The <code>spring_layout</code> algorithm is one such method. The algorithm works by treating nodes as repelling charged particles and edges as springs connecting them. Algorithmically, it minimizes the energy of the system until an equilibrium is reached; so we would have to specify the number of iterations <code>k</code>, as well as the spring constant <code>k</code> which determines the strength of the springs.</p>
<p>Observe the network structure and how teams are interconnected. This edges illustrate the number of games played between each pair of teams. As expected, we see that inter-division matchups are more frequent than inter-league ones. The main takeway is how MLB place an emphasis on inter-league regional matchups. Teams like the <a href="https://www.baseball-reference.com/teams/LAD/2025.shtml">LA Dodgers</a> and <a href="https://www.baseball-reference.com/teams/LAA/2025.shtml">LA Angels</a> squared up six times this season. Another example inludes the <a href="https://www.baseball-reference.com/teams/CHC/2025.shtml">Chicago Cubs</a> and <a href="https://www.baseball-reference.com/teams/CHW/2025.shtml">Chicago White Sox</a>.</p>
<div id="figmlb-graph-interactive" class="cell" data-execution_count="4">
<details class="code-fold">
<summary>Code</summary>
<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">pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nx.spring_layout(G, weight<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;">'weight'</span>, iterations<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;">10000</span>, seed<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;">47</span>)</span>
<span id="cb4-2"></span>
<span id="cb4-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Set the calculated positions as a node attribute</span></span>
<span id="cb4-4">nx.set_node_attributes(G, pos, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pos'</span>)</span>
<span id="cb4-5"></span>
<span id="cb4-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Visualization with Plotly ---</span></span>
<span id="cb4-7">fig_data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-8"></span>
<span id="cb4-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Create Edge Traces by Color with Hover Text ---</span></span>
<span id="cb4-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Group edges by weight (number of games) to color them</span></span>
<span id="cb4-11">edges_by_weight <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> defaultdict(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</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="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'text'</span>: []})</span>
<span id="cb4-12"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> edge <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.edges(data<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="cb4-13">    weight <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> edge[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].get(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'weight'</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb4-14">    x0, y0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[edge[<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;">'pos'</span>]</span>
<span id="cb4-15">    x1, y1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[edge[<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;">'pos'</span>]</span>
<span id="cb4-16">    edges_by_weight[weight][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>].extend([x0, x1, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>])</span>
<span id="cb4-17">    edges_by_weight[weight][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>].extend([y0, y1, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>])</span>
<span id="cb4-18"></span>
<span id="cb4-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define a colorscale</span></span>
<span id="cb4-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define a colorscale for the edges</span></span>
<span id="cb4-21">min_weight <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(edges_by_weight.keys()) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> edges_by_weight <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb4-22">max_weight <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(edges_by_weight.keys()) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> edges_by_weight <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb4-23">base_colorscale <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> px.colors.sequential.Blues</span>
<span id="cb4-24"></span>
<span id="cb4-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create a discrete color map</span></span>
<span id="cb4-26">unique_weights <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(edges_by_weight.keys()))</span>
<span id="cb4-27">num_unique_weights <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(unique_weights)</span>
<span id="cb4-28"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> num_unique_weights <span class="op" 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="cb4-29">    color_map <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {weight: base_colorscale[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(base_colorscale) <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 class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (num_unique_weights <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 class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, weight <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(unique_weights)}</span>
<span id="cb4-30"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb4-31">    color_map <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {unique_weights[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]: base_colorscale[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]} <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> unique_weights <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> {}</span>
<span id="cb4-32"></span>
<span id="cb4-33"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> weight, a <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(edges_by_weight.items()):</span>
<span id="cb4-34">    color <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> color_map.get(weight, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#888888'</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Default color if weight not in map</span></span>
<span id="cb4-35">    edge_trace <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Scatter(x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>a[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>], y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>a[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>], line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(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;">2</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color), hoverinfo<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;">'none'</span>, mode<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'</span>)</span>
<span id="cb4-36">    fig_data.append(edge_trace)</span>
<span id="cb4-37"></span>
<span id="cb4-38">edge_hover_x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-39">edge_hover_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-40">edge_hover_text <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-41"></span>
<span id="cb4-42"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> edge <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.edges(data<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="cb4-43">    x0, y0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[edge[<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;">'pos'</span>]</span>
<span id="cb4-44">    x1, y1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[edge[<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;">'pos'</span>]</span>
<span id="cb4-45">    weight <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> edge[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].get(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'weight'</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb4-46">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Position the hover point at the midpoint of the edge</span></span>
<span id="cb4-47">    edge_hover_x.append((x0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1) <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-48">    edge_hover_y.append((y0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> y1) <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-49">    edge_hover_text.append(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>edge[<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="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> vs </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>edge[<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="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>weight<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;"> games'</span>)</span>
<span id="cb4-50"></span>
<span id="cb4-51"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># This trace holds the hover text and has invisible markers</span></span>
<span id="cb4-52">edge_hover_trace <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Scatter(</span>
<span id="cb4-53">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>edge_hover_x,</span>
<span id="cb4-54">    y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>edge_hover_y,</span>
<span id="cb4-55">    mode<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;">'markers'</span>,</span>
<span id="cb4-56">    hoverinfo<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;">'text'</span>,</span>
<span id="cb4-57">    text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>edge_hover_text,</span>
<span id="cb4-58">    marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</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;">20</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;">'rgba(0,0,0,0)'</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Invisible markers with a larger hover area</span></span>
<span id="cb4-59">)</span>
<span id="cb4-60">fig_data.append(edge_hover_trace)</span>
<span id="cb4-61"></span>
<span id="cb4-62">discrete_colorscale_for_bar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-63"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> num_unique_weights <span class="op" 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>
<span id="cb4-64">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, weight <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(unique_weights):</span>
<span id="cb4-65">        color <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> color_map.get(weight, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#888888'</span>)</span>
<span id="cb4-66">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define start and end points for this color's block in the bar (on a 0-1 scale)</span></span>
<span id="cb4-67">        start_norm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> num_unique_weights</span>
<span id="cb4-68">        end_norm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (i <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 class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> num_unique_weights</span>
<span id="cb4-69">        discrete_colorscale_for_bar.append([start_norm, color])</span>
<span id="cb4-70">        discrete_colorscale_for_bar.append([end_norm, color])</span>
<span id="cb4-71"></span>
<span id="cb4-72"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The colorbar needs to map values to this new 0-1 scale.</span></span>
<span id="cb4-73"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># We'll place the tick labels for our unique_weights in the center of each color block.</span></span>
<span id="cb4-74">tickvals_for_bar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [ (i <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>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> num_unique_weights <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(num_unique_weights) ]</span>
<span id="cb4-75">ticktext_for_bar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>(w) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> w <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> unique_weights]</span>
<span id="cb4-76"></span>
<span id="cb4-77">colorbar_trace <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Scatter(x<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>], 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>], mode<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;">'markers'</span>, marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb4-78">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The dummy `color` value is irrelevant because we control the scale with cmin/cmax</span></span>
<span id="cb4-79">    color<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>],</span>
<span id="cb4-80">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Here is our custom discrete colorscale</span></span>
<span id="cb4-81">    colorscale<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>discrete_colorscale_for_bar,</span>
<span id="cb4-82">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># We are now working in a normalized 0-1 space for the colorbar</span></span>
<span id="cb4-83">    cmin<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="cb4-84">    cmax<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="cb4-85">    showscale<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="cb4-86">    colorbar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb4-87">        thickness<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>,</span>
<span id="cb4-88">        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;">'Games Played'</span>,</span>
<span id="cb4-89">        xanchor<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="cb4-90">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Place tick labels at the center of each color block</span></span>
<span id="cb4-91">        tickvals<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>tickvals_for_bar,</span>
<span id="cb4-92">        ticktext<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ticktext_for_bar,</span>
<span id="cb4-93">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># This makes the color bar look more like distinct bins</span></span>
<span id="cb4-94">        outlinewidth<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="cb4-95">    )),</span>
<span id="cb4-96">    hoverinfo<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;">'none'</span></span>
<span id="cb4-97">)</span>
<span id="cb4-98">fig_data.append(colorbar_trace)</span>
<span id="cb4-99"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Create Node Trace ---</span></span>
<span id="cb4-100">node_x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-101">node_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-102"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> node <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.nodes():</span>
<span id="cb4-103">    x, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[node][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pos'</span>]</span>
<span id="cb4-104">    node_x.append(x)</span>
<span id="cb4-105">    node_y.append(y)</span>
<span id="cb4-106">    </span>
<span id="cb4-107"></span>
<span id="cb4-108">node_adjacencies <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-109">node_text <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-110"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> node, adjacencies <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.adjacency():</span>
<span id="cb4-111">    num_connections <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(adjacencies)</span>
<span id="cb4-112">    node_adjacencies.append(num_connections)</span>
<span id="cb4-113">    node_text.append(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Team: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>node<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="cb4-114"></span>
<span id="cb4-115">node_trace <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Scatter(</span>
<span id="cb4-116">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>node_x, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>node_y,</span>
<span id="cb4-117">    mode<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;">'markers'</span>,</span>
<span id="cb4-118">    hoverinfo<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;">'text'</span>,</span>
<span id="cb4-119">    hovertext<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>node_text,</span>
<span id="cb4-120">    marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb4-121">        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;">35</span>, <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Make the hover area large</span></span>
<span id="cb4-122">        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;">'rgba(255, 255, 255, 1)'</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Make the markers invisible</span></span>
<span id="cb4-123">    )</span>
<span id="cb4-124">)</span>
<span id="cb4-125">fig_data.append(node_trace)</span>
<span id="cb4-126"></span>
<span id="cb4-127">layout_images <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb4-128"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate the range of coordinates to dynamically size logos</span></span>
<span id="cb4-129">x_range <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(node_x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(node_x) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> node_x <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb4-130">y_range <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(node_y) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(node_y) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> node_y <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb4-131">logo_size_x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> x_range <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.08</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Adjust the multiplier as needed</span></span>
<span id="cb4-132">logo_size_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y_range <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.08</span></span>
<span id="cb4-133"></span>
<span id="cb4-134"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> node <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.nodes():</span>
<span id="cb4-135">    x, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[node][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pos'</span>]</span>
<span id="cb4-136">    logo_url <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> team_logos.get(node)</span>
<span id="cb4-137">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> logo_url:</span>
<span id="cb4-138">        layout_images.append(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(source<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>logo_url, xref<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;">"x"</span>, yref<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;">"y"</span>, x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>x, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y, sizex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>logo_size_x, sizey<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>logo_size_y, xanchor<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>, yanchor<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;">"middle"</span>, layer<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;">"above"</span>))</span>
<span id="cb4-139"></span>
<span id="cb4-140"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Create the Figure ---</span></span>
<span id="cb4-141">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Figure(</span>
<span id="cb4-142">    data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>fig_data,</span>
<span id="cb4-143">    layout<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>go.Layout(</span>
<span id="cb4-144">        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;">'&lt;br&gt;MLB 2025 Schedule Matchups'</span>,</span>
<span id="cb4-145">        showlegend<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-146">        hovermode<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;">'closest'</span>,</span>
<span id="cb4-147">        margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(b<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>,l<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>,r<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>,t<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;">60</span>),</span>
<span id="cb4-148">        xaxis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(showgrid<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>, zeroline<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>, showticklabels<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-149">        yaxis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(showgrid<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>, zeroline<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>, showticklabels<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-150">        height<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;">600</span>, 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;">800</span>,</span>
<span id="cb4-151">        images<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>layout_images,</span>
<span id="cb4-152">    ),</span>
<span id="cb4-153">)</span>
<span id="cb4-154">fig.show()</span></code></pre></div>
</details>
<div id="figmlb-graph-interactive-1" class="cell-output cell-output-display">
        <script type="text/javascript">
        window.PlotlyConfig = {MathJaxConfig: 'local'};
        if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}
        </script>
        <script type="module">import "https://cdn.plot.ly/plotly-3.0.1.min"</script>
        
<p>Interactive Graph Network of MLB Teams and Their Matchups in the 2025 Season</p>
</div>
<div id="figmlb-graph-interactive-2" class="cell-output cell-output-display">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="1bdde03d-0e75-4616-96d8-bcaae199bb14" class="plotly-graph-div" style="height:600px; width:800px;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("1bdde03d-0e75-4616-96d8-bcaae199bb14")) {                    Plotly.newPlot(                        "1bdde03d-0e75-4616-96d8-bcaae199bb14",                        [{"hoverinfo":"none","line":{"color":"rgb(247,251,255)","width":2},"mode":"lines","x":[-0.04971980091163401,0.7923783203138837,null,-0.04971980091163401,0.44683830518461165,null,-0.04971980091163401,0.4752774404006889,null,-0.04971980091163401,0.9472062065390072,null,-0.04971980091163401,0.20213016405575931,null,-0.04971980091163401,0.11208129186651997,null,-0.04971980091163401,-0.47130468589113905,null,-0.04971980091163401,-0.021139410458931668,null,-0.04971980091163401,-0.2640612720793042,null,-0.04971980091163401,0.30233937862709037,null,-0.04971980091163401,-0.19776722281883458,null,-0.04971980091163401,0.94594035491709,null,-0.04971980091163401,0.6107335559824987,null,-0.04971980091163401,0.784733808705997,null,0.44683830518461165,-0.9587056845686045,null,0.44683830518461165,0.17201038114210768,null,0.44683830518461165,0.46815029513736683,null,0.44683830518461165,-0.6252448981132341,null,0.44683830518461165,-0.8034227747685079,null,0.44683830518461165,-0.9490341114677298,null,0.44683830518461165,-0.49924482802783193,null,0.44683830518461165,-0.13152454922746928,null,0.44683830518461165,0.2933468056946778,null,0.44683830518461165,-0.07830727779608779,null,0.44683830518461165,-0.6474637572088544,null,0.44683830518461165,-0.3497772666361602,null,0.44683830518461165,-0.40396251644252973,null,0.6744720869913147,-0.8034227747685079,null,0.6744720869913147,-0.3497772666361602,null,0.6744720869913147,-0.7769583391417596,null,0.6744720869913147,-0.13152454922746928,null,0.6744720869913147,-0.49924482802783193,null,0.6744720869913147,0.17201038114210768,null,0.6744720869913147,-0.40396251644252973,null,0.6744720869913147,0.2933468056946778,null,0.6744720869913147,-0.07830727779608779,null,0.6744720869913147,-0.6252448981132341,null,0.6744720869913147,0.46815029513736683,null,0.6744720869913147,-0.6474637572088544,null,0.6744720869913147,-0.9587056845686045,null,0.6744720869913147,-0.9490341114677298,null,-0.40396251644252973,-0.021139410458931668,null,-0.40396251644252973,0.20213016405575931,null,-0.40396251644252973,-0.2640612720793042,null,-0.40396251644252973,0.4752774404006889,null,-0.40396251644252973,-0.47130468589113905,null,-0.40396251644252973,-0.19776722281883458,null,-0.40396251644252973,0.7923783203138837,null,-0.40396251644252973,0.11208129186651997,null,-0.40396251644252973,0.30233937862709037,null,-0.40396251644252973,0.6107335559824987,null,-0.40396251644252973,0.94594035491709,null,-0.40396251644252973,0.784733808705997,null,0.9472062065390072,-0.6474637572088544,null,0.9472062065390072,-0.9490341114677298,null,0.9472062065390072,-0.7769583391417596,null,0.9472062065390072,0.17201038114210768,null,0.9472062065390072,0.46815029513736683,null,0.9472062065390072,-0.07830727779608779,null,0.9472062065390072,-0.6252448981132341,null,0.9472062065390072,0.2933468056946778,null,0.9472062065390072,-0.13152454922746928,null,0.9472062065390072,-0.9587056845686045,null,0.9472062065390072,-0.8034227747685079,null,0.9472062065390072,-0.49924482802783193,null,0.9472062065390072,-0.3497772666361602,null,-0.7769583391417596,-0.2640612720793042,null,-0.7769583391417596,0.7923783203138837,null,-0.7769583391417596,-0.021139410458931668,null,-0.7769583391417596,0.6107335559824987,null,-0.7769583391417596,0.4752774404006889,null,-0.7769583391417596,0.94594035491709,null,-0.7769583391417596,-0.47130468589113905,null,-0.7769583391417596,0.20213016405575931,null,-0.7769583391417596,0.30233937862709037,null,-0.7769583391417596,0.11208129186651997,null,-0.7769583391417596,0.784733808705997,null,-0.7769583391417596,-0.19776722281883458,null,-0.6252448981132341,0.4752774404006889,null,-0.6252448981132341,0.784733808705997,null,-0.6252448981132341,0.6107335559824987,null,-0.6252448981132341,0.94594035491709,null,-0.6252448981132341,-0.19776722281883458,null,-0.6252448981132341,-0.47130468589113905,null,-0.6252448981132341,0.7923783203138837,null,-0.6252448981132341,-0.021139410458931668,null,-0.6252448981132341,-0.2640612720793042,null,-0.6252448981132341,0.30233937862709037,null,-0.6252448981132341,0.11208129186651997,null,-0.3497772666361602,0.6107335559824987,null,-0.3497772666361602,-0.47130468589113905,null,-0.3497772666361602,-0.021139410458931668,null,-0.3497772666361602,0.20213016405575931,null,-0.3497772666361602,0.4752774404006889,null,-0.3497772666361602,-0.19776722281883458,null,-0.3497772666361602,0.30233937862709037,null,-0.3497772666361602,0.11208129186651997,null,-0.3497772666361602,0.784733808705997,null,-0.3497772666361602,-0.2640612720793042,null,-0.3497772666361602,0.94594035491709,null,0.20213016405575931,-0.9587056845686045,null,0.20213016405575931,-0.8034227747685079,null,0.20213016405575931,-0.6474637572088544,null,0.20213016405575931,0.46815029513736683,null,0.20213016405575931,-0.9490341114677298,null,0.20213016405575931,-0.07830727779608779,null,0.20213016405575931,0.2933468056946778,null,0.20213016405575931,-0.49924482802783193,null,0.20213016405575931,-0.13152454922746928,null,0.20213016405575931,0.17201038114210768,null,0.7923783203138837,-0.13152454922746928,null,0.7923783203138837,-0.6474637572088544,null,0.7923783203138837,-0.49924482802783193,null,0.7923783203138837,-0.9587056845686045,null,0.7923783203138837,-0.9490341114677298,null,0.7923783203138837,0.2933468056946778,null,0.7923783203138837,-0.8034227747685079,null,0.7923783203138837,0.46815029513736683,null,0.7923783203138837,0.17201038114210768,null,0.7923783203138837,-0.07830727779608779,null,-0.47130468589113905,-0.49924482802783193,null,-0.47130468589113905,-0.9587056845686045,null,-0.47130468589113905,-0.9490341114677298,null,-0.47130468589113905,-0.13152454922746928,null,-0.47130468589113905,0.17201038114210768,null,-0.47130468589113905,-0.8034227747685079,null,-0.47130468589113905,-0.07830727779608779,null,-0.47130468589113905,0.46815029513736683,null,-0.47130468589113905,0.2933468056946778,null,0.11208129186651997,-0.6474637572088544,null,0.11208129186651997,-0.13152454922746928,null,0.11208129186651997,-0.07830727779608779,null,0.11208129186651997,-0.9587056845686045,null,0.11208129186651997,0.17201038114210768,null,0.11208129186651997,-0.8034227747685079,null,0.11208129186651997,-0.9490341114677298,null,0.11208129186651997,0.46815029513736683,null,0.11208129186651997,0.2933468056946778,null,-0.6474637572088544,0.30233937862709037,null,-0.6474637572088544,-0.021139410458931668,null,-0.6474637572088544,0.784733808705997,null,-0.6474637572088544,0.94594035491709,null,-0.6474637572088544,-0.19776722281883458,null,-0.6474637572088544,-0.2640612720793042,null,-0.6474637572088544,0.4752774404006889,null,-0.6474637572088544,0.6107335559824987,null,-0.49924482802783193,0.4752774404006889,null,-0.49924482802783193,-0.021139410458931668,null,-0.49924482802783193,-0.19776722281883458,null,-0.49924482802783193,0.6107335559824987,null,-0.49924482802783193,-0.2640612720793042,null,-0.49924482802783193,0.784733808705997,null,-0.49924482802783193,0.30233937862709037,null,-0.49924482802783193,0.94594035491709,null,-0.8034227747685079,-0.021139410458931668,null,-0.8034227747685079,-0.2640612720793042,null,-0.8034227747685079,0.4752774404006889,null,-0.8034227747685079,0.30233937862709037,null,-0.8034227747685079,0.784733808705997,null,-0.8034227747685079,0.94594035491709,null,-0.8034227747685079,0.6107335559824987,null,-0.19776722281883458,0.17201038114210768,null,-0.19776722281883458,-0.9587056845686045,null,-0.19776722281883458,-0.13152454922746928,null,-0.19776722281883458,-0.9490341114677298,null,-0.19776722281883458,0.2933468056946778,null,-0.19776722281883458,-0.07830727779608779,null,-0.19776722281883458,0.46815029513736683,null,-0.9587056845686045,0.784733808705997,null,-0.9587056845686045,-0.021139410458931668,null,-0.9587056845686045,0.4752774404006889,null,-0.9587056845686045,0.30233937862709037,null,-0.9587056845686045,0.6107335559824987,null,-0.9587056845686045,0.94594035491709,null,-0.07830727779608779,0.6107335559824987,null,-0.07830727779608779,0.94594035491709,null,-0.07830727779608779,0.784733808705997,null,-0.07830727779608779,0.4752774404006889,null,-0.07830727779608779,-0.2640612720793042,null,-0.07830727779608779,-0.021139410458931668,null,-0.021139410458931668,0.46815029513736683,null,-0.021139410458931668,0.2933468056946778,null,-0.021139410458931668,-0.13152454922746928,null,-0.021139410458931668,0.17201038114210768,null,0.6107335559824987,-0.9490341114677298,null,0.6107335559824987,0.2933468056946778,null,0.6107335559824987,-0.13152454922746928,null,0.6107335559824987,0.46815029513736683,null,-0.2640612720793042,-0.9490341114677298,null,-0.2640612720793042,0.46815029513736683,null,-0.2640612720793042,0.2933468056946778,null,-0.2640612720793042,-0.13152454922746928,null,-0.2640612720793042,0.17201038114210768,null,0.17201038114210768,0.784733808705997,null,0.17201038114210768,0.4752774404006889,null,0.17201038114210768,0.30233937862709037,null,0.17201038114210768,0.94594035491709,null,-0.9490341114677298,0.4752774404006889,null,-0.9490341114677298,0.94594035491709,null,-0.9490341114677298,0.30233937862709037,null,-0.9490341114677298,0.784733808705997,null,0.94594035491709,0.46815029513736683,null,0.94594035491709,-0.13152454922746928,null,0.46815029513736683,0.30233937862709037,null,0.46815029513736683,0.4752774404006889,null,0.784733808705997,-0.13152454922746928,null,0.784733808705997,0.2933468056946778,null,0.2933468056946778,0.30233937862709037,null,0.2933468056946778,0.4752774404006889,null,-0.13152454922746928,0.30233937862709037,null],"y":[0.983007903486735,0.3248586724293874,null,0.983007903486735,0.1226571947305712,null,0.983007903486735,-0.8885340085748538,null,0.983007903486735,0.03491396132422168,null,0.983007903486735,-0.16070011925745725,null,0.983007903486735,-1.0,null,0.983007903486735,-0.6980195462441733,null,0.983007903486735,-0.7135256658318695,null,0.983007903486735,-0.9460743892940172,null,0.983007903486735,-0.5568146874414868,null,0.983007903486735,-0.46083955276844274,null,0.983007903486735,-0.3568940731424135,null,0.983007903486735,-0.45887811984869514,null,0.983007903486735,-0.7062299888031088,null,0.1226571947305712,-0.06083864586342279,null,0.1226571947305712,0.45604290006075976,null,0.1226571947305712,0.6497403923440755,null,0.1226571947305712,0.8126069043372498,null,0.1226571947305712,-0.31664391173928624,null,0.1226571947305712,0.26568818062818117,null,0.1226571947305712,-0.13108624400660954,null,0.1226571947305712,0.1956428369615909,null,0.1226571947305712,0.890145208878703,null,0.1226571947305712,0.6487473861977073,null,0.1226571947305712,0.15666503090875003,null,0.1226571947305712,0.9495207211781491,null,0.1226571947305712,0.4908085944608781,null,-0.09705236714160678,-0.31664391173928624,null,-0.09705236714160678,0.9495207211781491,null,-0.09705236714160678,0.5710854320304929,null,-0.09705236714160678,0.1956428369615909,null,-0.09705236714160678,-0.13108624400660954,null,-0.09705236714160678,0.45604290006075976,null,-0.09705236714160678,0.4908085944608781,null,-0.09705236714160678,0.890145208878703,null,-0.09705236714160678,0.6487473861977073,null,-0.09705236714160678,0.8126069043372498,null,-0.09705236714160678,0.6497403923440755,null,-0.09705236714160678,0.15666503090875003,null,-0.09705236714160678,-0.06083864586342279,null,-0.09705236714160678,0.26568818062818117,null,0.4908085944608781,-0.7135256658318695,null,0.4908085944608781,-0.16070011925745725,null,0.4908085944608781,-0.9460743892940172,null,0.4908085944608781,-0.8885340085748538,null,0.4908085944608781,-0.6980195462441733,null,0.4908085944608781,-0.46083955276844274,null,0.4908085944608781,0.3248586724293874,null,0.4908085944608781,-1.0,null,0.4908085944608781,-0.5568146874414868,null,0.4908085944608781,-0.45887811984869514,null,0.4908085944608781,-0.3568940731424135,null,0.4908085944608781,-0.7062299888031088,null,0.03491396132422168,0.15666503090875003,null,0.03491396132422168,0.26568818062818117,null,0.03491396132422168,0.5710854320304929,null,0.03491396132422168,0.45604290006075976,null,0.03491396132422168,0.6497403923440755,null,0.03491396132422168,0.6487473861977073,null,0.03491396132422168,0.8126069043372498,null,0.03491396132422168,0.890145208878703,null,0.03491396132422168,0.1956428369615909,null,0.03491396132422168,-0.06083864586342279,null,0.03491396132422168,-0.31664391173928624,null,0.03491396132422168,-0.13108624400660954,null,0.03491396132422168,0.9495207211781491,null,0.5710854320304929,-0.9460743892940172,null,0.5710854320304929,0.3248586724293874,null,0.5710854320304929,-0.7135256658318695,null,0.5710854320304929,-0.45887811984869514,null,0.5710854320304929,-0.8885340085748538,null,0.5710854320304929,-0.3568940731424135,null,0.5710854320304929,-0.6980195462441733,null,0.5710854320304929,-0.16070011925745725,null,0.5710854320304929,-0.5568146874414868,null,0.5710854320304929,-1.0,null,0.5710854320304929,-0.7062299888031088,null,0.5710854320304929,-0.46083955276844274,null,0.8126069043372498,-0.8885340085748538,null,0.8126069043372498,-0.7062299888031088,null,0.8126069043372498,-0.45887811984869514,null,0.8126069043372498,-0.3568940731424135,null,0.8126069043372498,-0.46083955276844274,null,0.8126069043372498,-0.6980195462441733,null,0.8126069043372498,0.3248586724293874,null,0.8126069043372498,-0.7135256658318695,null,0.8126069043372498,-0.9460743892940172,null,0.8126069043372498,-0.5568146874414868,null,0.8126069043372498,-1.0,null,0.9495207211781491,-0.45887811984869514,null,0.9495207211781491,-0.6980195462441733,null,0.9495207211781491,-0.7135256658318695,null,0.9495207211781491,-0.16070011925745725,null,0.9495207211781491,-0.8885340085748538,null,0.9495207211781491,-0.46083955276844274,null,0.9495207211781491,-0.5568146874414868,null,0.9495207211781491,-1.0,null,0.9495207211781491,-0.7062299888031088,null,0.9495207211781491,-0.9460743892940172,null,0.9495207211781491,-0.3568940731424135,null,-0.16070011925745725,-0.06083864586342279,null,-0.16070011925745725,-0.31664391173928624,null,-0.16070011925745725,0.15666503090875003,null,-0.16070011925745725,0.6497403923440755,null,-0.16070011925745725,0.26568818062818117,null,-0.16070011925745725,0.6487473861977073,null,-0.16070011925745725,0.890145208878703,null,-0.16070011925745725,-0.13108624400660954,null,-0.16070011925745725,0.1956428369615909,null,-0.16070011925745725,0.45604290006075976,null,0.3248586724293874,0.1956428369615909,null,0.3248586724293874,0.15666503090875003,null,0.3248586724293874,-0.13108624400660954,null,0.3248586724293874,-0.06083864586342279,null,0.3248586724293874,0.26568818062818117,null,0.3248586724293874,0.890145208878703,null,0.3248586724293874,-0.31664391173928624,null,0.3248586724293874,0.6497403923440755,null,0.3248586724293874,0.45604290006075976,null,0.3248586724293874,0.6487473861977073,null,-0.6980195462441733,-0.13108624400660954,null,-0.6980195462441733,-0.06083864586342279,null,-0.6980195462441733,0.26568818062818117,null,-0.6980195462441733,0.1956428369615909,null,-0.6980195462441733,0.45604290006075976,null,-0.6980195462441733,-0.31664391173928624,null,-0.6980195462441733,0.6487473861977073,null,-0.6980195462441733,0.6497403923440755,null,-0.6980195462441733,0.890145208878703,null,-1.0,0.15666503090875003,null,-1.0,0.1956428369615909,null,-1.0,0.6487473861977073,null,-1.0,-0.06083864586342279,null,-1.0,0.45604290006075976,null,-1.0,-0.31664391173928624,null,-1.0,0.26568818062818117,null,-1.0,0.6497403923440755,null,-1.0,0.890145208878703,null,0.15666503090875003,-0.5568146874414868,null,0.15666503090875003,-0.7135256658318695,null,0.15666503090875003,-0.7062299888031088,null,0.15666503090875003,-0.3568940731424135,null,0.15666503090875003,-0.46083955276844274,null,0.15666503090875003,-0.9460743892940172,null,0.15666503090875003,-0.8885340085748538,null,0.15666503090875003,-0.45887811984869514,null,-0.13108624400660954,-0.8885340085748538,null,-0.13108624400660954,-0.7135256658318695,null,-0.13108624400660954,-0.46083955276844274,null,-0.13108624400660954,-0.45887811984869514,null,-0.13108624400660954,-0.9460743892940172,null,-0.13108624400660954,-0.7062299888031088,null,-0.13108624400660954,-0.5568146874414868,null,-0.13108624400660954,-0.3568940731424135,null,-0.31664391173928624,-0.7135256658318695,null,-0.31664391173928624,-0.9460743892940172,null,-0.31664391173928624,-0.8885340085748538,null,-0.31664391173928624,-0.5568146874414868,null,-0.31664391173928624,-0.7062299888031088,null,-0.31664391173928624,-0.3568940731424135,null,-0.31664391173928624,-0.45887811984869514,null,-0.46083955276844274,0.45604290006075976,null,-0.46083955276844274,-0.06083864586342279,null,-0.46083955276844274,0.1956428369615909,null,-0.46083955276844274,0.26568818062818117,null,-0.46083955276844274,0.890145208878703,null,-0.46083955276844274,0.6487473861977073,null,-0.46083955276844274,0.6497403923440755,null,-0.06083864586342279,-0.7062299888031088,null,-0.06083864586342279,-0.7135256658318695,null,-0.06083864586342279,-0.8885340085748538,null,-0.06083864586342279,-0.5568146874414868,null,-0.06083864586342279,-0.45887811984869514,null,-0.06083864586342279,-0.3568940731424135,null,0.6487473861977073,-0.45887811984869514,null,0.6487473861977073,-0.3568940731424135,null,0.6487473861977073,-0.7062299888031088,null,0.6487473861977073,-0.8885340085748538,null,0.6487473861977073,-0.9460743892940172,null,0.6487473861977073,-0.7135256658318695,null,-0.7135256658318695,0.6497403923440755,null,-0.7135256658318695,0.890145208878703,null,-0.7135256658318695,0.1956428369615909,null,-0.7135256658318695,0.45604290006075976,null,-0.45887811984869514,0.26568818062818117,null,-0.45887811984869514,0.890145208878703,null,-0.45887811984869514,0.1956428369615909,null,-0.45887811984869514,0.6497403923440755,null,-0.9460743892940172,0.26568818062818117,null,-0.9460743892940172,0.6497403923440755,null,-0.9460743892940172,0.890145208878703,null,-0.9460743892940172,0.1956428369615909,null,-0.9460743892940172,0.45604290006075976,null,0.45604290006075976,-0.7062299888031088,null,0.45604290006075976,-0.8885340085748538,null,0.45604290006075976,-0.5568146874414868,null,0.45604290006075976,-0.3568940731424135,null,0.26568818062818117,-0.8885340085748538,null,0.26568818062818117,-0.3568940731424135,null,0.26568818062818117,-0.5568146874414868,null,0.26568818062818117,-0.7062299888031088,null,-0.3568940731424135,0.6497403923440755,null,-0.3568940731424135,0.1956428369615909,null,0.6497403923440755,-0.5568146874414868,null,0.6497403923440755,-0.8885340085748538,null,-0.7062299888031088,0.1956428369615909,null,-0.7062299888031088,0.890145208878703,null,0.890145208878703,-0.5568146874414868,null,0.890145208878703,-0.8885340085748538,null,0.1956428369615909,-0.5568146874414868,null],"type":"scatter"},{"hoverinfo":"none","line":{"color":"rgb(198,219,239)","width":2},"mode":"lines","x":[-0.04971980091163401,-0.9587056845686045,null,-0.04971980091163401,-0.8034227747685079,null,-0.04971980091163401,0.6744720869913147,null,-0.04971980091163401,0.46815029513736683,null,-0.04971980091163401,0.17201038114210768,null,-0.04971980091163401,-0.07830727779608779,null,-0.04971980091163401,-0.13152454922746928,null,-0.04971980091163401,-0.9490341114677298,null,-0.04971980091163401,-0.6474637572088544,null,0.44683830518461165,-0.021139410458931668,null,0.44683830518461165,0.94594035491709,null,0.44683830518461165,0.30233937862709037,null,0.44683830518461165,0.4752774404006889,null,0.44683830518461165,-0.7769583391417596,null,0.44683830518461165,-0.19776722281883458,null,0.44683830518461165,0.784733808705997,null,0.44683830518461165,-0.2640612720793042,null,0.44683830518461165,0.6107335559824987,null,0.6744720869913147,-0.19776722281883458,null,0.6744720869913147,0.4752774404006889,null,0.6744720869913147,0.784733808705997,null,0.6744720869913147,-0.47130468589113905,null,0.6744720869913147,-0.2640612720793042,null,0.6744720869913147,-0.021139410458931668,null,0.6744720869913147,0.6107335559824987,null,0.6744720869913147,0.30233937862709037,null,-0.40396251644252973,-0.07830727779608779,null,-0.40396251644252973,0.2933468056946778,null,-0.40396251644252973,0.46815029513736683,null,-0.40396251644252973,-0.9490341114677298,null,-0.40396251644252973,0.17201038114210768,null,-0.40396251644252973,0.9472062065390072,null,-0.40396251644252973,-0.6474637572088544,null,-0.40396251644252973,-0.49924482802783193,null,-0.40396251644252973,-0.9587056845686045,null,0.9472062065390072,-0.19776722281883458,null,0.9472062065390072,-0.2640612720793042,null,0.9472062065390072,0.6107335559824987,null,0.9472062065390072,0.11208129186651997,null,0.9472062065390072,0.94594035491709,null,0.9472062065390072,0.784733808705997,null,0.9472062065390072,0.30233937862709037,null,0.9472062065390072,-0.47130468589113905,null,-0.7769583391417596,-0.8034227747685079,null,-0.7769583391417596,-0.9490341114677298,null,-0.7769583391417596,0.17201038114210768,null,-0.7769583391417596,-0.49924482802783193,null,-0.7769583391417596,0.46815029513736683,null,-0.7769583391417596,-0.9587056845686045,null,-0.7769583391417596,0.2933468056946778,null,-0.7769583391417596,-0.13152454922746928,null,-0.6252448981132341,0.46815029513736683,null,-0.6252448981132341,0.17201038114210768,null,-0.6252448981132341,-0.07830727779608779,null,-0.6252448981132341,-0.13152454922746928,null,-0.6252448981132341,0.2933468056946778,null,-0.6252448981132341,-0.6474637572088544,null,-0.6252448981132341,-0.9490341114677298,null,-0.6252448981132341,-0.9587056845686045,null,-0.6252448981132341,0.20213016405575931,null,-0.3497772666361602,-0.49924482802783193,null,-0.3497772666361602,-0.9587056845686045,null,-0.3497772666361602,-0.07830727779608779,null,-0.3497772666361602,-0.8034227747685079,null,-0.3497772666361602,-0.13152454922746928,null,-0.3497772666361602,0.17201038114210768,null,-0.3497772666361602,0.7923783203138837,null,-0.3497772666361602,-0.6474637572088544,null,-0.3497772666361602,-0.9490341114677298,null,0.20213016405575931,0.6107335559824987,null,0.20213016405575931,-0.021139410458931668,null,0.20213016405575931,0.4752774404006889,null,0.20213016405575931,-0.19776722281883458,null,0.20213016405575931,0.94594035491709,null,0.20213016405575931,0.11208129186651997,null,0.20213016405575931,0.784733808705997,null,0.20213016405575931,-0.2640612720793042,null,0.7923783203138837,0.11208129186651997,null,0.7923783203138837,0.94594035491709,null,0.7923783203138837,-0.47130468589113905,null,0.7923783203138837,-0.021139410458931668,null,0.7923783203138837,-0.19776722281883458,null,0.7923783203138837,-0.2640612720793042,null,0.7923783203138837,0.30233937862709037,null,0.7923783203138837,0.4752774404006889,null,-0.47130468589113905,0.784733808705997,null,-0.47130468589113905,0.4752774404006889,null,-0.47130468589113905,0.6107335559824987,null,-0.47130468589113905,0.30233937862709037,null,-0.47130468589113905,-0.6474637572088544,null,-0.47130468589113905,0.94594035491709,null,0.11208129186651997,0.30233937862709037,null,0.11208129186651997,0.784733808705997,null,0.11208129186651997,-0.49924482802783193,null,0.11208129186651997,0.6107335559824987,null,0.11208129186651997,0.94594035491709,null,0.11208129186651997,0.4752774404006889,null,-0.6474637572088544,0.2933468056946778,null,-0.6474637572088544,-0.07830727779608779,null,-0.6474637572088544,0.46815029513736683,null,-0.6474637572088544,0.17201038114210768,null,-0.49924482802783193,0.2933468056946778,null,-0.49924482802783193,-0.07830727779608779,null,-0.49924482802783193,-0.13152454922746928,null,-0.49924482802783193,0.17201038114210768,null,-0.49924482802783193,0.46815029513736683,null,-0.8034227747685079,0.2933468056946778,null,-0.8034227747685079,-0.13152454922746928,null,-0.8034227747685079,0.17201038114210768,null,-0.8034227747685079,-0.19776722281883458,null,-0.8034227747685079,0.46815029513736683,null,-0.8034227747685079,-0.07830727779608779,null,-0.19776722281883458,0.784733808705997,null,-0.19776722281883458,0.94594035491709,null,-0.19776722281883458,0.6107335559824987,null,-0.9587056845686045,0.46815029513736683,null,-0.9587056845686045,-0.2640612720793042,null,-0.9587056845686045,0.2933468056946778,null,-0.9587056845686045,-0.13152454922746928,null,-0.07830727779608779,-0.9490341114677298,null,-0.07830727779608779,0.30233937862709037,null,-0.021139410458931668,0.4752774404006889,null,-0.021139410458931668,0.784733808705997,null,-0.021139410458931668,0.30233937862709037,null,-0.021139410458931668,-0.9490341114677298,null,-0.021139410458931668,0.6107335559824987,null,0.6107335559824987,0.17201038114210768,null,-0.2640612720793042,0.4752774404006889,null,-0.2640612720793042,0.30233937862709037,null,-0.2640612720793042,0.94594035491709,null,-0.9490341114677298,-0.13152454922746928,null,-0.9490341114677298,0.2933468056946778,null,0.94594035491709,0.2933468056946778,null,0.46815029513736683,0.784733808705997,null,0.4752774404006889,-0.13152454922746928,null],"y":[0.983007903486735,-0.06083864586342279,null,0.983007903486735,-0.31664391173928624,null,0.983007903486735,-0.09705236714160678,null,0.983007903486735,0.6497403923440755,null,0.983007903486735,0.45604290006075976,null,0.983007903486735,0.6487473861977073,null,0.983007903486735,0.1956428369615909,null,0.983007903486735,0.26568818062818117,null,0.983007903486735,0.15666503090875003,null,0.1226571947305712,-0.7135256658318695,null,0.1226571947305712,-0.3568940731424135,null,0.1226571947305712,-0.5568146874414868,null,0.1226571947305712,-0.8885340085748538,null,0.1226571947305712,0.5710854320304929,null,0.1226571947305712,-0.46083955276844274,null,0.1226571947305712,-0.7062299888031088,null,0.1226571947305712,-0.9460743892940172,null,0.1226571947305712,-0.45887811984869514,null,-0.09705236714160678,-0.46083955276844274,null,-0.09705236714160678,-0.8885340085748538,null,-0.09705236714160678,-0.7062299888031088,null,-0.09705236714160678,-0.6980195462441733,null,-0.09705236714160678,-0.9460743892940172,null,-0.09705236714160678,-0.7135256658318695,null,-0.09705236714160678,-0.45887811984869514,null,-0.09705236714160678,-0.5568146874414868,null,0.4908085944608781,0.6487473861977073,null,0.4908085944608781,0.890145208878703,null,0.4908085944608781,0.6497403923440755,null,0.4908085944608781,0.26568818062818117,null,0.4908085944608781,0.45604290006075976,null,0.4908085944608781,0.03491396132422168,null,0.4908085944608781,0.15666503090875003,null,0.4908085944608781,-0.13108624400660954,null,0.4908085944608781,-0.06083864586342279,null,0.03491396132422168,-0.46083955276844274,null,0.03491396132422168,-0.9460743892940172,null,0.03491396132422168,-0.45887811984869514,null,0.03491396132422168,-1.0,null,0.03491396132422168,-0.3568940731424135,null,0.03491396132422168,-0.7062299888031088,null,0.03491396132422168,-0.5568146874414868,null,0.03491396132422168,-0.6980195462441733,null,0.5710854320304929,-0.31664391173928624,null,0.5710854320304929,0.26568818062818117,null,0.5710854320304929,0.45604290006075976,null,0.5710854320304929,-0.13108624400660954,null,0.5710854320304929,0.6497403923440755,null,0.5710854320304929,-0.06083864586342279,null,0.5710854320304929,0.890145208878703,null,0.5710854320304929,0.1956428369615909,null,0.8126069043372498,0.6497403923440755,null,0.8126069043372498,0.45604290006075976,null,0.8126069043372498,0.6487473861977073,null,0.8126069043372498,0.1956428369615909,null,0.8126069043372498,0.890145208878703,null,0.8126069043372498,0.15666503090875003,null,0.8126069043372498,0.26568818062818117,null,0.8126069043372498,-0.06083864586342279,null,0.8126069043372498,-0.16070011925745725,null,0.9495207211781491,-0.13108624400660954,null,0.9495207211781491,-0.06083864586342279,null,0.9495207211781491,0.6487473861977073,null,0.9495207211781491,-0.31664391173928624,null,0.9495207211781491,0.1956428369615909,null,0.9495207211781491,0.45604290006075976,null,0.9495207211781491,0.3248586724293874,null,0.9495207211781491,0.15666503090875003,null,0.9495207211781491,0.26568818062818117,null,-0.16070011925745725,-0.45887811984869514,null,-0.16070011925745725,-0.7135256658318695,null,-0.16070011925745725,-0.8885340085748538,null,-0.16070011925745725,-0.46083955276844274,null,-0.16070011925745725,-0.3568940731424135,null,-0.16070011925745725,-1.0,null,-0.16070011925745725,-0.7062299888031088,null,-0.16070011925745725,-0.9460743892940172,null,0.3248586724293874,-1.0,null,0.3248586724293874,-0.3568940731424135,null,0.3248586724293874,-0.6980195462441733,null,0.3248586724293874,-0.7135256658318695,null,0.3248586724293874,-0.46083955276844274,null,0.3248586724293874,-0.9460743892940172,null,0.3248586724293874,-0.5568146874414868,null,0.3248586724293874,-0.8885340085748538,null,-0.6980195462441733,-0.7062299888031088,null,-0.6980195462441733,-0.8885340085748538,null,-0.6980195462441733,-0.45887811984869514,null,-0.6980195462441733,-0.5568146874414868,null,-0.6980195462441733,0.15666503090875003,null,-0.6980195462441733,-0.3568940731424135,null,-1.0,-0.5568146874414868,null,-1.0,-0.7062299888031088,null,-1.0,-0.13108624400660954,null,-1.0,-0.45887811984869514,null,-1.0,-0.3568940731424135,null,-1.0,-0.8885340085748538,null,0.15666503090875003,0.890145208878703,null,0.15666503090875003,0.6487473861977073,null,0.15666503090875003,0.6497403923440755,null,0.15666503090875003,0.45604290006075976,null,-0.13108624400660954,0.890145208878703,null,-0.13108624400660954,0.6487473861977073,null,-0.13108624400660954,0.1956428369615909,null,-0.13108624400660954,0.45604290006075976,null,-0.13108624400660954,0.6497403923440755,null,-0.31664391173928624,0.890145208878703,null,-0.31664391173928624,0.1956428369615909,null,-0.31664391173928624,0.45604290006075976,null,-0.31664391173928624,-0.46083955276844274,null,-0.31664391173928624,0.6497403923440755,null,-0.31664391173928624,0.6487473861977073,null,-0.46083955276844274,-0.7062299888031088,null,-0.46083955276844274,-0.3568940731424135,null,-0.46083955276844274,-0.45887811984869514,null,-0.06083864586342279,0.6497403923440755,null,-0.06083864586342279,-0.9460743892940172,null,-0.06083864586342279,0.890145208878703,null,-0.06083864586342279,0.1956428369615909,null,0.6487473861977073,0.26568818062818117,null,0.6487473861977073,-0.5568146874414868,null,-0.7135256658318695,-0.8885340085748538,null,-0.7135256658318695,-0.7062299888031088,null,-0.7135256658318695,-0.5568146874414868,null,-0.7135256658318695,0.26568818062818117,null,-0.7135256658318695,-0.45887811984869514,null,-0.45887811984869514,0.45604290006075976,null,-0.9460743892940172,-0.8885340085748538,null,-0.9460743892940172,-0.5568146874414868,null,-0.9460743892940172,-0.3568940731424135,null,0.26568818062818117,0.1956428369615909,null,0.26568818062818117,0.890145208878703,null,-0.3568940731424135,0.890145208878703,null,0.6497403923440755,-0.7062299888031088,null,-0.8885340085748538,0.1956428369615909,null],"type":"scatter"},{"hoverinfo":"none","line":{"color":"rgb(66,146,198)","width":2},"mode":"lines","x":[-0.04971980091163401,0.2933468056946778,null,-0.04971980091163401,-0.49924482802783193,null,0.44683830518461165,0.11208129186651997,null,0.44683830518461165,-0.47130468589113905,null,0.6744720869913147,0.94594035491709,null,0.6744720869913147,0.11208129186651997,null,-0.40396251644252973,-0.8034227747685079,null,-0.40396251644252973,-0.13152454922746928,null,0.9472062065390072,-0.021139410458931668,null,0.9472062065390072,0.4752774404006889,null,-0.7769583391417596,-0.07830727779608779,null,-0.7769583391417596,-0.6474637572088544,null,-0.6252448981132341,-0.8034227747685079,null,-0.6252448981132341,-0.49924482802783193,null,-0.3497772666361602,0.2933468056946778,null,-0.3497772666361602,0.46815029513736683,null,0.20213016405575931,0.30233937862709037,null,0.20213016405575931,-0.47130468589113905,null,0.7923783203138837,0.6107335559824987,null,0.7923783203138837,0.784733808705997,null,-0.6474637572088544,-0.13152454922746928,null,-0.19776722281883458,0.30233937862709037,null,-0.19776722281883458,0.4752774404006889,null,-0.9587056845686045,0.17201038114210768,null,-0.9587056845686045,-0.07830727779608779,null,-0.021139410458931668,0.94594035491709,null,0.6107335559824987,-0.2640612720793042,null,-0.2640612720793042,0.784733808705997,null,0.17201038114210768,-0.9490341114677298,null,-0.9490341114677298,0.46815029513736683,null],"y":[0.983007903486735,0.890145208878703,null,0.983007903486735,-0.13108624400660954,null,0.1226571947305712,-1.0,null,0.1226571947305712,-0.6980195462441733,null,-0.09705236714160678,-0.3568940731424135,null,-0.09705236714160678,-1.0,null,0.4908085944608781,-0.31664391173928624,null,0.4908085944608781,0.1956428369615909,null,0.03491396132422168,-0.7135256658318695,null,0.03491396132422168,-0.8885340085748538,null,0.5710854320304929,0.6487473861977073,null,0.5710854320304929,0.15666503090875003,null,0.8126069043372498,-0.31664391173928624,null,0.8126069043372498,-0.13108624400660954,null,0.9495207211781491,0.890145208878703,null,0.9495207211781491,0.6497403923440755,null,-0.16070011925745725,-0.5568146874414868,null,-0.16070011925745725,-0.6980195462441733,null,0.3248586724293874,-0.45887811984869514,null,0.3248586724293874,-0.7062299888031088,null,0.15666503090875003,0.1956428369615909,null,-0.46083955276844274,-0.5568146874414868,null,-0.46083955276844274,-0.8885340085748538,null,-0.06083864586342279,0.45604290006075976,null,-0.06083864586342279,0.6487473861977073,null,-0.7135256658318695,-0.3568940731424135,null,-0.45887811984869514,-0.9460743892940172,null,-0.9460743892940172,-0.7062299888031088,null,0.45604290006075976,0.26568818062818117,null,0.26568818062818117,0.6497403923440755,null],"type":"scatter"},{"hoverinfo":"none","line":{"color":"rgb(8,48,107)","width":2},"mode":"lines","x":[-0.04971980091163401,-0.7769583391417596,null,-0.04971980091163401,-0.3497772666361602,null,-0.04971980091163401,-0.6252448981132341,null,-0.04971980091163401,-0.40396251644252973,null,0.44683830518461165,0.6744720869913147,null,0.44683830518461165,0.7923783203138837,null,0.44683830518461165,0.20213016405575931,null,0.44683830518461165,0.9472062065390072,null,0.6744720869913147,0.20213016405575931,null,0.6744720869913147,0.9472062065390072,null,0.6744720869913147,0.7923783203138837,null,-0.40396251644252973,-0.3497772666361602,null,-0.40396251644252973,-0.6252448981132341,null,-0.40396251644252973,-0.7769583391417596,null,0.9472062065390072,0.7923783203138837,null,0.9472062065390072,0.20213016405575931,null,-0.7769583391417596,-0.3497772666361602,null,-0.7769583391417596,-0.6252448981132341,null,-0.6252448981132341,-0.3497772666361602,null,0.20213016405575931,0.7923783203138837,null,-0.47130468589113905,-0.2640612720793042,null,-0.47130468589113905,0.11208129186651997,null,-0.47130468589113905,-0.021139410458931668,null,-0.47130468589113905,-0.19776722281883458,null,0.11208129186651997,-0.19776722281883458,null,0.11208129186651997,-0.021139410458931668,null,0.11208129186651997,-0.2640612720793042,null,-0.6474637572088544,-0.9490341114677298,null,-0.6474637572088544,-0.49924482802783193,null,-0.6474637572088544,-0.9587056845686045,null,-0.6474637572088544,-0.8034227747685079,null,-0.49924482802783193,-0.9587056845686045,null,-0.49924482802783193,-0.8034227747685079,null,-0.49924482802783193,-0.9490341114677298,null,-0.8034227747685079,-0.9490341114677298,null,-0.8034227747685079,-0.9587056845686045,null,-0.19776722281883458,-0.021139410458931668,null,-0.19776722281883458,-0.2640612720793042,null,-0.9587056845686045,-0.9490341114677298,null,-0.07830727779608779,0.17201038114210768,null,-0.07830727779608779,0.2933468056946778,null,-0.07830727779608779,0.46815029513736683,null,-0.07830727779608779,-0.13152454922746928,null,-0.021139410458931668,-0.2640612720793042,null,0.6107335559824987,0.30233937862709037,null,0.6107335559824987,0.4752774404006889,null,0.6107335559824987,0.94594035491709,null,0.6107335559824987,0.784733808705997,null,0.17201038114210768,-0.13152454922746928,null,0.17201038114210768,0.46815029513736683,null,0.17201038114210768,0.2933468056946778,null,0.94594035491709,0.784733808705997,null,0.94594035491709,0.30233937862709037,null,0.94594035491709,0.4752774404006889,null,0.46815029513736683,0.2933468056946778,null,0.46815029513736683,-0.13152454922746928,null,0.784733808705997,0.30233937862709037,null,0.784733808705997,0.4752774404006889,null,0.2933468056946778,-0.13152454922746928,null,0.4752774404006889,0.30233937862709037,null],"y":[0.983007903486735,0.5710854320304929,null,0.983007903486735,0.9495207211781491,null,0.983007903486735,0.8126069043372498,null,0.983007903486735,0.4908085944608781,null,0.1226571947305712,-0.09705236714160678,null,0.1226571947305712,0.3248586724293874,null,0.1226571947305712,-0.16070011925745725,null,0.1226571947305712,0.03491396132422168,null,-0.09705236714160678,-0.16070011925745725,null,-0.09705236714160678,0.03491396132422168,null,-0.09705236714160678,0.3248586724293874,null,0.4908085944608781,0.9495207211781491,null,0.4908085944608781,0.8126069043372498,null,0.4908085944608781,0.5710854320304929,null,0.03491396132422168,0.3248586724293874,null,0.03491396132422168,-0.16070011925745725,null,0.5710854320304929,0.9495207211781491,null,0.5710854320304929,0.8126069043372498,null,0.8126069043372498,0.9495207211781491,null,-0.16070011925745725,0.3248586724293874,null,-0.6980195462441733,-0.9460743892940172,null,-0.6980195462441733,-1.0,null,-0.6980195462441733,-0.7135256658318695,null,-0.6980195462441733,-0.46083955276844274,null,-1.0,-0.46083955276844274,null,-1.0,-0.7135256658318695,null,-1.0,-0.9460743892940172,null,0.15666503090875003,0.26568818062818117,null,0.15666503090875003,-0.13108624400660954,null,0.15666503090875003,-0.06083864586342279,null,0.15666503090875003,-0.31664391173928624,null,-0.13108624400660954,-0.06083864586342279,null,-0.13108624400660954,-0.31664391173928624,null,-0.13108624400660954,0.26568818062818117,null,-0.31664391173928624,0.26568818062818117,null,-0.31664391173928624,-0.06083864586342279,null,-0.46083955276844274,-0.7135256658318695,null,-0.46083955276844274,-0.9460743892940172,null,-0.06083864586342279,0.26568818062818117,null,0.6487473861977073,0.45604290006075976,null,0.6487473861977073,0.890145208878703,null,0.6487473861977073,0.6497403923440755,null,0.6487473861977073,0.1956428369615909,null,-0.7135256658318695,-0.9460743892940172,null,-0.45887811984869514,-0.5568146874414868,null,-0.45887811984869514,-0.8885340085748538,null,-0.45887811984869514,-0.3568940731424135,null,-0.45887811984869514,-0.7062299888031088,null,0.45604290006075976,0.1956428369615909,null,0.45604290006075976,0.6497403923440755,null,0.45604290006075976,0.890145208878703,null,-0.3568940731424135,-0.7062299888031088,null,-0.3568940731424135,-0.5568146874414868,null,-0.3568940731424135,-0.8885340085748538,null,0.6497403923440755,0.890145208878703,null,0.6497403923440755,0.1956428369615909,null,-0.7062299888031088,-0.5568146874414868,null,-0.7062299888031088,-0.8885340085748538,null,0.890145208878703,0.1956428369615909,null,-0.8885340085748538,-0.5568146874414868,null],"type":"scatter"},{"hoverinfo":"text","marker":{"color":"rgba(0,0,0,0)","size":20},"mode":"markers","text":["SF vs CIN: 6 games","SF vs HOU: 3 games","SF vs SEA: 3 games","SF vs NYY: 3 games","SF vs PHI: 7 games","SF vs LAA: 3 games","SF vs MIL: 7 games","SF vs TEX: 3 games","SF vs SD: 13 games","SF vs COL: 13 games","SF vs CHC: 6 games","SF vs MIN: 3 games","SF vs ARI: 13 games","SF vs ATH: 6 games","SF vs KC: 3 games","SF vs WSH: 6 games","SF vs DET: 3 games","SF vs MIA: 6 games","SF vs ATL: 6 games","SF vs LAD: 13 games","SF vs CLE: 3 games","SF vs BOS: 3 games","SF vs CWS: 3 games","SF vs TOR: 3 games","SF vs NYM: 6 games","SF vs PIT: 6 games","SF vs TB: 3 games","SF vs BAL: 3 games","SF vs STL: 6 games","SEA vs ATH: 13 games","SEA vs DET: 6 games","SEA vs HOU: 13 games","SEA vs TEX: 13 games","SEA vs CIN: 3 games","SEA vs TOR: 6 games","SEA vs BOS: 6 games","SEA vs MIA: 3 games","SEA vs LAA: 13 games","SEA vs NYY: 6 games","SEA vs SD: 6 games","SEA vs CWS: 6 games","SEA vs WSH: 3 games","SEA vs MIN: 7 games","SEA vs BAL: 6 games","SEA vs ARI: 3 games","SEA vs CLE: 6 games","SEA vs CHC: 3 games","SEA vs KC: 7 games","SEA vs PIT: 3 games","SEA vs MIL: 3 games","SEA vs TB: 6 games","SEA vs NYM: 3 games","SEA vs PHI: 3 games","SEA vs ATL: 3 games","SEA vs STL: 3 games","SEA vs COL: 3 games","SEA vs LAD: 3 games","ATH vs CHC: 3 games","ATH vs COL: 3 games","ATH vs SD: 3 games","ATH vs NYM: 3 games","ATH vs CWS: 6 games","ATH vs MIL: 3 games","ATH vs TEX: 13 games","ATH vs MIA: 3 games","ATH vs NYY: 6 games","ATH vs LAD: 3 games","ATH vs LAA: 13 games","ATH vs PHI: 3 games","ATH vs HOU: 13 games","ATH vs TOR: 7 games","ATH vs MIN: 7 games","ATH vs BAL: 6 games","ATH vs KC: 6 games","ATH vs CLE: 6 games","ATH vs DET: 6 games","ATH vs TB: 6 games","ATH vs ATL: 3 games","ATH vs ARI: 3 games","ATH vs WSH: 3 games","ATH vs STL: 3 games","ATH vs BOS: 6 games","ATH vs CIN: 3 games","ATH vs PIT: 3 games","LAD vs CHC: 7 games","LAD vs DET: 3 games","LAD vs ATL: 6 games","LAD vs PHI: 6 games","LAD vs WSH: 6 games","LAD vs COL: 13 games","LAD vs TEX: 3 games","LAD vs PIT: 6 games","LAD vs MIA: 6 games","LAD vs ARI: 13 games","LAD vs LAA: 6 games","LAD vs NYM: 7 games","LAD vs CLE: 3 games","LAD vs NYY: 3 games","LAD vs STL: 6 games","LAD vs SD: 13 games","LAD vs KC: 3 games","LAD vs CWS: 3 games","LAD vs HOU: 3 games","LAD vs MIL: 6 games","LAD vs MIN: 3 games","LAD vs BOS: 3 games","LAD vs CIN: 6 games","LAD vs TB: 3 games","LAD vs TOR: 3 games","LAD vs BAL: 3 games","LAA vs CWS: 6 games","LAA vs STL: 3 games","LAA vs CLE: 6 games","LAA vs TB: 6 games","LAA vs HOU: 13 games","LAA vs TEX: 13 games","LAA vs PIT: 3 games","LAA vs MIN: 6 games","LAA vs DET: 7 games","LAA vs TOR: 6 games","LAA vs BAL: 6 games","LAA vs SD: 3 games","LAA vs MIA: 3 games","LAA vs NYY: 7 games","LAA vs BOS: 6 games","LAA vs WSH: 3 games","LAA vs ATL: 3 games","LAA vs ARI: 3 games","LAA vs PHI: 3 games","LAA vs NYM: 3 games","LAA vs CIN: 3 games","LAA vs CHC: 3 games","LAA vs KC: 6 games","LAA vs MIL: 3 games","LAA vs COL: 3 games","SD vs ATL: 7 games","SD vs CLE: 3 games","SD vs CHC: 6 games","SD vs COL: 13 games","SD vs HOU: 3 games","SD vs DET: 3 games","SD vs TB: 3 games","SD vs PIT: 6 games","SD vs NYY: 3 games","SD vs TOR: 3 games","SD vs MIA: 6 games","SD vs MIL: 6 games","SD vs ARI: 13 games","SD vs KC: 3 games","SD vs WSH: 6 games","SD vs CIN: 6 games","SD vs PHI: 6 games","SD vs TEX: 3 games","SD vs STL: 7 games","SD vs NYM: 6 games","SD vs BOS: 3 games","SD vs MIN: 3 games","SD vs BAL: 3 games","SD vs CWS: 3 games","ARI vs CHC: 7 games","ARI vs NYY: 3 games","ARI vs WSH: 6 games","ARI vs BAL: 3 games","ARI vs MIL: 7 games","ARI vs MIA: 6 games","ARI vs TB: 3 games","ARI vs ATL: 6 games","ARI vs NYM: 6 games","ARI vs PHI: 6 games","ARI vs COL: 13 games","ARI vs STL: 6 games","ARI vs PIT: 6 games","ARI vs CIN: 6 games","ARI vs TOR: 3 games","ARI vs CWS: 3 games","ARI vs KC: 3 games","ARI vs HOU: 3 games","ARI vs DET: 3 games","ARI vs TEX: 6 games","ARI vs CLE: 3 games","ARI vs BOS: 3 games","ARI vs MIN: 3 games","COL vs TB: 3 games","COL vs PHI: 7 games","COL vs MIL: 6 games","COL vs WSH: 7 games","COL vs KC: 3 games","COL vs CIN: 6 games","COL vs ATL: 6 games","COL vs DET: 3 games","COL vs TEX: 3 games","COL vs NYY: 3 games","COL vs CHC: 6 games","COL vs NYM: 6 games","COL vs MIA: 6 games","COL vs HOU: 6 games","COL vs CWS: 3 games","COL vs BOS: 3 games","COL vs MIN: 3 games","COL vs STL: 6 games","COL vs BAL: 3 games","COL vs CLE: 3 games","COL vs PIT: 6 games","COL vs TOR: 3 games","TEX vs BOS: 7 games","TEX vs CIN: 3 games","TEX vs TB: 6 games","TEX vs CHC: 3 games","TEX vs DET: 6 games","TEX vs HOU: 13 games","TEX vs NYY: 6 games","TEX vs CWS: 6 games","TEX vs TOR: 6 games","TEX vs STL: 3 games","TEX vs WSH: 3 games","TEX vs MIN: 6 games","TEX vs KC: 7 games","TEX vs PIT: 3 games","TEX vs BAL: 6 games","TEX vs ATL: 3 games","TEX vs PHI: 3 games","TEX vs CLE: 6 games","TEX vs MIL: 3 games","TEX vs NYM: 3 games","TEX vs MIA: 3 games","HOU vs NYM: 3 games","HOU vs MIN: 6 games","HOU vs STL: 3 games","HOU vs TOR: 6 games","HOU vs KC: 6 games","HOU vs DET: 6 games","HOU vs CWS: 6 games","HOU vs MIL: 3 games","HOU vs CIN: 3 games","HOU vs TB: 7 games","HOU vs PIT: 3 games","HOU vs CLE: 6 games","HOU vs PHI: 3 games","HOU vs CHC: 3 games","HOU vs WSH: 3 games","HOU vs BOS: 6 games","HOU vs MIA: 3 games","HOU vs NYY: 6 games","HOU vs BAL: 7 games","HOU vs ATL: 3 games","KC vs CLE: 13 games","KC vs MIL: 3 games","KC vs BAL: 6 games","KC vs MIN: 13 games","KC vs NYY: 6 games","KC vs DET: 13 games","KC vs TB: 6 games","KC vs CWS: 13 games","KC vs BOS: 6 games","KC vs STL: 6 games","KC vs CIN: 3 games","KC vs PIT: 3 games","KC vs NYM: 3 games","KC vs MIA: 3 games","KC vs CHC: 3 games","KC vs ATL: 3 games","KC vs TOR: 6 games","KC vs WSH: 3 games","KC vs PHI: 3 games","MIN vs STL: 3 games","MIN vs CWS: 13 games","MIN vs DET: 13 games","MIN vs NYM: 3 games","MIN vs ATL: 3 games","MIN vs CLE: 13 games","MIN vs BOS: 6 games","MIN vs BAL: 6 games","MIN vs MIL: 6 games","MIN vs TB: 6 games","MIN vs TOR: 6 games","MIN vs CIN: 3 games","MIN vs MIA: 3 games","MIN vs CHC: 3 games","MIN vs PIT: 3 games","MIN vs WSH: 3 games","MIN vs NYY: 6 games","MIN vs PHI: 3 games","STL vs BOS: 3 games","STL vs PIT: 13 games","STL vs PHI: 6 games","STL vs NYM: 7 games","STL vs ATL: 6 games","STL vs MIL: 13 games","STL vs CIN: 13 games","STL vs WSH: 6 games","STL vs DET: 3 games","STL vs BAL: 3 games","STL vs TOR: 3 games","STL vs CWS: 3 games","STL vs CHC: 13 games","STL vs CLE: 3 games","STL vs MIA: 6 games","STL vs NYY: 3 games","STL vs TB: 3 games","MIL vs NYY: 3 games","MIL vs CIN: 13 games","MIL vs DET: 3 games","MIL vs CWS: 3 games","MIL vs CHC: 13 games","MIL vs TB: 3 games","MIL vs CLE: 3 games","MIL vs BAL: 3 games","MIL vs PIT: 13 games","MIL vs BOS: 3 games","MIL vs PHI: 6 games","MIL vs ATL: 6 games","MIL vs NYM: 6 games","MIL vs MIA: 6 games","MIL vs WSH: 6 games","MIL vs TOR: 3 games","CHC vs PHI: 6 games","CHC vs PIT: 13 games","CHC vs NYM: 6 games","CHC vs MIA: 6 games","CHC vs CWS: 6 games","CHC vs CIN: 13 games","CHC vs WSH: 6 games","CHC vs DET: 3 games","CHC vs CLE: 3 games","CHC vs NYY: 3 games","CHC vs BOS: 3 games","CHC vs BAL: 3 games","CHC vs TOR: 3 games","CHC vs ATL: 6 games","CHC vs TB: 3 games","CWS vs DET: 13 games","CWS vs CLE: 13 games","CWS vs BOS: 7 games","CWS vs MIA: 3 games","CWS vs CIN: 3 games","CWS vs NYM: 3 games","CWS vs BAL: 6 games","CWS vs TOR: 6 games","CWS vs PIT: 3 games","CWS vs TB: 6 games","CWS vs PHI: 3 games","CWS vs ATL: 3 games","CWS vs NYY: 7 games","CWS vs WSH: 3 games","CIN vs PIT: 13 games","CIN vs BAL: 3 games","CIN vs MIA: 7 games","CIN vs WSH: 6 games","CIN vs ATL: 7 games","CIN vs CLE: 6 games","CIN vs DET: 3 games","CIN vs NYY: 3 games","CIN vs BOS: 3 games","CIN vs PHI: 6 games","CIN vs NYM: 6 games","CIN vs TB: 3 games","CIN vs TOR: 3 games","ATL vs MIA: 13 games","ATL vs PHI: 13 games","ATL vs TB: 3 games","ATL vs TOR: 3 games","ATL vs PIT: 6 games","ATL vs WSH: 13 games","ATL vs BOS: 6 games","ATL vs NYM: 13 games","ATL vs BAL: 3 games","ATL vs NYY: 3 games","ATL vs CLE: 3 games","ATL vs DET: 3 games","DET vs NYY: 6 games","DET vs BAL: 6 games","DET vs BOS: 6 games","DET vs TOR: 7 games","DET vs CLE: 13 games","DET vs PIT: 6 games","DET vs TB: 6 games","DET vs WSH: 3 games","DET vs PHI: 3 games","DET vs NYM: 3 games","DET vs MIA: 3 games","TB vs PIT: 3 games","TB vs BOS: 13 games","TB vs NYY: 13 games","TB vs PHI: 3 games","TB vs TOR: 13 games","TB vs MIA: 6 games","TB vs NYM: 3 games","TB vs BAL: 13 games","TB vs CLE: 7 games","TB vs WSH: 3 games","CLE vs BAL: 7 games","CLE vs PIT: 3 games","CLE vs NYY: 6 games","CLE vs BOS: 6 games","CLE vs TOR: 6 games","CLE vs WSH: 3 games","CLE vs PHI: 3 games","CLE vs NYM: 3 games","CLE vs MIA: 3 games","MIA vs PIT: 7 games","MIA vs NYM: 13 games","MIA vs WSH: 13 games","MIA vs PHI: 13 games","MIA vs BAL: 3 games","MIA vs NYY: 3 games","MIA vs BOS: 3 games","MIA vs TOR: 3 games","PIT vs NYY: 3 games","PIT vs WSH: 7 games","PIT vs NYM: 6 games","PIT vs PHI: 6 games","PIT vs TOR: 3 games","PIT vs BOS: 3 games","PIT vs BAL: 3 games","TOR vs BAL: 13 games","TOR vs WSH: 3 games","TOR vs NYM: 3 games","TOR vs BOS: 13 games","TOR vs NYY: 13 games","TOR vs PHI: 6 games","WSH vs PHI: 13 games","WSH vs BAL: 6 games","WSH vs NYM: 13 games","WSH vs BOS: 3 games","WSH vs NYY: 3 games","BAL vs BOS: 13 games","BAL vs NYY: 13 games","BAL vs NYM: 3 games","BAL vs PHI: 3 games","PHI vs NYM: 13 games","PHI vs BOS: 3 games","PHI vs NYY: 3 games","NYY vs NYM: 6 games","NYY vs BOS: 13 games","NYM vs BOS: 3 games"],"x":[-0.5042127427401193,0.37132925970112485,0.1985592521364888,0.21277881974452745,0.12181350239152189,0.4487432028136866,-0.274482314469733,0.07620518157206266,-0.4133390700266968,-0.19974853377389712,-0.4265712878400709,0.031180745477442977,-0.33748234951243405,0.31237614303984035,-0.2605122434013865,0.2092152471128664,-0.03542960568528284,0.06114529011523683,-0.0640135393538609,-0.22684115867708188,-0.1568905364954691,0.12630978885772817,-0.1237435118652343,0.44811027700272804,-0.09062217506955164,-0.49937695618968186,0.28050687753543235,0.3675070038971815,-0.3485917790602442,0.5606551960879631,0.21284944736284,0.6196083127492477,0.3244842346201855,-0.2559336896919964,0.6963893300508508,0.374588841905851,0.30942434316335965,0.6970222558618094,0.4610578727926503,-0.16506001697857398,0.12453554118288854,0.45749430016098924,0.2794597985255658,0.6157860569453043,-0.08920329646431124,0.09138851655265373,-0.1782922347919481,-0.012233190353263701,-0.25109790314155905,-0.02620326142161014,0.5287859305835552,0.1576568779785712,0.3700925554396447,0.18426551369426192,-0.10031272601212138,0.04853051927422572,0.02143789437104096,-0.0644753438885966,0.16234741017757723,-0.05124312607522247,0.2714737688819227,0.23835243208624005,0.08761362948174137,0.438301125523537,0.42324123406671116,0.5748747636960018,0.13525478527439247,0.810839146765161,0.48390944634299626,0.7334252036525992,0.8102062209542024,0.3932766894289173,0.7296029478486559,0.10158370055008781,0.20520540745600524,0.3266663382661915,0.6426028214869066,0.2980824045976134,0.024613594439040265,0.5713111910643407,0.01350416489123013,0.4884057328092025,-0.14211679878864492,-0.13728101223820754,-0.6036926456055188,-0.2125509634507307,-0.24113489711930874,-0.05530785537392596,0.03209388934741855,-0.37686989153934497,-0.10091617619338521,-0.6764983139551297,-0.11597606765021103,-0.514603707277882,0.2716218450482387,-0.2677435328349995,-0.33401189426091693,0.0356574619790796,-0.5257131368256921,-0.5904604277921447,-0.43763360116683436,-0.30086486963068215,0.19420790193567697,-0.45160367223518083,-0.14594061228800487,-0.05081156890771968,-0.6813341005055671,0.10338551976998447,0.2709889192372802,0.19038564613173362,0.37471949186008635,0.1498712246650764,0.3415724672298515,0.778969881260753,0.8697922634264454,0.5746681852973833,-0.0009139524643612673,0.5296437492027636,0.4630333980400378,0.9465732807280487,0.8659700076225021,0.08512393369862381,0.5596082938405574,0.7112418234698481,0.6247727925830489,0.707678250838187,0.4344494643714597,0.16098065421288654,0.6202765061168425,0.407840828655769,-0.005749739014798638,0.07189171588524967,0.23795076032393409,0.22398068925558764,0.2987144699514235,-0.4276328084689237,-0.520509805610532,-0.7901905569551337,-0.5633678028889599,0.007709990586062032,-0.3990488748003456,-0.08311239157963046,-0.8629962253047447,-0.15084044937053534,0.08449100788766523,-0.302473978999826,-0.6381015835847957,-0.7011016186274969,-0.6241315125164493,-0.15440402200219638,-0.8678320118551821,-0.2418057667235409,-0.28741408754300013,-0.712211048175307,-0.45424144418461443,-0.23730948025733462,-0.33243852363761983,0.003887734782118679,-0.48736278098029706,-0.714333836440871,-0.07498372885627261,-0.07854730148793365,0.07974445529638141,-0.562244863070533,-0.22661725848556324,-0.00725567106536773,-0.351776087954661,-0.3783847236703517,-0.16594904620927817,-0.4875110823746972,-0.6363543276610443,-0.7871395047904819,-0.7919752913409193,0.16034772840192796,-0.41150606046603433,-0.5482747920021867,0.08356671110032476,-0.3231921542860829,-0.2115573670287374,-0.44465308509626916,-0.16145275974307188,-0.2565818031233571,0.13047814467316923,-0.028215230470741204,-0.42451104733199607,0.05918651425060331,-0.4105409762636496,-0.6542414756023823,-0.21404227221612399,-0.18545833854754595,-0.07382355129020045,0.06275008688226436,-0.5766000207023341,-0.24065090793181476,-0.08888344274702627,0.22130052683886173,-0.2737722447274974,-0.02371894400453492,-0.11884798738482012,-0.49862051192250734,0.21747827103491837,-0.30691926935773217,-0.649405689051945,0.29808154414046495,0.25223477134142486,-0.3782877602564226,0.406431860019129,-0.30064630535637427,0.09049537679841382,0.4972542421848215,0.3387038022282241,0.0021814706184623694,0.5740352594864246,-0.22266679657654753,0.3351402295965631,0.15710572796113964,-0.13458726091768985,-0.3734519737059852,0.49343198638087815,0.061911443129835764,0.24773848487521855,-0.030965554011772436,-0.14855733198603632,0.035302807414145015,0.1870702725989335,0.3304268855432072,0.4522298060902018,0.07245728155251463,0.8691593376154869,0.1605368172113723,0.385619454927476,0.2973055487475246,0.14656674614302587,-0.08316368212736042,0.7015559381481912,-0.07832789557692305,0.26415852411728974,0.5428625630042807,-0.005522227227312104,0.6302643077256253,0.5473588494704871,0.48219435072799566,0.6338278803572863,0.7885560645099403,0.3570355212588979,-0.3676829789852216,-0.4852747569594855,0.15671456140742895,-0.17961169701230956,0.0019863772547749348,-0.24622204817503535,0.06971443504567981,-0.33453595435498684,-0.08448265363202434,-0.5593842215499967,-0.7150051852298718,-0.7101693986794344,-0.30141461755930415,-0.1496471523745157,-0.6373637303298234,-0.27480598184361343,0.2373178345129755,-0.0015771953768861091,-0.08897894009823062,-0.26769123267116723,-0.042842965476157305,0.04547094070379415,-0.009721628680474659,0.01688700703521609,-0.07598999010639211,0.20721033524680516,0.44840755028625845,-0.19358176808065597,0.3614074239245093,0.529010823391805,-0.4233121963510423,0.14204583650431382,-0.34567074145099397,-0.4184764098006049,0.2901157935019434,0.29367936613360446,0.2027140487805989,-0.17256218929088202,-0.7982489343382921,-0.1770584757570883,-0.38949415321816183,-0.3628855175024711,-0.5733542926183431,-0.8030847208887295,-0.08965673103574379,-0.334301583833893,0.06863502574857128,0.14923829885411782,-0.42261549001384446,-0.7254432659886811,-0.4557625146440793,-0.23772668803337338,-0.08609315840408274,-0.018365100613177865,-0.011983693813571505,-0.7289752562982182,-0.2601921192433818,-0.34850602542333325,-0.6513338013981699,0.05574436397733337,-0.3816530500535681,0.1427444903390825,-0.7241394697477809,-0.09845272470037078,-0.10294901116657706,-0.28877605291195985,-0.3153846886276506,-0.16361722344286211,-0.01554726644523255,0.22334776344462906,-0.25503798453691506,-0.8762284431181189,-0.46747366199798857,-0.3157061968132001,-0.5005949987936712,-0.8810642296685562,-0.16763623981557052,-0.41228109261371976,-0.5337420234239061,-0.16407266718390948,-0.25054169807070875,-0.009344483031255457,0.07125879007429109,-0.44086502628229784,-0.0963446093930046,-0.10945331663888312,-0.23091424744906938,0.0522860779041279,-0.01287842083836345,-0.5782364536937196,-0.16464588602315194,0.2934832929435812,0.3740865660491277,-0.5734006671432822,0.20648316658183205,0.047789791437921614,-0.13803725030746117,0.13875510879092717,0.13519153615926613,-0.9538698980181671,-0.08698593793130377,-0.3933476517132484,-0.24527769471561883,-0.5185064811823461,-0.6113834783239543,-0.48992254751376807,-0.2417141220839578,-0.32818315297075706,-0.3326794394369633,-0.5451151168980369,-0.1739860642930529,-0.006382664825757223,0.046851551673009945,0.10751976394929501,0.26621313909320543,0.4338165385605011,-0.5136706946319087,0.1949215086706395,0.11201605041550129,-0.10491591351177854,0.3532132654549546,0.19848508130230058,-0.171184274937696,-0.04972334412750973,0.2270690149708786,0.38179719912353266,0.14059998408407937,0.4624004722290792,-0.14260034126911791,-0.4850867609633307,0.2947970727617835,0.2235054423392176,0.13610369761787305,-0.07633197984320048,0.075435485341588,-0.16915027774261554,0.4565364673047945,0.5430054981915938,0.4520401808385882,0.7783369554497943,0.39137196856230316,0.2396045033775147,0.6977336823442478,0.17333614195159724,0.5394419255599328,0.2603362683133464,-0.606547691773517,0.10560808416069237,0.019139053273893092,0.34093954141889293,0.10204451152903132,0.014642766807686808,-0.19779291065338672,-0.046025445468598256,-0.38851186516281105,0.020242915957319196,0.32008033813973724,0.23267859341839275,0.4783720949240523,0.3236439107713983,0.237174879884599,0.5589753680295989,-0.23687833553352042,-0.24044190816518146,-0.5402793303475996,-0.32784365288652595,-0.0015468782753198518,-0.3233473664203197,-0.0821501513808664,0.8653370818115436,0.7070453250272284,0.4072079028448104,0.6241398667720902,0.7106088976588895,0.619643580305884,0.3807485504160223,0.6264420519216819,0.1683128729549488,0.3852448368822286,0.4717138677690279,0.5435365936665437,0.630005624553343,0.32660462973926385,0.5390403072003374,0.08091112823360426,0.2978430921608841,0.38431212304768336,0.1718764455866098,0.3888084095138896,0.08540741469981054],"y":[0.46108462881165607,0.6539332879580612,0.5528325491086531,0.04723694745594059,0.936576556182719,0.5089609324054784,0.4259608297400627,0.4111538921146388,0.7770466677586139,0.966264312332442,0.3331819958737243,-0.008496048256632527,0.8978074039119923,0.44297776817256407,0.14249417862128083,0.8163741479154052,0.13474111882743273,0.7195254017737474,0.8158776448422211,0.7369082489738066,0.018466757096358866,0.2130966080226241,0.2610841753591461,0.3130569151721607,0.589325370224163,0.6243480420574581,0.26206489181901993,0.13838895734181306,0.5698364671977425,0.012802413794482208,-0.2954342355506491,0.22375793357997928,-0.019021462263443027,0.030909274433574205,-0.11711843920592116,-0.2170787463554578,0.2893500473956655,0.07878557802739644,-0.38293840692214126,0.34687131338053206,-0.16909117901893578,0.3861987935373234,-0.4386714026347144,-0.2917863970362688,0.4676320495339105,-0.411708597281723,-0.09699335850435753,-0.287681175756801,0.19417268767937618,-0.0042145246380191695,-0.16811046255906198,0.15915001584608104,0.5064012018046371,0.3857022904641393,0.13966111281966062,0.5360889579543602,0.30673289459572467,-0.2068481394404465,0.42623417701827115,0.23701653244444304,0.04929523490999206,-0.27894595995502475,-0.11406930557410816,-0.128876243199532,0.17949526645957647,-0.4927931878582303,0.19687811365963565,-0.031069202908692552,0.3965464208685481,0.1139031526438903,-0.22697322014201016,-0.5485261835708034,-0.4016411779723578,-0.39753595669289005,-0.521563378217812,-0.40528901648673815,-0.27796524349515095,0.27584750952805026,0.3577772685978215,0.27634401260123437,0.029806331883571624,-0.3269335272915468,-0.07894550650251478,0.0843179067432872,0.08708234136079593,-0.1113585356854957,0.5697779903292928,0.6904769016697905,0.5702744934024768,0.7201646578195136,0.16505423760171042,0.3782483875445296,0.47342574726081893,0.651707749399064,0.26286127789254987,0.3432257157112345,-0.22763289741656956,-0.19886270705698783,0.3237368126848141,0.5309470132456855,-0.10360547589164759,0.01498452084621768,0.40783363344513274,0.1798611752271343,-0.25459570276956095,-0.03300304649030433,0.21498497429872765,0.01596523730609148,0.0669572606592323,-0.10771069717111537,-0.21296279572211052,0.09578949611648585,-0.4555802139848978,-0.21198207926223672,0.17988631687680454,-0.06289307896661779,0.15030107097620143,-0.4825430193378892,-0.3393058522538239,-0.1609900559090959,-0.3356580137394436,0.30299969667735727,0.24547843069249073,-0.42681002362531606,-0.26095036305863256,0.3423271768341486,0.3418306737609645,0.4237604328307357,0.4625295851014623,0.11527839914290629,-0.012962342269600555,-0.14086497520753227,-0.3315527924599758,-0.04808614134119393,0.4922173412511854,0.6099164091141,-0.18749447863176216,0.12722076014560332,0.7603030766043211,0.44797205222994013,-0.0712201169006883,0.056103656090898874,0.418386806329337,-0.15872428827218044,0.1070956794440397,0.5135641660456263,0.2199995940119417,0.6918461681838713,-0.0634670571068402,0.6104129121872842,0.25512339308353504,0.730615320454598,0.20519265638651782,0.3638752314696215,0.3833641344960419,0.007135372294503062,-0.21445728398475356,-0.06757227838630797,0.055122939631025075,0.24798149629898178,-0.03796355211880198,0.7311736483406627,0.053188457767070485,0.34076033016532015,0.6343249021990047,0.17686439224427733,0.7306771452674785,0.5041248706494204,0.8513760566079764,0.8810638127576995,0.48463596762299993,0.5391475424827155,0.3758841292369135,0.22785641559741815,0.17588367578440353,0.05729367904653826,0.5687327883833186,0.049540619252690155,0.3259533925398963,-0.0667337424783837,0.12789610844788152,-0.0936965478313751,0.245321300664727,0.919832965028426,0.4092172385857698,0.7996305567611124,0.12575058746698792,0.44434103765736316,0.7991340536879282,0.11799752767313981,0.3944103009603459,0.03049335630164768,0.3164384047194314,0.57258177906987,0.7027818106194544,0.6371896968037682,0.2443405842048532,0.19635301686833118,-0.02523963941092544,0.5530928760434496,0.12164536618752014,0.0017231659420659518,0.6076044509031652,0.2963133240178678,-0.35875740334947204,-0.11076938256044003,-0.3097891195530762,-0.23867201549837175,-0.43711289254466335,0.08207927658596506,-0.5246170639161555,-0.31076983601295,-0.2587970961999354,-0.002017544174353611,0.24452013654330915,-0.5803500596287287,-0.42935983275081524,0.05249403068536196,-0.433465054030283,0.24402363347012504,0.36472254481062283,-0.5533872542757372,-0.1458931816320334,0.017471358852066826,0.14767139040165125,0.26025075469548914,-0.3375706637853063,0.24076185166906872,-0.016017700356513065,-0.18658043690739295,-0.19433349670124106,-0.06799044016952768,0.09688621421138892,0.13201001328298229,-0.06700972370965388,0.2952734265287843,-0.3106078584323149,0.6075019406540452,0.004107380345050565,0.48729953238673146,-0.1159780075060497,0.39045078624507357,-0.2818376680727332,-0.19068565818686073,0.48680302931354735,-0.8220469677690952,-0.4145528951253914,-0.7021247675236411,-0.8490097731220867,-0.7932767774095135,-0.7057726060380214,-0.5784488330464342,-0.579429549506308,-0.62741711684283,-0.2706772576677116,-0.37942909605379804,-0.21616568280799606,-0.2511883546412912,-0.12098832309170676,-0.5073317289917297,-0.024636080023232976,-0.5274568096932934,-0.02413957695004887,0.09606283131726484,-0.42166748454562497,-0.7304197763842214,-0.8567628329159347,-0.40217858151920455,-0.17562630690114633,-0.9730371946470087,-0.7784073437207434,-0.8531149944015544,-0.5655431220033048,-0.7294390599243475,-0.6784470365712068,-0.5304193229317113,-0.2719785499696201,-0.6583219558696431,-0.3671559096859094,-0.17512980382796223,-0.9442670042874268,-0.05492739556064852,-0.20007482826636835,0.2111766057684656,0.5234051198937265,0.17615393393517048,0.4027062085532287,0.012789393451070247,0.04791319252266362,0.4032027116264128,-0.2784303174615597,-0.2747824789471794,-0.10011452111683174,-0.15208726092984637,-0.0799894404152681,-0.3947046791926336,0.3063539654847549,-0.36593448883305185,-0.15110654446997257,-0.5098101262907316,-0.09596244493501616,-0.4223059549192395,-0.29596289838752615,-0.2238650778729479,-0.29498218192765235,-0.5385803166503134,-0.41865811640485917,0.06730096831078582,-0.34395046572404814,0.37952948243604673,0.2588305710955489,0.032278296477490684,0.16247832802707513,0.259327074168733,-0.2439901585745115,0.28675064856970833,-0.025477865555552537,-0.06050053738884767,0.06969949416073676,-0.3887417322538645,-0.18874127880135452,0.16654824030239465,-0.5150847887855778,-0.6313591505166517,-0.60258896015707,-0.43672929959038653,-0.5114369502711975,-0.3367689924408499,0.16605173722921054,-0.3877610157939907,-0.5871826093001561,-0.70345697103123,-0.5088271201049648,-0.00239832635384149,-0.26083909931593274,-0.13259835790342592,-0.5835347707857758,-0.40886681295542815,-0.09757568607013078,-0.45985883630856894,0.2146528280551301,0.0939539167146323,-0.6746867806716482,0.0944504197878164,0.10242476738237918,-0.3835343173332658,0.19760212709866848,0.29445087324032637,0.29395437016714226,-0.50345651757872,-0.38718215584764615,-0.4746863272191383,-0.3088266666524548,0.4146532815076401,0.06740209554908405,-0.25985838285605894,-0.20886635950291815,0.5523951431292335,0.7694462975382051,0.0949346331745061,0.14592665652764691,0.4572177834129443,0.6492438892708914,0.04596634937811028,0.4221951115796491,-0.02874130130270075,-0.11989331118857322,-0.14866350154815494,-0.03238913981708108,-0.8010298372033616,-0.7098778273174892,-0.6351701766366782,-0.5352098694871414,-0.8298000275629434,-0.22391874260184416,-0.5862018928402823,-0.031892636743896974,0.08830977152341674,-0.2589414144351393,-0.12874138288555487,-0.09659496961025699,-0.5078464036450909,-0.6737060642117745,0.2156335445150039,-0.4078860964955543,-0.0014176098939676918,-0.13161764144355212,-0.582554054325902,-0.7024762545713562,0.0954311362476902,-0.826152189048563,-0.34019310433291805,-0.9173041989344355,-0.7514445383677519,-0.6514842312182154,-0.14816699847497083,-0.027964590207657125,-0.37521577616621316,-0.24501574461662873,0.3608655403444705,0.32584286851117533,0.5528916462024176,0.6730940544697314,-0.12509354437117454,-0.216245554257047,-0.050385893690363504,0.04957441345917313,-0.3114229139733363,0.45771428648612833,0.23066550879488604,0.5779166947534421,-0.04560294625711617,-0.1455632534066528,-0.22027090408746383,-0.5315620309727611,0.14642315960083102,-0.0806256180904113,-0.45685438029195014,-0.6227140408586336,0.26662556786814473,0.7699428006113893,-0.028244798229516643,0.4226916146528332,0.04646285245129439,-0.11939680811538911,-0.6315223381222979,-0.7973819986889813,-0.25529357592075896,0.09195761003779707,0.5428940229201469,0.1666652607186081,0.0008056001519246014,-0.34644558580663143,-0.7226743480081703,-0.18058592523994793],"type":"scatter"},{"hoverinfo":"none","marker":{"cmax":1,"cmin":0,"color":[0.5],"colorbar":{"outlinewidth":0,"thickness":15,"ticktext":["3","6","7","13"],"tickvals":[0.125,0.375,0.625,0.875],"title":{"text":"Games Played"},"xanchor":"left"},"colorscale":[[0.0,"rgb(247,251,255)"],[0.25,"rgb(247,251,255)"],[0.25,"rgb(198,219,239)"],[0.5,"rgb(198,219,239)"],[0.5,"rgb(66,146,198)"],[0.75,"rgb(66,146,198)"],[0.75,"rgb(8,48,107)"],[1.0,"rgb(8,48,107)"]],"showscale":true},"mode":"markers","x":[null],"y":[null],"type":"scatter"},{"hoverinfo":"text","hovertext":["Team: SF","Team: SEA","Team: ATH","Team: LAD","Team: LAA","Team: SD","Team: ARI","Team: COL","Team: TEX","Team: HOU","Team: KC","Team: MIN","Team: STL","Team: MIL","Team: CHC","Team: CWS","Team: CIN","Team: ATL","Team: DET","Team: TB","Team: CLE","Team: MIA","Team: PIT","Team: TOR","Team: WSH","Team: BAL","Team: PHI","Team: NYY","Team: NYM","Team: BOS"],"marker":{"color":"rgba(255, 255, 255, 1)","size":35},"mode":"markers","x":[-0.04971980091163401,0.44683830518461165,0.6744720869913147,-0.40396251644252973,0.9472062065390072,-0.7769583391417596,-0.6252448981132341,-0.3497772666361602,0.20213016405575931,0.7923783203138837,-0.47130468589113905,0.11208129186651997,-0.6474637572088544,-0.49924482802783193,-0.8034227747685079,-0.19776722281883458,-0.9587056845686045,-0.07830727779608779,-0.021139410458931668,0.6107335559824987,-0.2640612720793042,0.17201038114210768,-0.9490341114677298,0.94594035491709,0.46815029513736683,0.784733808705997,0.2933468056946778,0.4752774404006889,-0.13152454922746928,0.30233937862709037],"y":[0.983007903486735,0.1226571947305712,-0.09705236714160678,0.4908085944608781,0.03491396132422168,0.5710854320304929,0.8126069043372498,0.9495207211781491,-0.16070011925745725,0.3248586724293874,-0.6980195462441733,-1.0,0.15666503090875003,-0.13108624400660954,-0.31664391173928624,-0.46083955276844274,-0.06083864586342279,0.6487473861977073,-0.7135256658318695,-0.45887811984869514,-0.9460743892940172,0.45604290006075976,0.26568818062818117,-0.3568940731424135,0.6497403923440755,-0.7062299888031088,0.890145208878703,-0.8885340085748538,0.1956428369615909,-0.5568146874414868],"type":"scatter"}],                        {"height":600,"hovermode":"closest","images":[{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002f5\u002f58\u002fSan_Francisco_Giants_Logo.svg","x":-0.04971980091163401,"xanchor":"center","xref":"x","y":0.983007903486735,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002f6\u002f6d\u002fSeattle_Mariners_logo_%28low_res%29.svg","x":0.44683830518461165,"xanchor":"center","xref":"x","y":0.1226571947305712,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fthumb\u002fb\u002fb8\u002fAthletics_logo.svg\u002f330px-Athletics_logo.svg.png","x":0.6744720869913147,"xanchor":"center","xref":"x","y":-0.09705236714160678,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f0\u002f0e\u002fLos_Angeles_Dodgers_Logo.svg","x":-0.40396251644252973,"xanchor":"center","xref":"x","y":0.4908085944608781,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f8\u002f8b\u002fLos_Angeles_Angels_of_Anaheim.svg","x":0.9472062065390072,"xanchor":"center","xref":"x","y":0.03491396132422168,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fthumb\u002fe\u002fe2\u002fSD_Logo_Brown.svg\u002f250px-SD_Logo_Brown.svg.png","x":-0.7769583391417596,"xanchor":"center","xref":"x","y":0.5710854320304929,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fthumb\u002fa\u002fac\u002fArizona_Diamondbacks_logo_teal.svg\u002f330px-Arizona_Diamondbacks_logo_teal.svg.png","x":-0.6252448981132341,"xanchor":"center","xref":"x","y":0.8126069043372498,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002fc\u002fc0\u002fColorado_Rockies_full_logo.svg","x":-0.3497772666361602,"xanchor":"center","xref":"x","y":0.9495207211781491,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fc\u002fc7\u002fTexas_Rangers_logo.svg","x":0.20213016405575931,"xanchor":"center","xref":"x","y":-0.16070011925745725,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f6\u002f6b\u002fHouston-Astros-Logo.svg","x":0.7923783203138837,"xanchor":"center","xref":"x","y":0.3248586724293874,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f7\u002f78\u002fKansas_City_Royals_Primary_Logo.svg","x":-0.47130468589113905,"xanchor":"center","xref":"x","y":-0.6980195462441733,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fthumb\u002f1\u002f17\u002fMinnesota_Twins_New_Logo.svg\u002f250px-Minnesota_Twins_New_Logo.svg.png","x":0.11208129186651997,"xanchor":"center","xref":"x","y":-1.0,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002f9\u002f9d\u002fSt._Louis_Cardinals_logo.svg","x":-0.6474637572088544,"xanchor":"center","xref":"x","y":0.15666503090875003,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002fb\u002fb8\u002fMilwaukee_Brewers_logo.svg","x":-0.49924482802783193,"xanchor":"center","xref":"x","y":-0.13108624400660954,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f8\u002f80\u002fChicago_Cubs_logo.svg","x":-0.8034227747685079,"xanchor":"center","xref":"x","y":-0.31664391173928624,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fc\u002fc1\u002fChicago_White_Sox.svg","x":-0.19776722281883458,"xanchor":"center","xref":"x","y":-0.46083955276844274,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f0\u002f01\u002fCincinnati_Reds_Logo.svg","x":-0.9587056845686045,"xanchor":"center","xref":"x","y":-0.06083864586342279,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002ff\u002ff2\u002fAtlanta_Braves.svg","x":-0.07830727779608779,"xanchor":"center","xref":"x","y":0.6487473861977073,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fe\u002fe3\u002fDetroit_Tigers_logo.svg","x":-0.021139410458931668,"xanchor":"center","xref":"x","y":-0.7135256658318695,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f5\u002f55\u002fTampa_Bay_Rays_Logo.svg","x":0.6107335559824987,"xanchor":"center","xref":"x","y":-0.45887811984869514,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002fa\u002fa9\u002fGuardians_winged_%22G%22.svg","x":-0.2640612720793042,"xanchor":"center","xref":"x","y":-0.9460743892940172,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002ff\u002ffd\u002fMarlins_team_logo.svg","x":0.17201038114210768,"xanchor":"center","xref":"x","y":0.45604290006075976,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f8\u002f81\u002fPittsburgh_Pirates_logo_2014.svg","x":-0.9490341114677298,"xanchor":"center","xref":"x","y":0.26568818062818117,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002fc\u002fcc\u002fToronto_Blue_Jay_Primary_Logo.svg","x":0.94594035491709,"xanchor":"center","xref":"x","y":-0.3568940731424135,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fa\u002fa3\u002fWashington_Nationals_logo.svg","x":0.46815029513736683,"xanchor":"center","xref":"x","y":0.6497403923440755,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fe\u002fe9\u002fBaltimore_Orioles_Script.svg","x":0.784733808705997,"xanchor":"center","xref":"x","y":-0.7062299888031088,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002ff\u002ff0\u002fPhiladelphia_Phillies_%282019%29_logo.svg","x":0.2933468056946778,"xanchor":"center","xref":"x","y":0.890145208878703,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002ff\u002ffe\u002fNew_York_Yankees_Primary_Logo.svg","x":0.4752774404006889,"xanchor":"center","xref":"x","y":-0.8885340085748538,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002fthumb\u002f7\u002f7b\u002fNew_York_Mets.svg\u002f250px-New_York_Mets.svg.png","x":-0.13152454922746928,"xanchor":"center","xref":"x","y":0.1956428369615909,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15247295128860894,"sizey":0.1586406322789388,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002f6\u002f6d\u002fRedSoxPrimary_HangingSocks.svg","x":0.30233937862709037,"xanchor":"center","xref":"x","y":-0.5568146874414868,"yanchor":"middle","yref":"y"}],"margin":{"b":20,"l":5,"r":5,"t":60},"showlegend":false,"title":{"text":"\u003cbr\u003eMLB 2025 Schedule Matchups"},"width":800,"xaxis":{"showgrid":false,"showticklabels":false,"zeroline":false},"yaxis":{"showgrid":false,"showticklabels":false,"zeroline":false},"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}}},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('1bdde03d-0e75-4616-96d8-bcaae199bb14');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
</div>
</section>
<section id="mlb-expansion-to-32-teams-as-a-graph" class="level3">
<h3 class="anchored" data-anchor-id="mlb-expansion-to-32-teams-as-a-graph">MLB Expansion to 32 Teams as a Graph</h3>
<p>Now let’s visualize the expanded league structure as a graph. In this hypothetical scenario, we have 32 teams divided into two leagues, each with four divisions. We introduce a Portland team to the American League. The National League receives a new team in Nashville. In summary, Table&nbsp;1 shows the new team alignments.</p>
<div id="tbl-mlb-expansion" 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-mlb-expansion-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: MLB Expansion to 32 Teams
</figcaption>
<div aria-describedby="tbl-mlb-expansion-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<table class="caption-top table">
<thead>
<tr class="header">
<th>League</th>
<th>Division</th>
<th>Teams</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>AL</td>
<td>East</td>
<td>BAL, BOS, NYY, WSH</td>
</tr>
<tr class="even">
<td>AL</td>
<td>Central</td>
<td>CWS, CLE, DET, TOR</td>
</tr>
<tr class="odd">
<td>AL</td>
<td>South</td>
<td>HOU, KC, COL, TEX</td>
</tr>
<tr class="even">
<td>AL</td>
<td>West</td>
<td>LAA, ATH, SEA, POR</td>
</tr>
<tr class="odd">
<td>NL</td>
<td>East</td>
<td>NYM, PHI, CIN, PIT</td>
</tr>
<tr class="even">
<td>NL</td>
<td>Central</td>
<td>CHC, MIL, STL, MIN</td>
</tr>
<tr class="odd">
<td>NL</td>
<td>South</td>
<td>MIA, TB, NSH, ATL</td>
</tr>
<tr class="even">
<td>NL</td>
<td>West</td>
<td>LAD, SD, SF, ARI</td>
</tr>
</tbody>
</table>
</div>
</figure>
</div>
<p>Of course, we will redo our artistic rendition under this new structure.</p>
<div id="cell-fig:mlb-graph-32" class="cell" data-execution_count="5">
<details class="code-fold">
<summary>Code</summary>
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Team Data ---</span></span>
<span id="cb5-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># A dictionary to map old abbreviations to modern ones</span></span>
<span id="cb5-3">team_name_map <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb5-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ANA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LAA'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ARI'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ARI'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ATL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ATL'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BAL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BAL'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BOS'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BOS'</span>,</span>
<span id="cb5-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CHA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CWS'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CHN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CHC'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CIN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CIN'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CLE'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CLE'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'COL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'COL'</span>,</span>
<span id="cb5-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'DET'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'DET'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'HOU'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'HOU'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'KCA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'KC'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LAN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LAD'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIA'</span>,</span>
<span id="cb5-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIL'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIL'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MIN'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'NYA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'NYY'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'NYN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'NYM'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ATH'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'OAK'</span>,</span>
<span id="cb5-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PHI'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PHI'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PIT'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PIT'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SDN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SD'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SEA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SEA'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SFN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SF'</span>,</span>
<span id="cb5-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SLN'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'STL'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TBA'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TB'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TEX'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TEX'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TOR'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TOR'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'WAS'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'WSH'</span></span>
<span id="cb5-10">}</span>
<span id="cb5-11"></span>
<span id="cb5-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Longitudes for geographical sorting (East to West)</span></span>
<span id="cb5-13">team_longitudes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb5-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"BOS"</span>: <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;">71.0589</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NYY"</span>: <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;">73.92</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NYM"</span>: <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;">73.84</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PHI"</span>: <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;">75.16</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"BAL"</span>: <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;">76.61</span>,</span>
<span id="cb5-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"WSH"</span>: <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;">77.03</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PIT"</span>: <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;">79.99</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TOR"</span>: <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;">79.38</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TB"</span>: <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;">82.65</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MIA"</span>: <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;">80.19</span>,</span>
<span id="cb5-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ATL"</span>: <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;">84.38</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CLE"</span>: <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;">81.69</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CIN"</span>: <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;">84.51</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"DET"</span>: <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;">83.04</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CWS"</span>: <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;">87.62</span>,</span>
<span id="cb5-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CHC"</span>: <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;">87.62</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"STL"</span>: <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;">90.19</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MIL"</span>: <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;">87.90</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MIN"</span>: <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;">93.26</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"KC"</span>: <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;">94.48</span>,</span>
<span id="cb5-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HOU"</span>: <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;">95.36</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TEX"</span>: <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;">96.79</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COL"</span>: <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;">104.99</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ARI"</span>: <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;">112.07</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"LAD"</span>: <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;">118.24</span>,</span>
<span id="cb5-19">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"LAA"</span>: <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;">117.88</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SD"</span>: <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;">117.16</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SF"</span>: <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;">122.38</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ATH"</span>: <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;">122.27</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SEA"</span>: <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;">122.33</span>,</span>
<span id="cb5-20">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NSH"</span>: <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;">86.78</span>,  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Nashville</span></span>
<span id="cb5-21">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POR"</span>: <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;">122.67</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Portland</span></span>
<span id="cb5-22">}</span>
<span id="cb5-23"></span>
<span id="cb5-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Simulate 32-Team League with 8 Divisions ---</span></span>
<span id="cb5-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 1. Define the new 8-division structure (4 teams per division)</span></span>
<span id="cb5-26">divisions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb5-27">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL East"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"BAL"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"BOS"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NYY"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"WSH"</span>],</span>
<span id="cb5-28">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL Central"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CWS"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CLE"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"DET"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TOR"</span>],</span>
<span id="cb5-29">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL South"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HOU"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"KC"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COL"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TEX"</span>],</span>
<span id="cb5-30">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL West"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"LAA"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ATH"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SEA"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POR"</span>],</span>
<span id="cb5-31">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL East"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NYM"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PHI"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CIN"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PIT"</span>],</span>
<span id="cb5-32">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL Central"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CHC"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MIL"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"STL"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MIN"</span>],</span>
<span id="cb5-33">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL South"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MIA"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TB"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NSH"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ATL"</span>],</span>
<span id="cb5-34">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL West"</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"LAD"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SD"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SF"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ARI"</span>]</span>
<span id="cb5-35">}</span>
<span id="cb5-36"></span>
<span id="cb5-37">leagues <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb5-38">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL"</span>: divisions[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL East"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> divisions[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL Central"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> divisions[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL South"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> divisions[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL West"</span>],</span>
<span id="cb5-39">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL"</span>: divisions[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL East"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> divisions[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL Central"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> divisions[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL South"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> divisions[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL West"</span>]</span>
<span id="cb5-40">}</span>
<span id="cb5-41"></span>
<span id="cb5-42"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 2. Simulate a full schedule based on the new structure</span></span>
<span id="cb5-43">all_games <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb5-44">all_teams <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> leagues[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> leagues[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL"</span>]</span>
<span id="cb5-45"></span>
<span id="cb5-46"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Scheduling formula for 162 games:</span></span>
<span id="cb5-47"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># - 14 games vs. 3 divisional opponents (42 games)</span></span>
<span id="cb5-48"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># - 6 games vs. 12 other league opponents (72 games)</span></span>
<span id="cb5-49"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># - 3 games vs. 16 interleague opponents (48 games)</span></span>
<span id="cb5-50"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use itertools.combinations to handle each pair only once, which is cleaner</span></span>
<span id="cb5-51"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># and avoids the double-counting issue with odd numbers of games.</span></span>
<span id="cb5-52"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> team1, team2 <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> itertools.combinations(all_teams, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>):</span>
<span id="cb5-53">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Determine the relationship between team1 and team2</span></span>
<span id="cb5-54">    team1_league <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;">"AL"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> team1 <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> leagues[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL"</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL"</span></span>
<span id="cb5-55">    team2_league <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;">"AL"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> team2 <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> leagues[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AL"</span>] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NL"</span></span>
<span id="cb5-56"></span>
<span id="cb5-57">    team1_division <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">next</span>(name <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> name, teams <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> divisions.items() <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> team1 <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> teams)</span>
<span id="cb5-58">    team2_division <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">next</span>(name <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> name, teams <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> divisions.items() <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> team2 <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> teams)</span>
<span id="cb5-59"></span>
<span id="cb5-60">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> team1_division <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> team2_division:</span>
<span id="cb5-61">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Divisional opponents play 14 games</span></span>
<span id="cb5-62">        all_games.extend([(team1, team2)] <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;">14</span>)</span>
<span id="cb5-63">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">elif</span> team1_league <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> team2_league:</span>
<span id="cb5-64">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Other intraleague opponents play 6 games</span></span>
<span id="cb5-65">        all_games.extend([(team1, team2)] <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;">6</span>)</span>
<span id="cb5-66">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb5-67">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Interleague opponents play 3 games</span></span>
<span id="cb5-68">        all_games.extend([(team1, team2)] <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="cb5-69"></span>
<span id="cb5-70"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Create Graph and Circular Layout ---</span></span>
<span id="cb5-71">sorted_teams <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(all_teams, key<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> team: team_longitudes[team])</span>
<span id="cb5-72"></span>
<span id="cb5-73">G <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nx.Graph()</span>
<span id="cb5-74">num_teams <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(sorted_teams)</span>
<span id="cb5-75">angle_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;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.pi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> num_teams</span>
<span id="cb5-76"></span>
<span id="cb5-77"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, team <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(sorted_teams):</span>
<span id="cb5-78">    angle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> angle_step</span>
<span id="cb5-79">    x, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cos(angle), np.sin(angle)</span>
<span id="cb5-80">    G.add_node(team, pos<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(x, y))</span>
<span id="cb5-81"></span>
<span id="cb5-82"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The game list has duplicates (A vs B and B vs A), so Counter handles it well</span></span>
<span id="cb5-83">game_counts <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Counter(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">tuple</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(game)) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> game <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> all_games)</span>
<span id="cb5-84"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (team1, team2), count <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> game_counts.items():</span>
<span id="cb5-85">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> G.has_node(team1) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> G.has_node(team2):</span>
<span id="cb5-86">        G.add_edge(team1, team2, weight<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>count)</span>
<span id="cb5-87"></span>
<span id="cb5-88"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Visualization with Matplotlib ---</span></span>
<span id="cb5-89">plt.figure(figsize<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;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>))</span>
<span id="cb5-90">ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.gca()</span>
<span id="cb5-91">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MLB Network with 32 Teams in 8 Divisions (Simulated Schedule)"</span>, fontsize<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;">16</span>)</span>
<span id="cb5-92"></span>
<span id="cb5-93"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Extract positions for drawing</span></span>
<span id="cb5-94">pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nx.get_node_attributes(G, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pos'</span>)</span>
<span id="cb5-95"></span>
<span id="cb5-96"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Draw the graph components</span></span>
<span id="cb5-97">nx.draw_networkx_nodes(G, pos, node_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;">'skyblue'</span>, node_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;">750</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.9</span>)</span>
<span id="cb5-98">nx.draw_networkx_edges(G, pos, edge_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;">'gray'</span>, width<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.0</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.6</span>)</span>
<span id="cb5-99">nx.draw_networkx_labels(G, pos, font_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>, font_weight<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;">'bold'</span>)</span>
<span id="cb5-100"></span>
<span id="cb5-101"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Remove axes for a cleaner look</span></span>
<span id="cb5-102">plt.axis(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"off"</span>)</span>
<span id="cb5-103">plt.tight_layout()</span>
<span id="cb5-104">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="figmlb-graph-32" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/mlb-realignment-graph-theory/index_files/figure-html/figmlb-graph-32-output-1.png" alt="Graph Network of Simulated 32-Team MLB Schedule" width="758" height="759" class="figure-img"></p>
<figcaption>Graph Network of Simulated 32-Team MLB Schedule</figcaption>
</figure>
</div>
</div>
</div>
<p>Last but not least, we can create an interactive graph to explore the simulated schedule.</p>
<div id="cell-fig:mlb-graph-interactive-32" class="cell" data-execution_count="6">
<details class="code-fold">
<summary>Code</summary>
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Visualization with Plotly ---</span></span>
<span id="cb6-2">pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nx.spring_layout(G, weight<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;">'weight'</span>, iterations<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;">10000</span>, seed<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;">47</span>)</span>
<span id="cb6-3"></span>
<span id="cb6-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Set the calculated positions as a node attribute</span></span>
<span id="cb6-5">nx.set_node_attributes(G, pos, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pos'</span>)</span>
<span id="cb6-6"></span>
<span id="cb6-7">fig_data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb6-8"></span>
<span id="cb6-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Create Edge Traces by Color with Hover Text ---</span></span>
<span id="cb6-10">edges_by_weight <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> defaultdict(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</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>
<span id="cb6-11"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> edge <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.edges(data<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="cb6-12">    weight <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> edge[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].get(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'weight'</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb6-13">    x0, y0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[edge[<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;">'pos'</span>]</span>
<span id="cb6-14">    x1, y1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[edge[<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;">'pos'</span>]</span>
<span id="cb6-15">    edges_by_weight[weight][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>].extend([x0, x1, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>])</span>
<span id="cb6-16">    edges_by_weight[weight][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>].extend([y0, y1, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>])</span>
<span id="cb6-17"></span>
<span id="cb6-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define a colorscale for the edges</span></span>
<span id="cb6-19">min_weight <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(edges_by_weight.keys()) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> edges_by_weight <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb6-20">max_weight <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(edges_by_weight.keys()) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> edges_by_weight <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb6-21">base_colorscale <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> px.colors.sequential.Blues</span>
<span id="cb6-22"></span>
<span id="cb6-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create a discrete color map</span></span>
<span id="cb6-24">unique_weights <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(edges_by_weight.keys()))</span>
<span id="cb6-25">num_unique_weights <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(unique_weights)</span>
<span id="cb6-26"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> num_unique_weights <span class="op" 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="cb6-27">    color_map <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {weight: base_colorscale[<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>(i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(base_colorscale) <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 class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (num_unique_weights <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 class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, weight <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(unique_weights)}</span>
<span id="cb6-28"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb6-29">    color_map <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {unique_weights[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]: base_colorscale[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]} <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> unique_weights <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> {}</span>
<span id="cb6-30"></span>
<span id="cb6-31"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> weight, a <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(edges_by_weight.items()):</span>
<span id="cb6-32">    color <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> color_map.get(weight, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#888888'</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Default color if weight not in map</span></span>
<span id="cb6-33">    edge_trace <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Scatter(x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>a[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>], y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>a[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>], line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(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;">2</span>, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>color), hoverinfo<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;">'none'</span>, mode<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'</span>)</span>
<span id="cb6-34">    fig_data.append(edge_trace)</span>
<span id="cb6-35"></span>
<span id="cb6-36">edge_hover_x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb6-37">edge_hover_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb6-38">edge_hover_text <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb6-39"></span>
<span id="cb6-40"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> edge <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.edges(data<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="cb6-41">    x0, y0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[edge[<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;">'pos'</span>]</span>
<span id="cb6-42">    x1, y1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[edge[<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;">'pos'</span>]</span>
<span id="cb6-43">    weight <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> edge[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].get(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'weight'</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb6-44">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Position the hover point at the midpoint of the edge</span></span>
<span id="cb6-45">    edge_hover_x.append((x0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1) <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="cb6-46">    edge_hover_y.append((y0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> y1) <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="cb6-47">    edge_hover_text.append(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>edge[<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="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> vs </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>edge[<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="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>weight<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;"> games'</span>)</span>
<span id="cb6-48"></span>
<span id="cb6-49"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># This trace holds the hover text and has invisible markers</span></span>
<span id="cb6-50">edge_hover_trace <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Scatter(</span>
<span id="cb6-51">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>edge_hover_x,</span>
<span id="cb6-52">    y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>edge_hover_y,</span>
<span id="cb6-53">    mode<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;">'markers'</span>,</span>
<span id="cb6-54">    hoverinfo<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;">'text'</span>,</span>
<span id="cb6-55">    text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>edge_hover_text,</span>
<span id="cb6-56">    marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</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;">20</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;">'rgba(0,0,0,0)'</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Invisible markers with a larger hover area</span></span>
<span id="cb6-57">)</span>
<span id="cb6-58">fig_data.append(edge_hover_trace)</span>
<span id="cb6-59"></span>
<span id="cb6-60">discrete_colorscale_for_bar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb6-61"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> num_unique_weights <span class="op" 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>
<span id="cb6-62">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, weight <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(unique_weights):</span>
<span id="cb6-63">        color <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> color_map.get(weight, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#888888'</span>)</span>
<span id="cb6-64">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define start and end points for this color's block in the bar (on a 0-1 scale)</span></span>
<span id="cb6-65">        start_norm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> num_unique_weights</span>
<span id="cb6-66">        end_norm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (i <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 class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> num_unique_weights</span>
<span id="cb6-67">        discrete_colorscale_for_bar.append([start_norm, color])</span>
<span id="cb6-68">        discrete_colorscale_for_bar.append([end_norm, color])</span>
<span id="cb6-69"></span>
<span id="cb6-70"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The colorbar needs to map values to this new 0-1 scale.</span></span>
<span id="cb6-71"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># We'll place the tick labels for our unique_weights in the center of each color block.</span></span>
<span id="cb6-72">tickvals_for_bar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [ (i <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>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> num_unique_weights <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(num_unique_weights) ] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> num_unique_weights <span class="op" 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="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> []</span>
<span id="cb6-73">ticktext_for_bar <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">str</span>(w) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> w <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> unique_weights]</span>
<span id="cb6-74"></span>
<span id="cb6-75">colorbar_trace <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Scatter(</span>
<span id="cb6-76">    x<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>], 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>], mode<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;">'markers'</span>, </span>
<span id="cb6-77">    marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb6-78">        color<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>],</span>
<span id="cb6-79">        colorscale<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>discrete_colorscale_for_bar,</span>
<span id="cb6-80">        cmin<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="cb6-81">        cmax<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="cb6-82">        showscale<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="cb6-83">        colorbar<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb6-84">            thickness<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>,</span>
<span id="cb6-85">            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;">'Games Played'</span>,</span>
<span id="cb6-86">            xanchor<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="cb6-87">            tickvals<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>tickvals_for_bar,</span>
<span id="cb6-88">            ticktext<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ticktext_for_bar,</span>
<span id="cb6-89">            outlinewidth<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="cb6-90">    )),</span>
<span id="cb6-91">    hoverinfo<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;">'none'</span></span>
<span id="cb6-92">)</span>
<span id="cb6-93">fig_data.append(colorbar_trace)</span>
<span id="cb6-94"></span>
<span id="cb6-95"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Create Node Trace ---</span></span>
<span id="cb6-96">node_x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb6-97">node_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb6-98"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> node <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.nodes():</span>
<span id="cb6-99">    x, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[node][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pos'</span>]</span>
<span id="cb6-100">    node_x.append(x)</span>
<span id="cb6-101">    node_y.append(y)</span>
<span id="cb6-102"></span>
<span id="cb6-103">node_text <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb6-104"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> node <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.nodes():</span>
<span id="cb6-105">    node_text.append(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'Team: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>node<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="cb6-106"></span>
<span id="cb6-107">node_trace <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Scatter(</span>
<span id="cb6-108">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>node_x, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>node_y,</span>
<span id="cb6-109">    mode<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;">'markers'</span>,</span>
<span id="cb6-110">    hoverinfo<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;">'text'</span>,</span>
<span id="cb6-111">    hovertext<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>node_text,</span>
<span id="cb6-112">    marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb6-113">        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;">35</span>, <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Make the hover area large</span></span>
<span id="cb6-114">        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;">'rgba(255, 255, 255, 0)'</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Make the markers invisible</span></span>
<span id="cb6-115">    )</span>
<span id="cb6-116">)</span>
<span id="cb6-117">fig_data.append(node_trace)</span>
<span id="cb6-118"></span>
<span id="cb6-119">layout_images <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb6-120"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate the range of coordinates to dynamically size logos</span></span>
<span id="cb6-121">x_range <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(node_x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(node_x) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> node_x <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb6-122">y_range <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(node_y) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(node_y) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> node_y <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb6-123">logo_size_x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> x_range <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.08</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Adjust the multiplier as needed</span></span>
<span id="cb6-124">logo_size_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y_range <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.08</span></span>
<span id="cb6-125"></span>
<span id="cb6-126"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> node <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> G.nodes():</span>
<span id="cb6-127">    x, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> G.nodes[node][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pos'</span>]</span>
<span id="cb6-128">    logo_url <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> team_logos.get(node)</span>
<span id="cb6-129">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> logo_url:</span>
<span id="cb6-130">        layout_images.append(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(source<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>logo_url, xref<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;">"x"</span>, yref<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;">"y"</span>, x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>x, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y, sizex<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>logo_size_x, sizey<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>logo_size_y, xanchor<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>, yanchor<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;">"middle"</span>, layer<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;">"above"</span>))</span>
<span id="cb6-131"></span>
<span id="cb6-132"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Create the Figure ---</span></span>
<span id="cb6-133">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Figure(</span>
<span id="cb6-134">    data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>fig_data,</span>
<span id="cb6-135">    layout<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>go.Layout(</span>
<span id="cb6-136">        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;">'&lt;br&gt;MLB 32-Team Expansion Simulation'</span>,</span>
<span id="cb6-137">        showlegend<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="cb6-138">        hovermode<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;">'closest'</span>,</span>
<span id="cb6-139">        margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(b<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>,l<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>,r<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>,t<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;">60</span>),</span>
<span id="cb6-140">        xaxis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(showgrid<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>, zeroline<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>, showticklabels<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="cb6-141">        yaxis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(showgrid<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>, zeroline<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>, showticklabels<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="cb6-142">        height<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;">600</span>, 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;">800</span>,</span>
<span id="cb6-143">        images<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>layout_images,</span>
<span id="cb6-144">    ),</span>
<span id="cb6-145">)</span>
<span id="cb6-146">fig.show()</span></code></pre></div>
</details>
<div id="figmlb-graph-interactive-32" class="cell-output cell-output-display">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="48911430-7419-4b0d-834a-44fbeaf9bb85" class="plotly-graph-div" style="height:600px; width:800px;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("48911430-7419-4b0d-834a-44fbeaf9bb85")) {                    Plotly.newPlot(                        "48911430-7419-4b0d-834a-44fbeaf9bb85",                        [{"hoverinfo":"none","line":{"color":"rgb(247,251,255)","width":2},"mode":"lines","x":[-0.1293902629132215,-0.6045535789144961,null,-0.1293902629132215,-0.8478429269792223,null,-0.1293902629132215,-0.952083484743586,null,-0.1293902629132215,-0.9571261288084636,null,-0.1293902629132215,-0.17287032075994663,null,-0.1293902629132215,-0.5801995866405754,null,-0.1293902629132215,-0.7882803942323491,null,-0.1293902629132215,-0.30234211764424435,null,-0.1293902629132215,0.5089150509500633,null,-0.1293902629132215,0.25097855257111035,null,-0.1293902629132215,0.2304098046443714,null,-0.1293902629132215,0.07612300271336989,null,-0.1293902629132215,-0.4325415528388654,null,-0.1293902629132215,-0.6318521606313038,null,-0.1293902629132215,-0.0676874162160826,null,-0.1293902629132215,-0.2934296191835501,null,-0.0676874162160826,0.7289131214928921,null,-0.0676874162160826,0.9456837309769305,null,-0.0676874162160826,0.8969427617730916,null,-0.0676874162160826,0.5352154239411152,null,-0.0676874162160826,0.9292959528684408,null,-0.0676874162160826,0.6842525701775461,null,-0.0676874162160826,0.31252836477924645,null,-0.0676874162160826,0.6295055096369523,null,-0.0676874162160826,0.25016484049172893,null,-0.0676874162160826,-0.061519203987132204,null,-0.0676874162160826,0.48898924645671216,null,-0.0676874162160826,0.21975149279329945,null,-0.0676874162160826,-0.38073799801552943,null,-0.0676874162160826,-0.46029700869829177,null,-0.0676874162160826,-0.024915665060014594,null,-0.024915665060014594,-0.6045535789144961,null,-0.024915665060014594,-0.8478429269792223,null,-0.024915665060014594,-0.952083484743586,null,-0.024915665060014594,-0.9571261288084636,null,-0.024915665060014594,-0.17287032075994663,null,-0.024915665060014594,-0.5801995866405754,null,-0.024915665060014594,-0.7882803942323491,null,-0.024915665060014594,-0.30234211764424435,null,-0.024915665060014594,0.5089150509500633,null,-0.024915665060014594,0.25097855257111035,null,-0.024915665060014594,0.2304098046443714,null,-0.024915665060014594,0.07612300271336989,null,-0.024915665060014594,-0.4325415528388654,null,-0.024915665060014594,-0.6318521606313038,null,-0.024915665060014594,-0.2934296191835501,null,-0.46029700869829177,-0.6045535789144961,null,-0.46029700869829177,-0.8478429269792223,null,-0.46029700869829177,-0.952083484743586,null,-0.46029700869829177,-0.9571261288084636,null,-0.46029700869829177,-0.17287032075994663,null,-0.46029700869829177,-0.5801995866405754,null,-0.46029700869829177,-0.7882803942323491,null,-0.46029700869829177,-0.30234211764424435,null,-0.46029700869829177,0.5089150509500633,null,-0.46029700869829177,0.25097855257111035,null,-0.46029700869829177,0.2304098046443714,null,-0.46029700869829177,0.07612300271336989,null,-0.46029700869829177,-0.4325415528388654,null,-0.46029700869829177,-0.6318521606313038,null,-0.46029700869829177,-0.2934296191835501,null,-0.4325415528388654,0.7289131214928921,null,-0.4325415528388654,0.9456837309769305,null,-0.4325415528388654,0.8969427617730916,null,-0.4325415528388654,0.5352154239411152,null,-0.4325415528388654,0.9292959528684408,null,-0.4325415528388654,0.6842525701775461,null,-0.4325415528388654,0.31252836477924645,null,-0.4325415528388654,0.6295055096369523,null,-0.4325415528388654,0.25016484049172893,null,-0.4325415528388654,-0.061519203987132204,null,-0.4325415528388654,0.48898924645671216,null,-0.4325415528388654,0.21975149279329945,null,-0.4325415528388654,-0.38073799801552943,null,-0.38073799801552943,-0.6045535789144961,null,-0.38073799801552943,-0.8478429269792223,null,-0.38073799801552943,-0.952083484743586,null,-0.38073799801552943,-0.9571261288084636,null,-0.38073799801552943,-0.17287032075994663,null,-0.38073799801552943,-0.5801995866405754,null,-0.38073799801552943,-0.7882803942323491,null,-0.38073799801552943,-0.30234211764424435,null,-0.38073799801552943,0.5089150509500633,null,-0.38073799801552943,0.25097855257111035,null,-0.38073799801552943,0.2304098046443714,null,-0.38073799801552943,0.07612300271336989,null,-0.38073799801552943,-0.6318521606313038,null,-0.38073799801552943,-0.2934296191835501,null,-0.6318521606313038,0.7289131214928921,null,-0.6318521606313038,0.9456837309769305,null,-0.6318521606313038,0.8969427617730916,null,-0.6318521606313038,0.5352154239411152,null,-0.6318521606313038,0.9292959528684408,null,-0.6318521606313038,0.6842525701775461,null,-0.6318521606313038,0.31252836477924645,null,-0.6318521606313038,0.6295055096369523,null,-0.6318521606313038,0.25016484049172893,null,-0.6318521606313038,-0.061519203987132204,null,-0.6318521606313038,0.48898924645671216,null,-0.6318521606313038,0.21975149279329945,null,-0.2934296191835501,0.7289131214928921,null,-0.2934296191835501,0.9456837309769305,null,-0.2934296191835501,0.8969427617730916,null,-0.2934296191835501,0.5352154239411152,null,-0.2934296191835501,0.9292959528684408,null,-0.2934296191835501,0.6842525701775461,null,-0.2934296191835501,0.31252836477924645,null,-0.2934296191835501,0.6295055096369523,null,-0.2934296191835501,0.25016484049172893,null,-0.2934296191835501,-0.061519203987132204,null,-0.2934296191835501,0.48898924645671216,null,-0.2934296191835501,0.21975149279329945,null,0.48898924645671216,-0.6045535789144961,null,0.48898924645671216,-0.8478429269792223,null,0.48898924645671216,-0.952083484743586,null,0.48898924645671216,-0.9571261288084636,null,0.48898924645671216,-0.17287032075994663,null,0.48898924645671216,-0.5801995866405754,null,0.48898924645671216,-0.7882803942323491,null,0.48898924645671216,-0.30234211764424435,null,0.48898924645671216,0.5089150509500633,null,0.48898924645671216,0.25097855257111035,null,0.48898924645671216,0.2304098046443714,null,0.48898924645671216,0.07612300271336989,null,0.21975149279329945,-0.6045535789144961,null,0.21975149279329945,-0.8478429269792223,null,0.21975149279329945,-0.952083484743586,null,0.21975149279329945,-0.9571261288084636,null,0.21975149279329945,-0.17287032075994663,null,0.21975149279329945,-0.5801995866405754,null,0.21975149279329945,-0.7882803942323491,null,0.21975149279329945,-0.30234211764424435,null,0.21975149279329945,0.5089150509500633,null,0.21975149279329945,0.25097855257111035,null,0.21975149279329945,0.2304098046443714,null,0.21975149279329945,0.07612300271336989,null,0.25016484049172893,-0.6045535789144961,null,0.25016484049172893,-0.8478429269792223,null,0.25016484049172893,-0.952083484743586,null,0.25016484049172893,-0.9571261288084636,null,0.25016484049172893,-0.17287032075994663,null,0.25016484049172893,-0.5801995866405754,null,0.25016484049172893,-0.7882803942323491,null,0.25016484049172893,-0.30234211764424435,null,0.25016484049172893,0.5089150509500633,null,0.25016484049172893,0.25097855257111035,null,0.25016484049172893,0.2304098046443714,null,0.25016484049172893,0.07612300271336989,null,-0.061519203987132204,-0.6045535789144961,null,-0.061519203987132204,-0.8478429269792223,null,-0.061519203987132204,-0.952083484743586,null,-0.061519203987132204,-0.9571261288084636,null,-0.061519203987132204,-0.17287032075994663,null,-0.061519203987132204,-0.5801995866405754,null,-0.061519203987132204,-0.7882803942323491,null,-0.061519203987132204,-0.30234211764424435,null,-0.061519203987132204,0.5089150509500633,null,-0.061519203987132204,0.25097855257111035,null,-0.061519203987132204,0.2304098046443714,null,-0.061519203987132204,0.07612300271336989,null,-0.30234211764424435,0.7289131214928921,null,-0.30234211764424435,0.9456837309769305,null,-0.30234211764424435,0.8969427617730916,null,-0.30234211764424435,0.5352154239411152,null,-0.30234211764424435,0.9292959528684408,null,-0.30234211764424435,0.6842525701775461,null,-0.30234211764424435,0.31252836477924645,null,-0.30234211764424435,0.6295055096369523,null,-0.7882803942323491,0.7289131214928921,null,-0.7882803942323491,0.9456837309769305,null,-0.7882803942323491,0.8969427617730916,null,-0.7882803942323491,0.5352154239411152,null,-0.7882803942323491,0.9292959528684408,null,-0.7882803942323491,0.6842525701775461,null,-0.7882803942323491,0.31252836477924645,null,-0.7882803942323491,0.6295055096369523,null,-0.5801995866405754,0.7289131214928921,null,-0.5801995866405754,0.9456837309769305,null,-0.5801995866405754,0.8969427617730916,null,-0.5801995866405754,0.5352154239411152,null,-0.5801995866405754,0.9292959528684408,null,-0.5801995866405754,0.6842525701775461,null,-0.5801995866405754,0.31252836477924645,null,-0.5801995866405754,0.6295055096369523,null,0.9292959528684408,-0.6045535789144961,null,0.9292959528684408,-0.8478429269792223,null,0.9292959528684408,-0.952083484743586,null,0.9292959528684408,-0.9571261288084636,null,0.9292959528684408,-0.17287032075994663,null,0.9292959528684408,0.5089150509500633,null,0.9292959528684408,0.25097855257111035,null,0.9292959528684408,0.2304098046443714,null,0.9292959528684408,0.07612300271336989,null,-0.17287032075994663,0.7289131214928921,null,-0.17287032075994663,0.9456837309769305,null,-0.17287032075994663,0.8969427617730916,null,-0.17287032075994663,0.5352154239411152,null,-0.17287032075994663,0.6842525701775461,null,-0.17287032075994663,0.31252836477924645,null,-0.17287032075994663,0.6295055096369523,null,0.2304098046443714,0.7289131214928921,null,0.2304098046443714,0.9456837309769305,null,0.2304098046443714,0.8969427617730916,null,0.2304098046443714,0.5352154239411152,null,0.2304098046443714,0.6842525701775461,null,0.2304098046443714,0.31252836477924645,null,0.2304098046443714,0.6295055096369523,null,-0.952083484743586,0.7289131214928921,null,-0.952083484743586,0.9456837309769305,null,-0.952083484743586,0.8969427617730916,null,-0.952083484743586,0.5352154239411152,null,-0.952083484743586,0.6842525701775461,null,-0.952083484743586,0.31252836477924645,null,-0.952083484743586,0.6295055096369523,null,0.07612300271336989,0.7289131214928921,null,0.07612300271336989,0.9456837309769305,null,0.07612300271336989,0.8969427617730916,null,0.07612300271336989,0.5352154239411152,null,0.07612300271336989,0.6842525701775461,null,0.07612300271336989,0.31252836477924645,null,0.07612300271336989,0.6295055096369523,null,0.31252836477924645,-0.6045535789144961,null,0.31252836477924645,-0.8478429269792223,null,0.31252836477924645,-0.9571261288084636,null,0.31252836477924645,0.5089150509500633,null,0.31252836477924645,0.25097855257111035,null,0.25097855257111035,0.7289131214928921,null,0.25097855257111035,0.9456837309769305,null,0.25097855257111035,0.8969427617730916,null,0.25097855257111035,0.5352154239411152,null,0.25097855257111035,0.6842525701775461,null,0.25097855257111035,0.6295055096369523,null,0.6842525701775461,-0.6045535789144961,null,0.6842525701775461,-0.8478429269792223,null,0.6842525701775461,-0.9571261288084636,null,0.6842525701775461,0.5089150509500633,null,0.5089150509500633,0.7289131214928921,null,0.5089150509500633,0.9456837309769305,null,0.5089150509500633,0.8969427617730916,null,0.5089150509500633,0.5352154239411152,null,0.5089150509500633,0.6295055096369523,null,-0.9571261288084636,0.7289131214928921,null,-0.9571261288084636,0.9456837309769305,null,-0.9571261288084636,0.8969427617730916,null,-0.9571261288084636,0.5352154239411152,null,-0.9571261288084636,0.6295055096369523,null,0.6295055096369523,-0.6045535789144961,null,0.6295055096369523,-0.8478429269792223,null,0.5352154239411152,-0.6045535789144961,null,0.5352154239411152,-0.8478429269792223,null,0.7289131214928921,-0.6045535789144961,null,0.7289131214928921,-0.8478429269792223,null,-0.8478429269792223,0.9456837309769305,null,-0.8478429269792223,0.8969427617730916,null,0.8969427617730916,-0.6045535789144961,null,-0.6045535789144961,0.9456837309769305,null],"y":[-0.6283009269781801,-0.13292294560255052,null,-0.6283009269781801,-0.2930080723174416,null,-0.6283009269781801,0.3095524284153506,null,-0.6283009269781801,0.00222274711555857,null,-0.6283009269781801,0.708962778636833,null,-0.6283009269781801,0.8413991314511314,null,-0.6283009269781801,0.6262086340430204,null,-0.6283009269781801,0.9853638236005767,null,-0.6283009269781801,0.7408446053373394,null,-0.6283009269781801,0.4778588956780366,null,-0.6283009269781801,0.7896580836582391,null,-0.6283009269781801,1.0,null,-0.6283009269781801,0.48731883257649616,null,-0.6283009269781801,0.23579839359787869,null,-0.6283009269781801,0.31611021975143444,null,-0.6283009269781801,0.056841138884124454,null,0.31611021975143444,-0.6902875398160129,null,0.31611021975143444,-0.1806441158732172,null,0.31611021975143444,-0.4594132392275352,null,0.31611021975143444,-0.38706740454704114,null,0.31611021975143444,0.14789309482509957,null,0.31611021975143444,0.31079088777914055,null,0.31611021975143444,-0.05454408347632135,null,0.31611021975143444,-0.016093989893461336,null,0.31611021975143444,-0.6094303126649081,null,0.31611021975143444,-0.9623921618512388,null,0.31611021975143444,-0.8777600078831772,null,0.31611021975143444,-0.9813482027304328,null,0.31611021975143444,-0.860304463271996,null,0.31611021975143444,-0.5779191544094333,null,0.31611021975143444,-0.3253870748073273,null,-0.3253870748073273,-0.13292294560255052,null,-0.3253870748073273,-0.2930080723174416,null,-0.3253870748073273,0.3095524284153506,null,-0.3253870748073273,0.00222274711555857,null,-0.3253870748073273,0.708962778636833,null,-0.3253870748073273,0.8413991314511314,null,-0.3253870748073273,0.6262086340430204,null,-0.3253870748073273,0.9853638236005767,null,-0.3253870748073273,0.7408446053373394,null,-0.3253870748073273,0.4778588956780366,null,-0.3253870748073273,0.7896580836582391,null,-0.3253870748073273,1.0,null,-0.3253870748073273,0.48731883257649616,null,-0.3253870748073273,0.23579839359787869,null,-0.3253870748073273,0.056841138884124454,null,-0.5779191544094333,-0.13292294560255052,null,-0.5779191544094333,-0.2930080723174416,null,-0.5779191544094333,0.3095524284153506,null,-0.5779191544094333,0.00222274711555857,null,-0.5779191544094333,0.708962778636833,null,-0.5779191544094333,0.8413991314511314,null,-0.5779191544094333,0.6262086340430204,null,-0.5779191544094333,0.9853638236005767,null,-0.5779191544094333,0.7408446053373394,null,-0.5779191544094333,0.4778588956780366,null,-0.5779191544094333,0.7896580836582391,null,-0.5779191544094333,1.0,null,-0.5779191544094333,0.48731883257649616,null,-0.5779191544094333,0.23579839359787869,null,-0.5779191544094333,0.056841138884124454,null,0.48731883257649616,-0.6902875398160129,null,0.48731883257649616,-0.1806441158732172,null,0.48731883257649616,-0.4594132392275352,null,0.48731883257649616,-0.38706740454704114,null,0.48731883257649616,0.14789309482509957,null,0.48731883257649616,0.31079088777914055,null,0.48731883257649616,-0.05454408347632135,null,0.48731883257649616,-0.016093989893461336,null,0.48731883257649616,-0.6094303126649081,null,0.48731883257649616,-0.9623921618512388,null,0.48731883257649616,-0.8777600078831772,null,0.48731883257649616,-0.9813482027304328,null,0.48731883257649616,-0.860304463271996,null,-0.860304463271996,-0.13292294560255052,null,-0.860304463271996,-0.2930080723174416,null,-0.860304463271996,0.3095524284153506,null,-0.860304463271996,0.00222274711555857,null,-0.860304463271996,0.708962778636833,null,-0.860304463271996,0.8413991314511314,null,-0.860304463271996,0.6262086340430204,null,-0.860304463271996,0.9853638236005767,null,-0.860304463271996,0.7408446053373394,null,-0.860304463271996,0.4778588956780366,null,-0.860304463271996,0.7896580836582391,null,-0.860304463271996,1.0,null,-0.860304463271996,0.23579839359787869,null,-0.860304463271996,0.056841138884124454,null,0.23579839359787869,-0.6902875398160129,null,0.23579839359787869,-0.1806441158732172,null,0.23579839359787869,-0.4594132392275352,null,0.23579839359787869,-0.38706740454704114,null,0.23579839359787869,0.14789309482509957,null,0.23579839359787869,0.31079088777914055,null,0.23579839359787869,-0.05454408347632135,null,0.23579839359787869,-0.016093989893461336,null,0.23579839359787869,-0.6094303126649081,null,0.23579839359787869,-0.9623921618512388,null,0.23579839359787869,-0.8777600078831772,null,0.23579839359787869,-0.9813482027304328,null,0.056841138884124454,-0.6902875398160129,null,0.056841138884124454,-0.1806441158732172,null,0.056841138884124454,-0.4594132392275352,null,0.056841138884124454,-0.38706740454704114,null,0.056841138884124454,0.14789309482509957,null,0.056841138884124454,0.31079088777914055,null,0.056841138884124454,-0.05454408347632135,null,0.056841138884124454,-0.016093989893461336,null,0.056841138884124454,-0.6094303126649081,null,0.056841138884124454,-0.9623921618512388,null,0.056841138884124454,-0.8777600078831772,null,0.056841138884124454,-0.9813482027304328,null,-0.8777600078831772,-0.13292294560255052,null,-0.8777600078831772,-0.2930080723174416,null,-0.8777600078831772,0.3095524284153506,null,-0.8777600078831772,0.00222274711555857,null,-0.8777600078831772,0.708962778636833,null,-0.8777600078831772,0.8413991314511314,null,-0.8777600078831772,0.6262086340430204,null,-0.8777600078831772,0.9853638236005767,null,-0.8777600078831772,0.7408446053373394,null,-0.8777600078831772,0.4778588956780366,null,-0.8777600078831772,0.7896580836582391,null,-0.8777600078831772,1.0,null,-0.9813482027304328,-0.13292294560255052,null,-0.9813482027304328,-0.2930080723174416,null,-0.9813482027304328,0.3095524284153506,null,-0.9813482027304328,0.00222274711555857,null,-0.9813482027304328,0.708962778636833,null,-0.9813482027304328,0.8413991314511314,null,-0.9813482027304328,0.6262086340430204,null,-0.9813482027304328,0.9853638236005767,null,-0.9813482027304328,0.7408446053373394,null,-0.9813482027304328,0.4778588956780366,null,-0.9813482027304328,0.7896580836582391,null,-0.9813482027304328,1.0,null,-0.6094303126649081,-0.13292294560255052,null,-0.6094303126649081,-0.2930080723174416,null,-0.6094303126649081,0.3095524284153506,null,-0.6094303126649081,0.00222274711555857,null,-0.6094303126649081,0.708962778636833,null,-0.6094303126649081,0.8413991314511314,null,-0.6094303126649081,0.6262086340430204,null,-0.6094303126649081,0.9853638236005767,null,-0.6094303126649081,0.7408446053373394,null,-0.6094303126649081,0.4778588956780366,null,-0.6094303126649081,0.7896580836582391,null,-0.6094303126649081,1.0,null,-0.9623921618512388,-0.13292294560255052,null,-0.9623921618512388,-0.2930080723174416,null,-0.9623921618512388,0.3095524284153506,null,-0.9623921618512388,0.00222274711555857,null,-0.9623921618512388,0.708962778636833,null,-0.9623921618512388,0.8413991314511314,null,-0.9623921618512388,0.6262086340430204,null,-0.9623921618512388,0.9853638236005767,null,-0.9623921618512388,0.7408446053373394,null,-0.9623921618512388,0.4778588956780366,null,-0.9623921618512388,0.7896580836582391,null,-0.9623921618512388,1.0,null,0.9853638236005767,-0.6902875398160129,null,0.9853638236005767,-0.1806441158732172,null,0.9853638236005767,-0.4594132392275352,null,0.9853638236005767,-0.38706740454704114,null,0.9853638236005767,0.14789309482509957,null,0.9853638236005767,0.31079088777914055,null,0.9853638236005767,-0.05454408347632135,null,0.9853638236005767,-0.016093989893461336,null,0.6262086340430204,-0.6902875398160129,null,0.6262086340430204,-0.1806441158732172,null,0.6262086340430204,-0.4594132392275352,null,0.6262086340430204,-0.38706740454704114,null,0.6262086340430204,0.14789309482509957,null,0.6262086340430204,0.31079088777914055,null,0.6262086340430204,-0.05454408347632135,null,0.6262086340430204,-0.016093989893461336,null,0.8413991314511314,-0.6902875398160129,null,0.8413991314511314,-0.1806441158732172,null,0.8413991314511314,-0.4594132392275352,null,0.8413991314511314,-0.38706740454704114,null,0.8413991314511314,0.14789309482509957,null,0.8413991314511314,0.31079088777914055,null,0.8413991314511314,-0.05454408347632135,null,0.8413991314511314,-0.016093989893461336,null,0.14789309482509957,-0.13292294560255052,null,0.14789309482509957,-0.2930080723174416,null,0.14789309482509957,0.3095524284153506,null,0.14789309482509957,0.00222274711555857,null,0.14789309482509957,0.708962778636833,null,0.14789309482509957,0.7408446053373394,null,0.14789309482509957,0.4778588956780366,null,0.14789309482509957,0.7896580836582391,null,0.14789309482509957,1.0,null,0.708962778636833,-0.6902875398160129,null,0.708962778636833,-0.1806441158732172,null,0.708962778636833,-0.4594132392275352,null,0.708962778636833,-0.38706740454704114,null,0.708962778636833,0.31079088777914055,null,0.708962778636833,-0.05454408347632135,null,0.708962778636833,-0.016093989893461336,null,0.7896580836582391,-0.6902875398160129,null,0.7896580836582391,-0.1806441158732172,null,0.7896580836582391,-0.4594132392275352,null,0.7896580836582391,-0.38706740454704114,null,0.7896580836582391,0.31079088777914055,null,0.7896580836582391,-0.05454408347632135,null,0.7896580836582391,-0.016093989893461336,null,0.3095524284153506,-0.6902875398160129,null,0.3095524284153506,-0.1806441158732172,null,0.3095524284153506,-0.4594132392275352,null,0.3095524284153506,-0.38706740454704114,null,0.3095524284153506,0.31079088777914055,null,0.3095524284153506,-0.05454408347632135,null,0.3095524284153506,-0.016093989893461336,null,1.0,-0.6902875398160129,null,1.0,-0.1806441158732172,null,1.0,-0.4594132392275352,null,1.0,-0.38706740454704114,null,1.0,0.31079088777914055,null,1.0,-0.05454408347632135,null,1.0,-0.016093989893461336,null,-0.05454408347632135,-0.13292294560255052,null,-0.05454408347632135,-0.2930080723174416,null,-0.05454408347632135,0.00222274711555857,null,-0.05454408347632135,0.7408446053373394,null,-0.05454408347632135,0.4778588956780366,null,0.4778588956780366,-0.6902875398160129,null,0.4778588956780366,-0.1806441158732172,null,0.4778588956780366,-0.4594132392275352,null,0.4778588956780366,-0.38706740454704114,null,0.4778588956780366,0.31079088777914055,null,0.4778588956780366,-0.016093989893461336,null,0.31079088777914055,-0.13292294560255052,null,0.31079088777914055,-0.2930080723174416,null,0.31079088777914055,0.00222274711555857,null,0.31079088777914055,0.7408446053373394,null,0.7408446053373394,-0.6902875398160129,null,0.7408446053373394,-0.1806441158732172,null,0.7408446053373394,-0.4594132392275352,null,0.7408446053373394,-0.38706740454704114,null,0.7408446053373394,-0.016093989893461336,null,0.00222274711555857,-0.6902875398160129,null,0.00222274711555857,-0.1806441158732172,null,0.00222274711555857,-0.4594132392275352,null,0.00222274711555857,-0.38706740454704114,null,0.00222274711555857,-0.016093989893461336,null,-0.016093989893461336,-0.13292294560255052,null,-0.016093989893461336,-0.2930080723174416,null,-0.38706740454704114,-0.13292294560255052,null,-0.38706740454704114,-0.2930080723174416,null,-0.6902875398160129,-0.13292294560255052,null,-0.6902875398160129,-0.2930080723174416,null,-0.2930080723174416,-0.1806441158732172,null,-0.2930080723174416,-0.4594132392275352,null,-0.4594132392275352,-0.13292294560255052,null,-0.13292294560255052,-0.1806441158732172,null],"type":"scatter"},{"hoverinfo":"none","line":{"color":"rgb(107,174,214)","width":2},"mode":"lines","x":[-0.1293902629132215,0.7289131214928921,null,-0.1293902629132215,0.9456837309769305,null,-0.1293902629132215,0.8969427617730916,null,-0.1293902629132215,0.5352154239411152,null,-0.1293902629132215,0.9292959528684408,null,-0.1293902629132215,0.6842525701775461,null,-0.1293902629132215,0.31252836477924645,null,-0.1293902629132215,0.6295055096369523,null,-0.1293902629132215,0.25016484049172893,null,-0.1293902629132215,-0.061519203987132204,null,-0.1293902629132215,0.48898924645671216,null,-0.1293902629132215,0.21975149279329945,null,-0.0676874162160826,-0.6045535789144961,null,-0.0676874162160826,-0.8478429269792223,null,-0.0676874162160826,-0.952083484743586,null,-0.0676874162160826,-0.9571261288084636,null,-0.0676874162160826,-0.17287032075994663,null,-0.0676874162160826,-0.5801995866405754,null,-0.0676874162160826,-0.7882803942323491,null,-0.0676874162160826,-0.30234211764424435,null,-0.0676874162160826,0.5089150509500633,null,-0.0676874162160826,0.25097855257111035,null,-0.0676874162160826,0.2304098046443714,null,-0.0676874162160826,0.07612300271336989,null,-0.024915665060014594,0.7289131214928921,null,-0.024915665060014594,0.9456837309769305,null,-0.024915665060014594,0.8969427617730916,null,-0.024915665060014594,0.5352154239411152,null,-0.024915665060014594,0.9292959528684408,null,-0.024915665060014594,0.6842525701775461,null,-0.024915665060014594,0.31252836477924645,null,-0.024915665060014594,0.6295055096369523,null,-0.024915665060014594,0.25016484049172893,null,-0.024915665060014594,-0.061519203987132204,null,-0.024915665060014594,0.48898924645671216,null,-0.024915665060014594,0.21975149279329945,null,-0.46029700869829177,0.7289131214928921,null,-0.46029700869829177,0.9456837309769305,null,-0.46029700869829177,0.8969427617730916,null,-0.46029700869829177,0.5352154239411152,null,-0.46029700869829177,0.9292959528684408,null,-0.46029700869829177,0.6842525701775461,null,-0.46029700869829177,0.31252836477924645,null,-0.46029700869829177,0.6295055096369523,null,-0.46029700869829177,0.25016484049172893,null,-0.46029700869829177,-0.061519203987132204,null,-0.46029700869829177,0.48898924645671216,null,-0.46029700869829177,0.21975149279329945,null,-0.4325415528388654,-0.6045535789144961,null,-0.4325415528388654,-0.8478429269792223,null,-0.4325415528388654,-0.952083484743586,null,-0.4325415528388654,-0.9571261288084636,null,-0.4325415528388654,-0.17287032075994663,null,-0.4325415528388654,-0.5801995866405754,null,-0.4325415528388654,-0.7882803942323491,null,-0.4325415528388654,-0.30234211764424435,null,-0.4325415528388654,0.5089150509500633,null,-0.4325415528388654,0.25097855257111035,null,-0.4325415528388654,0.2304098046443714,null,-0.4325415528388654,0.07612300271336989,null,-0.38073799801552943,0.7289131214928921,null,-0.38073799801552943,0.9456837309769305,null,-0.38073799801552943,0.8969427617730916,null,-0.38073799801552943,0.5352154239411152,null,-0.38073799801552943,0.9292959528684408,null,-0.38073799801552943,0.6842525701775461,null,-0.38073799801552943,0.31252836477924645,null,-0.38073799801552943,0.6295055096369523,null,-0.38073799801552943,0.25016484049172893,null,-0.38073799801552943,-0.061519203987132204,null,-0.38073799801552943,0.48898924645671216,null,-0.38073799801552943,0.21975149279329945,null,-0.6318521606313038,-0.6045535789144961,null,-0.6318521606313038,-0.8478429269792223,null,-0.6318521606313038,-0.952083484743586,null,-0.6318521606313038,-0.9571261288084636,null,-0.6318521606313038,-0.17287032075994663,null,-0.6318521606313038,-0.5801995866405754,null,-0.6318521606313038,-0.7882803942323491,null,-0.6318521606313038,-0.30234211764424435,null,-0.6318521606313038,0.5089150509500633,null,-0.6318521606313038,0.25097855257111035,null,-0.6318521606313038,0.2304098046443714,null,-0.6318521606313038,0.07612300271336989,null,-0.2934296191835501,-0.6045535789144961,null,-0.2934296191835501,-0.8478429269792223,null,-0.2934296191835501,-0.952083484743586,null,-0.2934296191835501,-0.9571261288084636,null,-0.2934296191835501,-0.17287032075994663,null,-0.2934296191835501,-0.5801995866405754,null,-0.2934296191835501,-0.7882803942323491,null,-0.2934296191835501,-0.30234211764424435,null,-0.2934296191835501,0.5089150509500633,null,-0.2934296191835501,0.25097855257111035,null,-0.2934296191835501,0.2304098046443714,null,-0.2934296191835501,0.07612300271336989,null,0.48898924645671216,0.7289131214928921,null,0.48898924645671216,0.9456837309769305,null,0.48898924645671216,0.8969427617730916,null,0.48898924645671216,0.5352154239411152,null,0.48898924645671216,0.9292959528684408,null,0.48898924645671216,0.6842525701775461,null,0.48898924645671216,0.31252836477924645,null,0.48898924645671216,0.6295055096369523,null,0.21975149279329945,0.7289131214928921,null,0.21975149279329945,0.9456837309769305,null,0.21975149279329945,0.8969427617730916,null,0.21975149279329945,0.5352154239411152,null,0.21975149279329945,0.9292959528684408,null,0.21975149279329945,0.6842525701775461,null,0.21975149279329945,0.31252836477924645,null,0.21975149279329945,0.6295055096369523,null,0.25016484049172893,0.7289131214928921,null,0.25016484049172893,0.9456837309769305,null,0.25016484049172893,0.8969427617730916,null,0.25016484049172893,0.5352154239411152,null,0.25016484049172893,0.9292959528684408,null,0.25016484049172893,0.6842525701775461,null,0.25016484049172893,0.31252836477924645,null,0.25016484049172893,0.6295055096369523,null,-0.061519203987132204,0.7289131214928921,null,-0.061519203987132204,0.9456837309769305,null,-0.061519203987132204,0.8969427617730916,null,-0.061519203987132204,0.5352154239411152,null,-0.061519203987132204,0.9292959528684408,null,-0.061519203987132204,0.6842525701775461,null,-0.061519203987132204,0.31252836477924645,null,-0.061519203987132204,0.6295055096369523,null,-0.30234211764424435,-0.6045535789144961,null,-0.30234211764424435,-0.8478429269792223,null,-0.30234211764424435,-0.952083484743586,null,-0.30234211764424435,-0.9571261288084636,null,-0.30234211764424435,0.5089150509500633,null,-0.30234211764424435,0.25097855257111035,null,-0.30234211764424435,0.2304098046443714,null,-0.30234211764424435,0.07612300271336989,null,-0.7882803942323491,-0.6045535789144961,null,-0.7882803942323491,-0.8478429269792223,null,-0.7882803942323491,-0.952083484743586,null,-0.7882803942323491,-0.9571261288084636,null,-0.7882803942323491,0.5089150509500633,null,-0.7882803942323491,0.25097855257111035,null,-0.7882803942323491,0.2304098046443714,null,-0.7882803942323491,0.07612300271336989,null,-0.5801995866405754,-0.6045535789144961,null,-0.5801995866405754,-0.8478429269792223,null,-0.5801995866405754,-0.952083484743586,null,-0.5801995866405754,-0.9571261288084636,null,-0.5801995866405754,0.5089150509500633,null,-0.5801995866405754,0.25097855257111035,null,-0.5801995866405754,0.2304098046443714,null,-0.5801995866405754,0.07612300271336989,null,0.9292959528684408,0.7289131214928921,null,0.9292959528684408,0.9456837309769305,null,0.9292959528684408,0.8969427617730916,null,0.9292959528684408,0.5352154239411152,null,-0.17287032075994663,-0.6045535789144961,null,-0.17287032075994663,-0.8478429269792223,null,-0.17287032075994663,-0.952083484743586,null,-0.17287032075994663,-0.9571261288084636,null,-0.17287032075994663,0.5089150509500633,null,-0.17287032075994663,0.25097855257111035,null,-0.17287032075994663,0.2304098046443714,null,-0.17287032075994663,0.07612300271336989,null,0.2304098046443714,-0.6045535789144961,null,0.2304098046443714,-0.8478429269792223,null,0.2304098046443714,-0.952083484743586,null,0.2304098046443714,-0.9571261288084636,null,-0.952083484743586,0.5089150509500633,null,-0.952083484743586,0.25097855257111035,null,-0.952083484743586,0.07612300271336989,null,0.07612300271336989,-0.6045535789144961,null,0.07612300271336989,-0.8478429269792223,null,0.07612300271336989,-0.9571261288084636,null,0.31252836477924645,0.7289131214928921,null,0.31252836477924645,0.9456837309769305,null,0.31252836477924645,0.8969427617730916,null,0.31252836477924645,0.5352154239411152,null,0.25097855257111035,-0.6045535789144961,null,0.25097855257111035,-0.8478429269792223,null,0.25097855257111035,-0.9571261288084636,null,0.6842525701775461,0.7289131214928921,null,0.6842525701775461,0.9456837309769305,null,0.6842525701775461,0.8969427617730916,null,0.6842525701775461,0.5352154239411152,null,0.5089150509500633,-0.6045535789144961,null,0.5089150509500633,-0.8478429269792223,null,0.5089150509500633,-0.9571261288084636,null,0.6295055096369523,0.7289131214928921,null,0.6295055096369523,0.9456837309769305,null,0.6295055096369523,0.8969427617730916,null,0.6295055096369523,0.5352154239411152,null],"y":[-0.6283009269781801,-0.6902875398160129,null,-0.6283009269781801,-0.1806441158732172,null,-0.6283009269781801,-0.4594132392275352,null,-0.6283009269781801,-0.38706740454704114,null,-0.6283009269781801,0.14789309482509957,null,-0.6283009269781801,0.31079088777914055,null,-0.6283009269781801,-0.05454408347632135,null,-0.6283009269781801,-0.016093989893461336,null,-0.6283009269781801,-0.6094303126649081,null,-0.6283009269781801,-0.9623921618512388,null,-0.6283009269781801,-0.8777600078831772,null,-0.6283009269781801,-0.9813482027304328,null,0.31611021975143444,-0.13292294560255052,null,0.31611021975143444,-0.2930080723174416,null,0.31611021975143444,0.3095524284153506,null,0.31611021975143444,0.00222274711555857,null,0.31611021975143444,0.708962778636833,null,0.31611021975143444,0.8413991314511314,null,0.31611021975143444,0.6262086340430204,null,0.31611021975143444,0.9853638236005767,null,0.31611021975143444,0.7408446053373394,null,0.31611021975143444,0.4778588956780366,null,0.31611021975143444,0.7896580836582391,null,0.31611021975143444,1.0,null,-0.3253870748073273,-0.6902875398160129,null,-0.3253870748073273,-0.1806441158732172,null,-0.3253870748073273,-0.4594132392275352,null,-0.3253870748073273,-0.38706740454704114,null,-0.3253870748073273,0.14789309482509957,null,-0.3253870748073273,0.31079088777914055,null,-0.3253870748073273,-0.05454408347632135,null,-0.3253870748073273,-0.016093989893461336,null,-0.3253870748073273,-0.6094303126649081,null,-0.3253870748073273,-0.9623921618512388,null,-0.3253870748073273,-0.8777600078831772,null,-0.3253870748073273,-0.9813482027304328,null,-0.5779191544094333,-0.6902875398160129,null,-0.5779191544094333,-0.1806441158732172,null,-0.5779191544094333,-0.4594132392275352,null,-0.5779191544094333,-0.38706740454704114,null,-0.5779191544094333,0.14789309482509957,null,-0.5779191544094333,0.31079088777914055,null,-0.5779191544094333,-0.05454408347632135,null,-0.5779191544094333,-0.016093989893461336,null,-0.5779191544094333,-0.6094303126649081,null,-0.5779191544094333,-0.9623921618512388,null,-0.5779191544094333,-0.8777600078831772,null,-0.5779191544094333,-0.9813482027304328,null,0.48731883257649616,-0.13292294560255052,null,0.48731883257649616,-0.2930080723174416,null,0.48731883257649616,0.3095524284153506,null,0.48731883257649616,0.00222274711555857,null,0.48731883257649616,0.708962778636833,null,0.48731883257649616,0.8413991314511314,null,0.48731883257649616,0.6262086340430204,null,0.48731883257649616,0.9853638236005767,null,0.48731883257649616,0.7408446053373394,null,0.48731883257649616,0.4778588956780366,null,0.48731883257649616,0.7896580836582391,null,0.48731883257649616,1.0,null,-0.860304463271996,-0.6902875398160129,null,-0.860304463271996,-0.1806441158732172,null,-0.860304463271996,-0.4594132392275352,null,-0.860304463271996,-0.38706740454704114,null,-0.860304463271996,0.14789309482509957,null,-0.860304463271996,0.31079088777914055,null,-0.860304463271996,-0.05454408347632135,null,-0.860304463271996,-0.016093989893461336,null,-0.860304463271996,-0.6094303126649081,null,-0.860304463271996,-0.9623921618512388,null,-0.860304463271996,-0.8777600078831772,null,-0.860304463271996,-0.9813482027304328,null,0.23579839359787869,-0.13292294560255052,null,0.23579839359787869,-0.2930080723174416,null,0.23579839359787869,0.3095524284153506,null,0.23579839359787869,0.00222274711555857,null,0.23579839359787869,0.708962778636833,null,0.23579839359787869,0.8413991314511314,null,0.23579839359787869,0.6262086340430204,null,0.23579839359787869,0.9853638236005767,null,0.23579839359787869,0.7408446053373394,null,0.23579839359787869,0.4778588956780366,null,0.23579839359787869,0.7896580836582391,null,0.23579839359787869,1.0,null,0.056841138884124454,-0.13292294560255052,null,0.056841138884124454,-0.2930080723174416,null,0.056841138884124454,0.3095524284153506,null,0.056841138884124454,0.00222274711555857,null,0.056841138884124454,0.708962778636833,null,0.056841138884124454,0.8413991314511314,null,0.056841138884124454,0.6262086340430204,null,0.056841138884124454,0.9853638236005767,null,0.056841138884124454,0.7408446053373394,null,0.056841138884124454,0.4778588956780366,null,0.056841138884124454,0.7896580836582391,null,0.056841138884124454,1.0,null,-0.8777600078831772,-0.6902875398160129,null,-0.8777600078831772,-0.1806441158732172,null,-0.8777600078831772,-0.4594132392275352,null,-0.8777600078831772,-0.38706740454704114,null,-0.8777600078831772,0.14789309482509957,null,-0.8777600078831772,0.31079088777914055,null,-0.8777600078831772,-0.05454408347632135,null,-0.8777600078831772,-0.016093989893461336,null,-0.9813482027304328,-0.6902875398160129,null,-0.9813482027304328,-0.1806441158732172,null,-0.9813482027304328,-0.4594132392275352,null,-0.9813482027304328,-0.38706740454704114,null,-0.9813482027304328,0.14789309482509957,null,-0.9813482027304328,0.31079088777914055,null,-0.9813482027304328,-0.05454408347632135,null,-0.9813482027304328,-0.016093989893461336,null,-0.6094303126649081,-0.6902875398160129,null,-0.6094303126649081,-0.1806441158732172,null,-0.6094303126649081,-0.4594132392275352,null,-0.6094303126649081,-0.38706740454704114,null,-0.6094303126649081,0.14789309482509957,null,-0.6094303126649081,0.31079088777914055,null,-0.6094303126649081,-0.05454408347632135,null,-0.6094303126649081,-0.016093989893461336,null,-0.9623921618512388,-0.6902875398160129,null,-0.9623921618512388,-0.1806441158732172,null,-0.9623921618512388,-0.4594132392275352,null,-0.9623921618512388,-0.38706740454704114,null,-0.9623921618512388,0.14789309482509957,null,-0.9623921618512388,0.31079088777914055,null,-0.9623921618512388,-0.05454408347632135,null,-0.9623921618512388,-0.016093989893461336,null,0.9853638236005767,-0.13292294560255052,null,0.9853638236005767,-0.2930080723174416,null,0.9853638236005767,0.3095524284153506,null,0.9853638236005767,0.00222274711555857,null,0.9853638236005767,0.7408446053373394,null,0.9853638236005767,0.4778588956780366,null,0.9853638236005767,0.7896580836582391,null,0.9853638236005767,1.0,null,0.6262086340430204,-0.13292294560255052,null,0.6262086340430204,-0.2930080723174416,null,0.6262086340430204,0.3095524284153506,null,0.6262086340430204,0.00222274711555857,null,0.6262086340430204,0.7408446053373394,null,0.6262086340430204,0.4778588956780366,null,0.6262086340430204,0.7896580836582391,null,0.6262086340430204,1.0,null,0.8413991314511314,-0.13292294560255052,null,0.8413991314511314,-0.2930080723174416,null,0.8413991314511314,0.3095524284153506,null,0.8413991314511314,0.00222274711555857,null,0.8413991314511314,0.7408446053373394,null,0.8413991314511314,0.4778588956780366,null,0.8413991314511314,0.7896580836582391,null,0.8413991314511314,1.0,null,0.14789309482509957,-0.6902875398160129,null,0.14789309482509957,-0.1806441158732172,null,0.14789309482509957,-0.4594132392275352,null,0.14789309482509957,-0.38706740454704114,null,0.708962778636833,-0.13292294560255052,null,0.708962778636833,-0.2930080723174416,null,0.708962778636833,0.3095524284153506,null,0.708962778636833,0.00222274711555857,null,0.708962778636833,0.7408446053373394,null,0.708962778636833,0.4778588956780366,null,0.708962778636833,0.7896580836582391,null,0.708962778636833,1.0,null,0.7896580836582391,-0.13292294560255052,null,0.7896580836582391,-0.2930080723174416,null,0.7896580836582391,0.3095524284153506,null,0.7896580836582391,0.00222274711555857,null,0.3095524284153506,0.7408446053373394,null,0.3095524284153506,0.4778588956780366,null,0.3095524284153506,1.0,null,1.0,-0.13292294560255052,null,1.0,-0.2930080723174416,null,1.0,0.00222274711555857,null,-0.05454408347632135,-0.6902875398160129,null,-0.05454408347632135,-0.1806441158732172,null,-0.05454408347632135,-0.4594132392275352,null,-0.05454408347632135,-0.38706740454704114,null,0.4778588956780366,-0.13292294560255052,null,0.4778588956780366,-0.2930080723174416,null,0.4778588956780366,0.00222274711555857,null,0.31079088777914055,-0.6902875398160129,null,0.31079088777914055,-0.1806441158732172,null,0.31079088777914055,-0.4594132392275352,null,0.31079088777914055,-0.38706740454704114,null,0.7408446053373394,-0.13292294560255052,null,0.7408446053373394,-0.2930080723174416,null,0.7408446053373394,0.00222274711555857,null,-0.016093989893461336,-0.6902875398160129,null,-0.016093989893461336,-0.1806441158732172,null,-0.016093989893461336,-0.4594132392275352,null,-0.016093989893461336,-0.38706740454704114,null],"type":"scatter"},{"hoverinfo":"none","line":{"color":"rgb(8,48,107)","width":2},"mode":"lines","x":[-0.1293902629132215,-0.38073799801552943,null,-0.1293902629132215,-0.46029700869829177,null,-0.1293902629132215,-0.024915665060014594,null,-0.0676874162160826,-0.4325415528388654,null,-0.0676874162160826,-0.6318521606313038,null,-0.0676874162160826,-0.2934296191835501,null,-0.024915665060014594,-0.38073799801552943,null,-0.024915665060014594,-0.46029700869829177,null,-0.46029700869829177,-0.38073799801552943,null,-0.4325415528388654,-0.6318521606313038,null,-0.4325415528388654,-0.2934296191835501,null,-0.6318521606313038,-0.2934296191835501,null,0.48898924645671216,0.25016484049172893,null,0.48898924645671216,-0.061519203987132204,null,0.48898924645671216,0.21975149279329945,null,0.21975149279329945,0.25016484049172893,null,0.21975149279329945,-0.061519203987132204,null,0.25016484049172893,-0.061519203987132204,null,-0.30234211764424435,-0.17287032075994663,null,-0.30234211764424435,-0.5801995866405754,null,-0.30234211764424435,-0.7882803942323491,null,-0.7882803942323491,-0.17287032075994663,null,-0.7882803942323491,-0.5801995866405754,null,-0.5801995866405754,-0.17287032075994663,null,0.9292959528684408,0.6842525701775461,null,0.9292959528684408,0.31252836477924645,null,0.9292959528684408,0.6295055096369523,null,0.2304098046443714,0.5089150509500633,null,0.2304098046443714,0.25097855257111035,null,0.2304098046443714,0.07612300271336989,null,-0.952083484743586,-0.6045535789144961,null,-0.952083484743586,-0.8478429269792223,null,-0.952083484743586,-0.9571261288084636,null,0.07612300271336989,0.5089150509500633,null,0.07612300271336989,0.25097855257111035,null,0.31252836477924645,0.6842525701775461,null,0.31252836477924645,0.6295055096369523,null,0.25097855257111035,0.5089150509500633,null,0.6842525701775461,0.6295055096369523,null,-0.9571261288084636,-0.6045535789144961,null,-0.9571261288084636,-0.8478429269792223,null,0.5352154239411152,0.7289131214928921,null,0.5352154239411152,0.9456837309769305,null,0.5352154239411152,0.8969427617730916,null,0.7289131214928921,0.9456837309769305,null,0.7289131214928921,0.8969427617730916,null,-0.8478429269792223,-0.6045535789144961,null,0.8969427617730916,0.9456837309769305,null],"y":[-0.6283009269781801,-0.860304463271996,null,-0.6283009269781801,-0.5779191544094333,null,-0.6283009269781801,-0.3253870748073273,null,0.31611021975143444,0.48731883257649616,null,0.31611021975143444,0.23579839359787869,null,0.31611021975143444,0.056841138884124454,null,-0.3253870748073273,-0.860304463271996,null,-0.3253870748073273,-0.5779191544094333,null,-0.5779191544094333,-0.860304463271996,null,0.48731883257649616,0.23579839359787869,null,0.48731883257649616,0.056841138884124454,null,0.23579839359787869,0.056841138884124454,null,-0.8777600078831772,-0.6094303126649081,null,-0.8777600078831772,-0.9623921618512388,null,-0.8777600078831772,-0.9813482027304328,null,-0.9813482027304328,-0.6094303126649081,null,-0.9813482027304328,-0.9623921618512388,null,-0.6094303126649081,-0.9623921618512388,null,0.9853638236005767,0.708962778636833,null,0.9853638236005767,0.8413991314511314,null,0.9853638236005767,0.6262086340430204,null,0.6262086340430204,0.708962778636833,null,0.6262086340430204,0.8413991314511314,null,0.8413991314511314,0.708962778636833,null,0.14789309482509957,0.31079088777914055,null,0.14789309482509957,-0.05454408347632135,null,0.14789309482509957,-0.016093989893461336,null,0.7896580836582391,0.7408446053373394,null,0.7896580836582391,0.4778588956780366,null,0.7896580836582391,1.0,null,0.3095524284153506,-0.13292294560255052,null,0.3095524284153506,-0.2930080723174416,null,0.3095524284153506,0.00222274711555857,null,1.0,0.7408446053373394,null,1.0,0.4778588956780366,null,-0.05454408347632135,0.31079088777914055,null,-0.05454408347632135,-0.016093989893461336,null,0.4778588956780366,0.7408446053373394,null,0.31079088777914055,-0.016093989893461336,null,0.00222274711555857,-0.13292294560255052,null,0.00222274711555857,-0.2930080723174416,null,-0.38706740454704114,-0.6902875398160129,null,-0.38706740454704114,-0.1806441158732172,null,-0.38706740454704114,-0.4594132392275352,null,-0.6902875398160129,-0.1806441158732172,null,-0.6902875398160129,-0.4594132392275352,null,-0.2930080723174416,-0.13292294560255052,null,-0.4594132392275352,-0.1806441158732172,null],"type":"scatter"},{"hoverinfo":"text","marker":{"color":"rgba(0,0,0,0)","size":20},"mode":"markers","text":["POR vs BAL: 6 games","POR vs BOS: 6 games","POR vs NYY: 6 games","POR vs WSH: 6 games","POR vs CWS: 6 games","POR vs CLE: 6 games","POR vs DET: 6 games","POR vs TOR: 6 games","POR vs HOU: 6 games","POR vs KC: 6 games","POR vs COL: 6 games","POR vs TEX: 6 games","POR vs LAA: 14 games","POR vs ATH: 14 games","POR vs SEA: 14 games","POR vs NYM: 3 games","POR vs PHI: 3 games","POR vs CIN: 3 games","POR vs PIT: 3 games","POR vs CHC: 3 games","POR vs MIL: 3 games","POR vs STL: 3 games","POR vs MIN: 3 games","POR vs MIA: 3 games","POR vs TB: 3 games","POR vs NSH: 3 games","POR vs ATL: 3 games","POR vs LAD: 3 games","POR vs SD: 3 games","POR vs SF: 3 games","POR vs ARI: 3 games","SF vs BAL: 3 games","SF vs BOS: 3 games","SF vs NYY: 3 games","SF vs WSH: 3 games","SF vs CWS: 3 games","SF vs CLE: 3 games","SF vs DET: 3 games","SF vs TOR: 3 games","SF vs HOU: 3 games","SF vs KC: 3 games","SF vs COL: 3 games","SF vs TEX: 3 games","SF vs LAA: 3 games","SF vs ATH: 3 games","SF vs SEA: 3 games","SF vs NYM: 6 games","SF vs PHI: 6 games","SF vs CIN: 6 games","SF vs PIT: 6 games","SF vs CHC: 6 games","SF vs MIL: 6 games","SF vs STL: 6 games","SF vs MIN: 6 games","SF vs MIA: 6 games","SF vs TB: 6 games","SF vs NSH: 6 games","SF vs ATL: 6 games","SF vs LAD: 14 games","SF vs SD: 14 games","SF vs ARI: 14 games","SEA vs BAL: 6 games","SEA vs BOS: 6 games","SEA vs NYY: 6 games","SEA vs WSH: 6 games","SEA vs CWS: 6 games","SEA vs CLE: 6 games","SEA vs DET: 6 games","SEA vs TOR: 6 games","SEA vs HOU: 6 games","SEA vs KC: 6 games","SEA vs COL: 6 games","SEA vs TEX: 6 games","SEA vs LAA: 14 games","SEA vs ATH: 14 games","SEA vs NYM: 3 games","SEA vs PHI: 3 games","SEA vs CIN: 3 games","SEA vs PIT: 3 games","SEA vs CHC: 3 games","SEA vs MIL: 3 games","SEA vs STL: 3 games","SEA vs MIN: 3 games","SEA vs MIA: 3 games","SEA vs TB: 3 games","SEA vs NSH: 3 games","SEA vs ATL: 3 games","SEA vs LAD: 3 games","SEA vs SD: 3 games","SEA vs ARI: 3 games","ATH vs BAL: 6 games","ATH vs BOS: 6 games","ATH vs NYY: 6 games","ATH vs WSH: 6 games","ATH vs CWS: 6 games","ATH vs CLE: 6 games","ATH vs DET: 6 games","ATH vs TOR: 6 games","ATH vs HOU: 6 games","ATH vs KC: 6 games","ATH vs COL: 6 games","ATH vs TEX: 6 games","ATH vs LAA: 14 games","ATH vs NYM: 3 games","ATH vs PHI: 3 games","ATH vs CIN: 3 games","ATH vs PIT: 3 games","ATH vs CHC: 3 games","ATH vs MIL: 3 games","ATH vs STL: 3 games","ATH vs MIN: 3 games","ATH vs MIA: 3 games","ATH vs TB: 3 games","ATH vs NSH: 3 games","ATH vs ATL: 3 games","ATH vs LAD: 3 games","ATH vs SD: 3 games","ATH vs ARI: 3 games","LAD vs BAL: 3 games","LAD vs BOS: 3 games","LAD vs NYY: 3 games","LAD vs WSH: 3 games","LAD vs CWS: 3 games","LAD vs CLE: 3 games","LAD vs DET: 3 games","LAD vs TOR: 3 games","LAD vs HOU: 3 games","LAD vs KC: 3 games","LAD vs COL: 3 games","LAD vs TEX: 3 games","LAD vs LAA: 3 games","LAD vs NYM: 6 games","LAD vs PHI: 6 games","LAD vs CIN: 6 games","LAD vs PIT: 6 games","LAD vs CHC: 6 games","LAD vs MIL: 6 games","LAD vs STL: 6 games","LAD vs MIN: 6 games","LAD vs MIA: 6 games","LAD vs TB: 6 games","LAD vs NSH: 6 games","LAD vs ATL: 6 games","LAD vs SD: 14 games","LAD vs ARI: 14 games","LAA vs BAL: 6 games","LAA vs BOS: 6 games","LAA vs NYY: 6 games","LAA vs WSH: 6 games","LAA vs CWS: 6 games","LAA vs CLE: 6 games","LAA vs DET: 6 games","LAA vs TOR: 6 games","LAA vs HOU: 6 games","LAA vs KC: 6 games","LAA vs COL: 6 games","LAA vs TEX: 6 games","LAA vs NYM: 3 games","LAA vs PHI: 3 games","LAA vs CIN: 3 games","LAA vs PIT: 3 games","LAA vs CHC: 3 games","LAA vs MIL: 3 games","LAA vs STL: 3 games","LAA vs MIN: 3 games","LAA vs MIA: 3 games","LAA vs TB: 3 games","LAA vs NSH: 3 games","LAA vs ATL: 3 games","LAA vs SD: 3 games","LAA vs ARI: 3 games","SD vs BAL: 3 games","SD vs BOS: 3 games","SD vs NYY: 3 games","SD vs WSH: 3 games","SD vs CWS: 3 games","SD vs CLE: 3 games","SD vs DET: 3 games","SD vs TOR: 3 games","SD vs HOU: 3 games","SD vs KC: 3 games","SD vs COL: 3 games","SD vs TEX: 3 games","SD vs NYM: 6 games","SD vs PHI: 6 games","SD vs CIN: 6 games","SD vs PIT: 6 games","SD vs CHC: 6 games","SD vs MIL: 6 games","SD vs STL: 6 games","SD vs MIN: 6 games","SD vs MIA: 6 games","SD vs TB: 6 games","SD vs NSH: 6 games","SD vs ATL: 6 games","SD vs ARI: 14 games","ARI vs BAL: 3 games","ARI vs BOS: 3 games","ARI vs NYY: 3 games","ARI vs WSH: 3 games","ARI vs CWS: 3 games","ARI vs CLE: 3 games","ARI vs DET: 3 games","ARI vs TOR: 3 games","ARI vs HOU: 3 games","ARI vs KC: 3 games","ARI vs COL: 3 games","ARI vs TEX: 3 games","ARI vs NYM: 6 games","ARI vs PHI: 6 games","ARI vs CIN: 6 games","ARI vs PIT: 6 games","ARI vs CHC: 6 games","ARI vs MIL: 6 games","ARI vs STL: 6 games","ARI vs MIN: 6 games","ARI vs MIA: 6 games","ARI vs TB: 6 games","ARI vs NSH: 6 games","ARI vs ATL: 6 games","COL vs BAL: 6 games","COL vs BOS: 6 games","COL vs NYY: 6 games","COL vs WSH: 6 games","COL vs CWS: 6 games","COL vs CLE: 6 games","COL vs DET: 6 games","COL vs TOR: 6 games","COL vs HOU: 14 games","COL vs KC: 14 games","COL vs TEX: 14 games","COL vs NYM: 3 games","COL vs PHI: 3 games","COL vs CIN: 3 games","COL vs PIT: 3 games","COL vs CHC: 3 games","COL vs MIL: 3 games","COL vs STL: 3 games","COL vs MIN: 3 games","COL vs MIA: 3 games","COL vs TB: 3 games","COL vs NSH: 3 games","COL vs ATL: 3 games","TEX vs BAL: 6 games","TEX vs BOS: 6 games","TEX vs NYY: 6 games","TEX vs WSH: 6 games","TEX vs CWS: 6 games","TEX vs CLE: 6 games","TEX vs DET: 6 games","TEX vs TOR: 6 games","TEX vs HOU: 14 games","TEX vs KC: 14 games","TEX vs NYM: 3 games","TEX vs PHI: 3 games","TEX vs CIN: 3 games","TEX vs PIT: 3 games","TEX vs CHC: 3 games","TEX vs MIL: 3 games","TEX vs STL: 3 games","TEX vs MIN: 3 games","TEX vs MIA: 3 games","TEX vs TB: 3 games","TEX vs NSH: 3 games","TEX vs ATL: 3 games","HOU vs BAL: 6 games","HOU vs BOS: 6 games","HOU vs NYY: 6 games","HOU vs WSH: 6 games","HOU vs CWS: 6 games","HOU vs CLE: 6 games","HOU vs DET: 6 games","HOU vs TOR: 6 games","HOU vs KC: 14 games","HOU vs NYM: 3 games","HOU vs PHI: 3 games","HOU vs CIN: 3 games","HOU vs PIT: 3 games","HOU vs CHC: 3 games","HOU vs MIL: 3 games","HOU vs STL: 3 games","HOU vs MIN: 3 games","HOU vs MIA: 3 games","HOU vs TB: 3 games","HOU vs NSH: 3 games","HOU vs ATL: 3 games","KC vs BAL: 6 games","KC vs BOS: 6 games","KC vs NYY: 6 games","KC vs WSH: 6 games","KC vs CWS: 6 games","KC vs CLE: 6 games","KC vs DET: 6 games","KC vs TOR: 6 games","KC vs NYM: 3 games","KC vs PHI: 3 games","KC vs CIN: 3 games","KC vs PIT: 3 games","KC vs CHC: 3 games","KC vs MIL: 3 games","KC vs STL: 3 games","KC vs MIN: 3 games","KC vs MIA: 3 games","KC vs TB: 3 games","KC vs NSH: 3 games","KC vs ATL: 3 games","MIN vs BAL: 3 games","MIN vs BOS: 3 games","MIN vs NYY: 3 games","MIN vs WSH: 3 games","MIN vs CWS: 3 games","MIN vs CLE: 3 games","MIN vs DET: 3 games","MIN vs TOR: 3 games","MIN vs NYM: 6 games","MIN vs PHI: 6 games","MIN vs CIN: 6 games","MIN vs PIT: 6 games","MIN vs CHC: 14 games","MIN vs MIL: 14 games","MIN vs STL: 14 games","MIN vs MIA: 6 games","MIN vs TB: 6 games","MIN vs NSH: 6 games","MIN vs ATL: 6 games","STL vs BAL: 3 games","STL vs BOS: 3 games","STL vs NYY: 3 games","STL vs WSH: 3 games","STL vs CWS: 3 games","STL vs CLE: 3 games","STL vs DET: 3 games","STL vs TOR: 3 games","STL vs NYM: 6 games","STL vs PHI: 6 games","STL vs CIN: 6 games","STL vs PIT: 6 games","STL vs CHC: 14 games","STL vs MIL: 14 games","STL vs MIA: 6 games","STL vs TB: 6 games","STL vs NSH: 6 games","STL vs ATL: 6 games","MIL vs BAL: 3 games","MIL vs BOS: 3 games","MIL vs NYY: 3 games","MIL vs WSH: 3 games","MIL vs CWS: 3 games","MIL vs CLE: 3 games","MIL vs DET: 3 games","MIL vs TOR: 3 games","MIL vs NYM: 6 games","MIL vs PHI: 6 games","MIL vs CIN: 6 games","MIL vs PIT: 6 games","MIL vs CHC: 14 games","MIL vs MIA: 6 games","MIL vs TB: 6 games","MIL vs NSH: 6 games","MIL vs ATL: 6 games","CWS vs BAL: 6 games","CWS vs BOS: 6 games","CWS vs NYY: 6 games","CWS vs WSH: 6 games","CWS vs CLE: 14 games","CWS vs DET: 14 games","CWS vs TOR: 14 games","CWS vs NYM: 3 games","CWS vs PHI: 3 games","CWS vs CIN: 3 games","CWS vs PIT: 3 games","CWS vs CHC: 3 games","CWS vs MIA: 3 games","CWS vs TB: 3 games","CWS vs NSH: 3 games","CWS vs ATL: 3 games","CHC vs BAL: 3 games","CHC vs BOS: 3 games","CHC vs NYY: 3 games","CHC vs WSH: 3 games","CHC vs CLE: 3 games","CHC vs DET: 3 games","CHC vs TOR: 3 games","CHC vs NYM: 6 games","CHC vs PHI: 6 games","CHC vs CIN: 6 games","CHC vs PIT: 6 games","CHC vs MIA: 6 games","CHC vs TB: 6 games","CHC vs NSH: 6 games","CHC vs ATL: 6 games","NSH vs BAL: 3 games","NSH vs BOS: 3 games","NSH vs NYY: 3 games","NSH vs WSH: 3 games","NSH vs CLE: 3 games","NSH vs DET: 3 games","NSH vs TOR: 3 games","NSH vs NYM: 6 games","NSH vs PHI: 6 games","NSH vs CIN: 6 games","NSH vs PIT: 6 games","NSH vs MIA: 14 games","NSH vs TB: 14 games","NSH vs ATL: 14 games","CIN vs BAL: 3 games","CIN vs BOS: 3 games","CIN vs NYY: 3 games","CIN vs WSH: 3 games","CIN vs CLE: 3 games","CIN vs DET: 3 games","CIN vs TOR: 3 games","CIN vs NYM: 14 games","CIN vs PHI: 14 games","CIN vs PIT: 14 games","CIN vs MIA: 6 games","CIN vs TB: 6 games","CIN vs ATL: 6 games","ATL vs BAL: 3 games","ATL vs BOS: 3 games","ATL vs NYY: 3 games","ATL vs WSH: 3 games","ATL vs CLE: 3 games","ATL vs DET: 3 games","ATL vs TOR: 3 games","ATL vs NYM: 6 games","ATL vs PHI: 6 games","ATL vs PIT: 6 games","ATL vs MIA: 14 games","ATL vs TB: 14 games","DET vs BAL: 6 games","DET vs BOS: 6 games","DET vs NYY: 6 games","DET vs WSH: 6 games","DET vs CLE: 14 games","DET vs TOR: 14 games","DET vs NYM: 3 games","DET vs PHI: 3 games","DET vs PIT: 3 games","DET vs MIA: 3 games","DET vs TB: 3 games","TB vs BAL: 3 games","TB vs BOS: 3 games","TB vs NYY: 3 games","TB vs WSH: 3 games","TB vs CLE: 3 games","TB vs TOR: 3 games","TB vs NYM: 6 games","TB vs PHI: 6 games","TB vs PIT: 6 games","TB vs MIA: 14 games","CLE vs BAL: 6 games","CLE vs BOS: 6 games","CLE vs NYY: 6 games","CLE vs WSH: 6 games","CLE vs TOR: 14 games","CLE vs NYM: 3 games","CLE vs PHI: 3 games","CLE vs PIT: 3 games","CLE vs MIA: 3 games","MIA vs BAL: 3 games","MIA vs BOS: 3 games","MIA vs NYY: 3 games","MIA vs WSH: 3 games","MIA vs TOR: 3 games","MIA vs NYM: 6 games","MIA vs PHI: 6 games","MIA vs PIT: 6 games","PIT vs BAL: 3 games","PIT vs BOS: 3 games","PIT vs NYY: 3 games","PIT vs WSH: 3 games","PIT vs TOR: 3 games","PIT vs NYM: 14 games","PIT vs PHI: 14 games","TOR vs BAL: 6 games","TOR vs BOS: 6 games","TOR vs NYY: 6 games","TOR vs WSH: 6 games","TOR vs NYM: 3 games","TOR vs PHI: 3 games","WSH vs BAL: 14 games","WSH vs BOS: 14 games","WSH vs NYY: 14 games","WSH vs NYM: 3 games","WSH vs PHI: 3 games","BAL vs BOS: 14 games","BAL vs NYY: 14 games","BAL vs NYM: 3 games","BAL vs PHI: 3 games","PHI vs BOS: 3 games","PHI vs NYY: 3 games","PHI vs NYM: 14 games","NYY vs BOS: 14 games","NYY vs NYM: 3 games","NYM vs BOS: 3 games"],"x":[0.2997614292898353,0.4081467340318545,0.38377624942993505,0.20291258051394684,0.39995284497760963,0.2774311536321623,0.09156905093301247,0.2500576233618654,0.060387288789253715,-0.09545473345017685,0.1797994917717453,0.04518061494003897,-0.2550641304643755,-0.2948436358057566,-0.07715296398661806,-0.36697192091385883,-0.4886165949462219,-0.5407368738284037,-0.5432581958608426,-0.15113029183658405,-0.35479492477689845,-0.4588353285727853,-0.21586619027873294,0.18976239401842088,0.06079414482894442,0.050509770865574954,-0.02663363009992581,-0.2809659078760435,-0.38062121177226266,-0.09853883956465205,-0.21140994104838579,0.3306128526384048,0.4389981573804239,0.41462767277850454,0.2337640038625163,0.43080426832617913,0.3082825769807318,0.12242047428158193,0.2809090467104348,0.09123871213782317,-0.0646033101016074,0.21065091512031478,0.07603203828860843,-0.22421270711580601,-0.2639922124571872,-0.046301540638048595,-0.3361204975652894,-0.4577651715976524,-0.5098854504798342,-0.5124067725122731,-0.12027886848801461,-0.32394350142832895,-0.4279839052242158,-0.18501476693016347,0.22061381736699034,0.09164556817751388,0.08136119421414441,0.004217793248643645,-0.250114484527474,-0.3497697884236932,-0.18055851769981635,0.35199872821643874,0.4603840329584579,0.4360135483565385,0.2551498794405503,0.4521901439042131,0.32966845255876576,0.14380634985961593,0.3022949222884688,0.11262458771585718,-0.0432174345235734,0.2320367906983488,0.09741791386664242,-0.202826831537772,-0.24260633687915317,-0.3147346219872554,-0.43637929601961845,-0.4884995749018003,-0.4910208969342391,-0.0988929929099806,-0.302557625850295,-0.40659802964618186,-0.16362889135212946,0.24199969294502435,0.11303144375554788,0.1027470697921784,0.025603668826677646,-0.22872860894944,-0.3283839128456592,-0.15917264212178234,0.13430805639730017,0.24269336113931936,0.21832287653739993,0.03745920762141172,0.23449947208507452,0.11197778073962719,-0.07388432195952266,0.08460425046933026,-0.10506608410328142,-0.260908106342712,0.014346118879210196,-0.12027275795249616,-0.4205175033569106,-0.5324252938063939,-0.654069967838757,-0.7061902467209389,-0.7087115687533777,-0.3165836647291192,-0.5202482976694336,-0.6242887014653205,-0.38131956317126803,0.02430902112588576,-0.10465922806359071,-0.11494360202696018,-0.19208700299246095,-0.4464192807685786,-0.5460745846647977,-0.37686331394092093,0.14818578432701335,0.25657108906903253,0.2322006044671131,0.051336935551124896,0.2483772000147877,0.12585550866934037,-0.060006594029809485,0.09848197839904343,-0.09118835617356824,-0.2470303784129988,0.02822384680892337,-0.10639503002278299,-0.4066397754271974,-0.5185475658766807,-0.6401922399090438,-0.6923125187912257,-0.6948338408236645,-0.30270593679940605,-0.5063705697397204,-0.6104109735356072,-0.3674418352415549,0.038186749055598934,-0.09078150013387754,-0.101065874097247,-0.17820927506274775,-0.5321968567350845,-0.3629855860112078,0.17408756173868134,0.2824728664807005,0.2581023818787811,0.07723871296279289,0.2742789774264557,0.15175728608100836,-0.03410481661814149,0.12438375581071143,-0.06528657876190025,-0.2211286010013308,0.05412562422059136,-0.080493252611115,-0.4926457884650128,-0.6142904624973758,-0.6664107413795577,-0.6689320634119965,-0.27680415938773806,-0.4804687923280524,-0.5845091961239393,-0.3415400578298869,0.06408852646726693,-0.06487972272220954,-0.07516409668557901,-0.15230749765107976,-0.5062950793234167,-0.3370838085995398,0.048530480430794165,0.15691578517281335,0.13254530057089392,-0.04831836834509429,0.1487218961185685,0.026200204773121183,-0.15966189792602867,-0.0011733254971757479,-0.19084366006978742,-0.346685682309218,-0.07143145708729581,-0.20605033391900218,-0.6182028697729,-0.739847543805263,-0.7919678226874449,-0.7944891447198836,-0.4023612406956252,-0.6060258736359396,-0.7100662774318265,-0.46709713913777406,-0.06146855484062025,-0.19043680403009672,-0.20072117799346617,-0.27786457895896693,-0.4626408899074269,0.217741751154671,0.3261270558966902,0.30175657129477074,0.12089290237878256,0.3179331668424453,0.19541147549699803,0.009549372797848177,0.1680379452267011,-0.02163238934591058,-0.17747441158534116,0.09777981363658103,-0.036839063195125324,-0.4489915990490231,-0.5706362730813862,-0.622756551963568,-0.6252778739960069,-0.23314996997174836,-0.43681460291206275,-0.5408550067079496,-0.2978858684138972,0.1077427158832566,-0.021225533306219874,-0.03150990726958934,-0.1086533082350901,0.6089511839748021,0.7173364887168213,0.692966004114902,0.5121023351989137,0.7091425996625764,0.5866209083171292,0.4007588056179793,0.5592473780468322,0.36957704347422055,0.21373502123479,0.3543703696250058,-0.057782166228891985,-0.17942684026125505,-0.2315471191434369,-0.23406844117587572,0.15805946284838276,-0.0456051700919316,-0.14964557388781846,0.0933235644062339,0.4989521487033877,0.36998389951391125,0.3596995255505418,0.28255612458504104,0.47433230714309577,0.582717611885115,0.5583471272831956,0.3774834583672073,0.5745237228308702,0.4520020314854228,0.26613992878627296,0.42462850121512585,0.23495816664251418,0.07911614440308362,-0.19240104306059835,-0.3140457170929614,-0.36616599597514327,-0.3686873180075821,0.02344058601667641,-0.18022404692363797,-0.28426445071952483,-0.04129531242547245,0.36433327187168135,0.23536502268220488,0.22508064871883543,0.14793724775333467,0.4895389809923105,0.5979242857343297,0.5735538011324103,0.39269013221642207,0.5897303966800849,0.46720870533463754,0.2813466026354877,0.4398351750643406,0.09432281825229837,-0.1771943692113836,-0.29883904324374666,-0.3509593221259285,-0.35348064415836733,0.038647259865891154,-0.1650173730744232,-0.2690577768703101,-0.026088638576257706,0.3795399457208961,0.25057169653141964,0.2402873225680502,0.16314392160254942,0.33369695875287997,0.44208226349489915,0.4177117788929797,0.23684810997699152,0.4338883744406543,0.311366683095207,0.1255045803960571,0.28399315282491006,-0.33303639145081415,-0.4546810654831772,-0.5068013443653591,-0.5093226663977979,-0.11719476237353942,-0.32085939531385377,-0.42489979910974063,-0.18193066081568826,0.22369792348146555,0.09472967429198907,0.0844453003286196,0.007301899363118841,0.21328550192432388,0.32167080666634307,0.29730032206442364,0.11643665314843543,0.3134769176120982,0.1909552262666509,0.005093123567501051,0.16358169599635397,-0.45344784827937024,-0.5750925223117334,-0.6272128011939151,-0.629734123226354,-0.2376062192020955,-0.44127085214240985,-0.5453112559382967,0.10328646665290947,-0.025681782536567,-0.035966156499936466,-0.11310955746543723,-0.029683636369728483,0.0787016683722907,0.05433118377037127,-0.12653248514561694,0.07050777931804586,-0.052013912027401465,-0.23787601472655132,-0.0793874422976984,-0.6964169865734227,-0.8180616606057857,-0.8701819394879675,-0.8727032615204063,-0.4805753574961479,-0.6842399904364622,-0.1396826716411429,-0.26865092083061937,-0.2789352947939888,-0.3560786957594896,0.07435676742615838,0.18274207216817756,0.15837158756625813,-0.022492081349730075,0.17454818311393272,0.052026491768485394,-0.13383561093066446,0.024652961498188464,-0.5923765827775358,-0.7140212568098988,-0.7661415356920807,-0.7686628577245195,-0.376534953700261,-0.03564226784525604,-0.1646105170347325,-0.17489489099810196,-0.2520382919636027,0.8291045371806665,0.9374898419226856,0.9131193573207662,0.732255688404778,0.8067742615229935,0.6209121588238437,0.7794007312526965,0.16237118697697234,0.04072651294460927,-0.011393765937572575,-0.013915087970011397,0.37821281605424706,0.719105501909252,0.5901372527197756,0.5798528787564061,0.5027094777909054,0.2780214003664727,0.38640670510849195,0.36203622050657247,0.1811725515905843,0.25569112470879973,0.06982902200964991,0.22831759443850283,-0.38871194983722135,-0.5103566238695845,-0.5624769027517663,-0.5649982247842051,0.16802236509505833,0.03905411590558186,0.028769741942212393,-0.04837365902328837,0.4796614630686318,0.5880467678106509,0.5636762832087315,0.3828126142927433,0.4573311874109588,0.2714690847118089,0.42995765714066186,-0.18707188713506234,-0.3087165611674254,-0.36083684004960725,-0.3633581620820461,0.36966242779721736,0.2406941786077409,0.15326640367887065,-0.11158518162534692,-0.0031998768833277347,-0.027570361485247163,-0.20843403040123537,-0.1339154572830199,-0.3197775599821697,-0.16128898755331683,-0.7783185318290411,-0.8999632058614041,-0.9546048067760248,-0.22158421689676133,-0.3505524660862378,-0.437980241015108,0.402518062103131,0.5109033668451501,0.48653288224323077,0.30566921332724256,0.38018778644545803,0.19432568374630815,0.3528142561751611,-0.2642152881005631,-0.38585996213292617,-0.44050156304754684,0.2925190268317166,0.16355077764224013,0.5207207431360693,0.6291060478780884,0.6047355632761691,0.4238718943601808,0.4983904674783963,0.47101693720809934,-0.14601260706762484,-0.2676572810999879,-0.32229888201460855,0.4107217078646549,0.2817534586751784,0.48994583703200123,0.5983311417740205,0.573960657172101,0.3930969882561128,0.46761556137432825,0.4402420311040313,-0.1767875131716929,-0.29843218720405595,-0.3530737881186766,0.3799468017605868,0.7065828458352191,0.8149681505772384,0.7905976659753189,0.6097339970593307,0.6568790399072493,0.03984949563152501,-0.08179517840083805,-0.13643677931545872,0.5965838105638047,0.6189140862214777,0.7272993909634968,0.7029289063615775,0.5220652374455892,0.5692102802935077,-0.04781926398221642,-0.16946393801457948,-0.22410553892920015,-0.11410650365778574,-0.005721198915766557,-0.030091683517685985,-0.2109553524336742,-0.16381030958575565,-0.7808398538614798,-0.9024845278938429,0.6792093155649221,0.7875946203069414,0.763224135705022,0.5823604667890337,0.01247596536122808,-0.10916870867113498,0.6320642727170036,0.7404495774590228,0.7160790928571035,-0.03466907748669046,-0.15631375151905352,0.8372984262349112,0.8129279416329919,0.062179771289197994,-0.05946490274316507,0.04892040199885411,0.024549917396934684,-0.7261982529468591,0.9213132463750111,0.14619459142929775,0.17056507603121718],"y":[-0.6592942333970965,-0.4044725214256986,-0.5438570831028576,-0.5076841657626106,-0.24020391607654024,-0.15875501959951976,-0.3414225052272507,-0.3221974584358207,-0.6188656198215441,-0.7953465444147094,-0.7530304674306787,-0.8048245648543064,-0.744302695125088,-0.6031100406938067,-0.4768440008927537,-0.38061193629036527,-0.4606544996478108,-0.15937424928141475,-0.31303908993131074,0.04033092582932646,0.10654910223647568,-0.0010461464675798338,0.17853144831119833,0.056271839179579675,-0.07522101565007175,0.0806785783400295,0.18584953651090996,-0.07049104720084196,-0.1962512666901507,-0.15609535361337282,-0.2857298940470278,-0.18708866003228922,0.06773305193910863,-0.07165150973805037,-0.03547859239780335,0.232001657288267,0.3134505537652875,0.13078306813755655,0.15000811492898655,-0.14666004645673683,-0.32314097104990214,-0.2808248940658714,-0.33261899148949914,-0.2720971217602808,-0.13090446732899944,-0.004638427527946437,0.09159363707444196,0.01155107371699643,0.31283132408339254,0.15916648343349651,0.5125364991941337,0.5787546756012829,0.47115942689722745,0.6507370216760056,0.528477412544387,0.3969845577147355,0.5528841517048367,0.6580551098757172,0.4017145261639653,0.2759543066746566,0.18647567931777945,-0.5078373073116701,-0.25301559534027224,-0.39240015701743125,-0.3562272396771842,-0.08874698999111387,-0.0072980935140933845,-0.18996557914182433,-0.17074053235039433,-0.4674086937361177,-0.643889618329283,-0.6015735413452523,-0.65336763876888,-0.5928457690396616,-0.4516531146083803,-0.22915501020493892,-0.3091975735623844,-0.007917323195988368,-0.16158216384588436,0.19178785191475284,0.25800602832190206,0.15041077961784655,0.3299883743966247,0.20772876526500605,0.07623591043535463,0.23213550442545589,0.33730646259633634,0.08096587888458442,-0.044794340604724314,-0.13427296796160143,-0.6341033471127231,-0.37928163514132524,-0.5186661968184842,-0.4824932794782372,-0.21501302979216685,-0.13356413331514638,-0.3162316189428773,-0.2970065721514473,-0.5936747335371707,-0.770155658130336,-0.7278395811463052,-0.779633678569933,-0.7191118088407147,-0.3554210500059919,-0.4354636133634374,-0.13418336299704137,-0.28784820364693736,0.06552181211369984,0.13173998852084906,0.024144739816793548,0.2037223345955717,0.08146272546395306,-0.05003012936569837,0.10586946462440289,0.21104042279528334,-0.045300160916468574,-0.1710603804057773,-0.26053900776265443,-0.10148435361975836,0.15333735835163947,0.013952796674480489,0.05012571401472751,0.31760596370079786,0.3990548601778183,0.2163873745500874,0.23561242134151741,-0.06105574004420597,-0.2375366646373713,-0.19522058765334052,-0.2470146850769683,-0.1864928153477499,0.17719794348697282,0.09715538012952729,0.39843563049592334,0.24477078984602738,0.5981408056066646,0.6643589820138138,0.5567637333097583,0.7363413280885365,0.6140817189569178,0.48258886412726637,0.6384884581173677,0.743659416288248,0.3615586130871874,0.27207998573031034,-0.7752960015440045,-0.5204742895726066,-0.6598588512497656,-0.6236859339095185,-0.35620568422344817,-0.2747567877464277,-0.45742427337415864,-0.43819922658272864,-0.734867387968452,-0.9113483125616173,-0.8690322355775866,-0.9208263330012143,-0.49661370443727326,-0.5766562677947188,-0.2753760174283227,-0.4290408580782187,-0.07567084231758148,-0.009452665910432256,-0.11704791461448777,0.06252968016429039,-0.05972992896732826,-0.19122278379697968,-0.03532318980687843,0.06984776836400203,-0.31225303483705863,-0.40173166219393575,-0.2272445731090671,0.02757713886233075,-0.11180742281482825,-0.07563450547458123,0.19184574421148914,0.2732946406885096,0.09062715506077867,0.10985220185220868,-0.1868159595335147,-0.36329688412668004,-0.32098080714264926,-0.37277490456627704,0.05143772399766408,-0.028604839359781448,0.27267541100661463,0.11901057035671862,0.47238058611735584,0.538598762524505,0.43100351382044955,0.6105811085992277,0.48832149946760905,0.3568286446379576,0.5127282386280589,0.6178991967989393,0.14631976624100157,-0.3167232004659442,-0.06190148849454637,-0.20128605017170537,-0.16511313283145834,0.10236711685461201,0.1838160133316325,0.0011485277039015515,0.02037357449533156,-0.2762945868903918,-0.45277551148355716,-0.4104594344995264,-0.46225353192315416,-0.038040903359213035,-0.11808346671665856,0.18319678364973752,0.02953194299984151,0.3829019587604787,0.44912013516762794,0.34152488646357243,0.5211024812423506,0.39884287211073194,0.26735001728108054,0.42324961127118177,0.5284205694420623,-0.784023773849595,-0.5292020618781972,-0.6685866235553561,-0.6324137062151092,-0.3649334565290388,-0.28348456005201833,-0.46615204567974927,-0.44692699888831927,-0.7435951602740427,-0.920076084867208,-0.929554105306805,-0.5053414767428639,-0.5853840401003094,-0.2841037897339133,-0.4377686303838093,-0.08439861462317211,-0.018180438216022887,-0.1257756869200784,0.05380190785869976,-0.06845770127291889,-0.19995055610257031,-0.04405096211246906,0.0611199960584114,-0.8358178712732228,-0.580996159301825,-0.720380720978984,-0.6842078036387369,-0.4167275539526666,-0.3352786574756461,-0.517946143103377,-0.49872109631194705,-0.7953892576976704,-0.9718701822908358,-0.5571355741664916,-0.6371781375239371,-0.3358978871575411,-0.4895627278074371,-0.1361927120467999,-0.06997453563965067,-0.17756978434370618,0.002007810435071977,-0.12025179869654667,-0.2517446535261981,-0.09584505953609684,0.009325898634783614,-0.6498589262404605,-0.39503721426906263,-0.5344217759462216,-0.4982488586059746,-0.23076860891990425,-0.14931971244288378,-0.3319871980706147,-0.3127621512791847,-0.7859112372580734,-0.3711766291337293,-0.4512191924911748,-0.14993894212477876,-0.30360378277467476,0.049766232985962444,0.11598440939311166,0.008389160689056152,0.1879667554678343,0.06570714633621566,-0.06578570849343576,0.09011388549666549,0.19528484366754595,-0.8263398508336258,-0.571518138862228,-0.710902700539387,-0.6747297831991399,-0.4072495335130696,-0.3258006370360491,-0.50846812266378,-0.48924307587235005,-0.5476575537268946,-0.6277001170843401,-0.3264198667179441,-0.4800847073678401,-0.1267146916072029,-0.06049651520005367,-0.16809176390410918,0.011485830874668979,-0.11077377825694967,-0.2422666330866011,-0.08636703909649984,0.018803919074380615,0.14753814189228193,0.4023598538636798,0.26297529218652077,0.2991482095267678,0.5666284592128381,0.6480773556898587,0.4654098700621277,0.4846349168535577,0.4262204389990131,0.34617787564156755,0.6474581260079637,0.49379328535806766,0.8471633011187049,0.9133814775258541,0.8057862288217985,0.863104214468958,0.7316113596393067,0.8875109536294079,0.9926819118002883,-0.032039452886496234,0.22278225908490162,0.08339769740774261,0.11957061474798963,0.38705086443406,0.4684997609110805,0.28583227528334954,0.30505732207477954,0.24664284422023494,0.1666002808627894,0.4678805312291855,0.3142156905792895,0.6675857063399266,0.7338038827470759,0.6835266196901799,0.5520337648605285,0.7079333588506298,0.8131043170215102,0.07555579581755928,0.33037750778895714,0.19099294611179812,0.22716586345204515,0.4946461131381155,0.576095009615136,0.39342752398740505,0.41265257077883505,0.3542380929242904,0.2741955295668449,0.5754757799332411,0.421810939283345,0.7751809550439822,0.7911218683942354,0.659629013564584,0.8155286075546853,0.9206995657255657,-0.27119722249545664,-0.016375510524058806,-0.1557600722012178,-0.11958715486097078,0.22934199130212007,0.04667450567438911,0.06589955246581912,0.007485074611274525,-0.072557488746171,0.2287227616202251,0.07505792097032907,0.4284279367309663,0.4443688500812195,0.31287599525156806,0.46877558924166934,0.5739465474125498,0.009337619410410058,0.2641593313818079,0.1247747697046489,0.16094768704489593,0.5098768332079868,0.3272093475802558,0.3464343943716858,0.2880199165171412,0.2079773531596957,0.5092576035260918,0.3555927628761958,0.7249036919870862,0.5934108371574348,0.749310431147536,0.8544813893184164,0.049685271921113106,0.30450698389251096,0.16512242221535195,0.20129533955559897,0.5502244857186898,0.3675570000909589,0.3867820468823889,0.32836756902784425,0.24832500567039875,0.5496052560367948,0.39594041538689884,0.7652513444977893,0.6337584896681379,0.8948290418291196,-0.19036755570033115,0.0644541562710667,-0.0749304054060923,-0.03875748806584528,0.31017165809724556,0.12750417246951462,0.14672921926094462,0.08831474140640003,0.008272178048954498,0.15588758776545458,0.525198516876345,0.39370566204669355,0.6547762142076753,0.15485623009199356,0.4096779420633914,0.2702933803862324,0.30646629772647943,0.6553954438895703,0.47272795826183933,0.49195300505326933,0.43353852719872477,0.35349596384127924,0.5011113735577792,0.8704223026686697,0.7389294478390183,-0.3724158116461671,-0.11759409967476928,-0.25697866135192826,-0.22080574401168124,0.1281234021514096,-0.03531903668489134,-0.09373351453943593,-0.17377607789688146,-0.026160668180381392,0.34315026093050904,0.21165740610085762,-0.10621432206898815,0.14860738990240968,0.009222828225250695,0.04539574556549772,0.39432489172858853,0.23088245289228762,0.17246797503774303,0.0924254116802975,0.24004082139679758,0.609351750507688,-0.18974832601843616,0.06507338595296168,-0.07431117572419732,-0.038138258383950296,0.1473484489428396,0.08893397108829501,0.008891407730849482,0.15650681744734957,0.52581774655824,0.025278532760663275,0.28010024473206113,0.14071568305490212,0.17688860039514914,0.36237530772193904,0.3039608298673945,0.22391826650994892,0.371533676226449,-0.34403239635022714,-0.08921068437882931,-0.2285952460559883,-0.19242232871574128,-0.006935621388951383,-0.06535009924349598,-0.1453926626009415,-0.3531907648547371,-0.09836905288333926,-0.23775361456049826,-0.20158069722025124,-0.07450846774800593,-0.15455103110545146,-0.5386774721815271,-0.28385576021012915,-0.42324032188728816,-0.25999517507479586,-0.3400377384322414,-0.435465827844615,-0.574850389521774,-0.41160524270928167,-0.4916478060667272,-0.2368260940953294,-0.37621065577248836,-0.21296550895999605,-0.3200286775503762,-0.2961680924150428,-0.15678353073788387],"type":"scatter"},{"hoverinfo":"none","marker":{"cmax":1,"cmin":0,"color":[0.5],"colorbar":{"outlinewidth":0,"thickness":15,"ticktext":["3","6","14"],"tickvals":[0.16666666666666666,0.5,0.8333333333333334],"title":{"text":"Games Played"},"xanchor":"left"},"colorscale":[[0.0,"rgb(247,251,255)"],[0.3333333333333333,"rgb(247,251,255)"],[0.3333333333333333,"rgb(107,174,214)"],[0.6666666666666666,"rgb(107,174,214)"],[0.6666666666666666,"rgb(8,48,107)"],[1.0,"rgb(8,48,107)"]],"showscale":true},"mode":"markers","x":[null],"y":[null],"type":"scatter"},{"hoverinfo":"text","hovertext":["Team: POR","Team: SF","Team: SEA","Team: ATH","Team: LAD","Team: LAA","Team: SD","Team: ARI","Team: COL","Team: TEX","Team: HOU","Team: KC","Team: MIN","Team: STL","Team: MIL","Team: CWS","Team: CHC","Team: NSH","Team: CIN","Team: ATL","Team: DET","Team: TB","Team: CLE","Team: MIA","Team: PIT","Team: TOR","Team: WSH","Team: BAL","Team: PHI","Team: NYY","Team: NYM","Team: BOS"],"marker":{"color":"rgba(255, 255, 255, 0)","size":35},"mode":"markers","x":[-0.1293902629132215,-0.0676874162160826,-0.024915665060014594,-0.46029700869829177,-0.4325415528388654,-0.38073799801552943,-0.6318521606313038,-0.2934296191835501,0.48898924645671216,0.21975149279329945,0.25016484049172893,-0.061519203987132204,-0.30234211764424435,-0.7882803942323491,-0.5801995866405754,0.9292959528684408,-0.17287032075994663,0.2304098046443714,-0.952083484743586,0.07612300271336989,0.31252836477924645,0.25097855257111035,0.6842525701775461,0.5089150509500633,-0.9571261288084636,0.6295055096369523,0.5352154239411152,0.7289131214928921,-0.8478429269792223,0.8969427617730916,-0.6045535789144961,0.9456837309769305],"y":[-0.6283009269781801,0.31611021975143444,-0.3253870748073273,-0.5779191544094333,0.48731883257649616,-0.860304463271996,0.23579839359787869,0.056841138884124454,-0.8777600078831772,-0.9813482027304328,-0.6094303126649081,-0.9623921618512388,0.9853638236005767,0.6262086340430204,0.8413991314511314,0.14789309482509957,0.708962778636833,0.7896580836582391,0.3095524284153506,1.0,-0.05454408347632135,0.4778588956780366,0.31079088777914055,0.7408446053373394,0.00222274711555857,-0.016093989893461336,-0.38706740454704114,-0.6902875398160129,-0.2930080723174416,-0.4594132392275352,-0.13292294560255052,-0.1806441158732172],"type":"scatter"}],                        {"height":600,"hovermode":"closest","images":[{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fa\u002fa6\u002fMajor_League_Baseball_logo.svg","x":-0.1293902629132215,"xanchor":"center","xref":"x","y":-0.6283009269781801,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002f5\u002f58\u002fSan_Francisco_Giants_Logo.svg","x":-0.0676874162160826,"xanchor":"center","xref":"x","y":0.31611021975143444,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002f6\u002f6d\u002fSeattle_Mariners_logo_%28low_res%29.svg","x":-0.024915665060014594,"xanchor":"center","xref":"x","y":-0.3253870748073273,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fthumb\u002fb\u002fb8\u002fAthletics_logo.svg\u002f330px-Athletics_logo.svg.png","x":-0.46029700869829177,"xanchor":"center","xref":"x","y":-0.5779191544094333,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f0\u002f0e\u002fLos_Angeles_Dodgers_Logo.svg","x":-0.4325415528388654,"xanchor":"center","xref":"x","y":0.48731883257649616,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f8\u002f8b\u002fLos_Angeles_Angels_of_Anaheim.svg","x":-0.38073799801552943,"xanchor":"center","xref":"x","y":-0.860304463271996,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fthumb\u002fe\u002fe2\u002fSD_Logo_Brown.svg\u002f250px-SD_Logo_Brown.svg.png","x":-0.6318521606313038,"xanchor":"center","xref":"x","y":0.23579839359787869,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fthumb\u002fa\u002fac\u002fArizona_Diamondbacks_logo_teal.svg\u002f330px-Arizona_Diamondbacks_logo_teal.svg.png","x":-0.2934296191835501,"xanchor":"center","xref":"x","y":0.056841138884124454,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002fc\u002fc0\u002fColorado_Rockies_full_logo.svg","x":0.48898924645671216,"xanchor":"center","xref":"x","y":-0.8777600078831772,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fc\u002fc7\u002fTexas_Rangers_logo.svg","x":0.21975149279329945,"xanchor":"center","xref":"x","y":-0.9813482027304328,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f6\u002f6b\u002fHouston-Astros-Logo.svg","x":0.25016484049172893,"xanchor":"center","xref":"x","y":-0.6094303126649081,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f7\u002f78\u002fKansas_City_Royals_Primary_Logo.svg","x":-0.061519203987132204,"xanchor":"center","xref":"x","y":-0.9623921618512388,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fthumb\u002f1\u002f17\u002fMinnesota_Twins_New_Logo.svg\u002f250px-Minnesota_Twins_New_Logo.svg.png","x":-0.30234211764424435,"xanchor":"center","xref":"x","y":0.9853638236005767,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002f9\u002f9d\u002fSt._Louis_Cardinals_logo.svg","x":-0.7882803942323491,"xanchor":"center","xref":"x","y":0.6262086340430204,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002fb\u002fb8\u002fMilwaukee_Brewers_logo.svg","x":-0.5801995866405754,"xanchor":"center","xref":"x","y":0.8413991314511314,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fc\u002fc1\u002fChicago_White_Sox.svg","x":0.9292959528684408,"xanchor":"center","xref":"x","y":0.14789309482509957,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f8\u002f80\u002fChicago_Cubs_logo.svg","x":-0.17287032075994663,"xanchor":"center","xref":"x","y":0.708962778636833,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fa\u002fa6\u002fMajor_League_Baseball_logo.svg","x":0.2304098046443714,"xanchor":"center","xref":"x","y":0.7896580836582391,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f0\u002f01\u002fCincinnati_Reds_Logo.svg","x":-0.952083484743586,"xanchor":"center","xref":"x","y":0.3095524284153506,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002ff\u002ff2\u002fAtlanta_Braves.svg","x":0.07612300271336989,"xanchor":"center","xref":"x","y":1.0,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fe\u002fe3\u002fDetroit_Tigers_logo.svg","x":0.31252836477924645,"xanchor":"center","xref":"x","y":-0.05454408347632135,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f5\u002f55\u002fTampa_Bay_Rays_Logo.svg","x":0.25097855257111035,"xanchor":"center","xref":"x","y":0.4778588956780366,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002fa\u002fa9\u002fGuardians_winged_%22G%22.svg","x":0.6842525701775461,"xanchor":"center","xref":"x","y":0.31079088777914055,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002ff\u002ffd\u002fMarlins_team_logo.svg","x":0.5089150509500633,"xanchor":"center","xref":"x","y":0.7408446053373394,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002f8\u002f81\u002fPittsburgh_Pirates_logo_2014.svg","x":-0.9571261288084636,"xanchor":"center","xref":"x","y":0.00222274711555857,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002fc\u002fcc\u002fToronto_Blue_Jay_Primary_Logo.svg","x":0.6295055096369523,"xanchor":"center","xref":"x","y":-0.016093989893461336,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fa\u002fa3\u002fWashington_Nationals_logo.svg","x":0.5352154239411152,"xanchor":"center","xref":"x","y":-0.38706740454704114,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002fe\u002fe9\u002fBaltimore_Orioles_Script.svg","x":0.7289131214928921,"xanchor":"center","xref":"x","y":-0.6902875398160129,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002ff\u002ff0\u002fPhiladelphia_Phillies_%282019%29_logo.svg","x":-0.8478429269792223,"xanchor":"center","xref":"x","y":-0.2930080723174416,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fcommons\u002ff\u002ffe\u002fNew_York_Yankees_Primary_Logo.svg","x":0.8969427617730916,"xanchor":"center","xref":"x","y":-0.4594132392275352,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002fthumb\u002f7\u002f7b\u002fNew_York_Mets.svg\u002f250px-New_York_Mets.svg.png","x":-0.6045535789144961,"xanchor":"center","xref":"x","y":-0.13292294560255052,"yanchor":"middle","yref":"y"},{"layer":"above","sizex":0.15222478878283152,"sizey":0.15850785621843463,"source":"https:\u002f\u002fupload.wikimedia.org\u002fwikipedia\u002fen\u002f6\u002f6d\u002fRedSoxPrimary_HangingSocks.svg","x":0.9456837309769305,"xanchor":"center","xref":"x","y":-0.1806441158732172,"yanchor":"middle","yref":"y"}],"margin":{"b":20,"l":5,"r":5,"t":60},"showlegend":false,"title":{"text":"\u003cbr\u003eMLB 32-Team Expansion Simulation"},"width":800,"xaxis":{"showgrid":false,"showticklabels":false,"zeroline":false},"yaxis":{"showgrid":false,"showticklabels":false,"zeroline":false},"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}}},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('48911430-7419-4b0d-834a-44fbeaf9bb85');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
<p>Interactive Graph Network of Simulated 32-Team MLB Schedule</p>
</div>
</div>
<p>The main advantage to this approach is that it allows for a more flexible and dynamic scheduling system, accommodating the unique needs and rivalries of the expanded league. By leveraging graph theory, we can better understand the relationships between teams and optimize the scheduling process for fairness and competitiveness.</p>
<p>This realignment places a greater emphasis on regional rivalries and travel considerations, potentially leading to a more engaging and balanced competition. I am personally a strong proponent of getting Portland a MLB team. Portland having a team would drastically cut down on the travel time for the Seattle Mariners. In addition, a Portland team would play into the already existing rivalry with Seattle. Just look at <a href="https://nikeborderclash.runnerspace.com/">Border Clash</a>, a regional cross country race that highlights the competitive spirit between these two cities - moreover states.</p>
<p>Nashville makes too much sense in terms of breaking up Atlanta’s stranglehold on the Southeast. With a team in Nashville, we could see some exciting matchups and rivalries emerge, particularly with the Atlanta Braves and the Cincinnati Reds. The geographic diversity would also help to balance the league and create a more dynamic schedule. Although, I could see the case for a team in Charlotte as well.</p>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>In the end, what is the Major League Baseball schedule? It’s a historical document, a 162-game compromise cobbled together by tradition, television contracts, and the brute force of geography. It works because it’s always worked. But when you strip away the nostalgia and the seventy-five-dollar parking, when you look at it not as a list of games but as a network, you’re left with a simple mathematical object: a graph.</p>
<p>And like any system, once you see its underlying structure, you can’t help but notice the flaws. They’re no longer just quirks; they’re inefficiencies. The Seattle Mariners’ travel woes aren’t just a logistical headache; on the graph, they’re a grotesquely long edge stretching across half the country, a screamingly obvious point of imbalance. Adding a team in Portland doesn’t just create a fun rivalry; it shortens that edge, creating a tighter, more rational cluster of nodes in the Pacific Northwest. The same goes for Nashville, a move that doesn’t just tap a new market but breaks up the Braves’ regional monopoly, forging new, logical connections in the Southeast.</p>
<p>This is the power of looking at the world through a different lens. It transforms the debate from one of pure opinion—“I think this city deserves a team!”—into a problem of optimization. You’re no longer just adding dots to a map; you’re balancing a network, minimizing the distance between nodes, and engineering more compelling matchups by strengthening local connections. The old men who run baseball can spend the next decade debating expansion in conference rooms, arguing over demographics and media rights. Or they could just run the algorithm. After all, the best path forward is often the shortest one… although Mike Piazza would disagree.</p>
<iframe src="https://streamable.com/m/clemens-throws-bat-c20053773?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<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>Past articles: - <a href="https://runningonnumbers.com/posts/principal-component-analysis-python-baseball/">Principal Component Analysis</a> - <a href="https://runningonnumbers.com/posts/support-vector-machine/">Support Vector Machine</a> - <a href="https://runningonnumbers.com/posts/k-means/">K-Means Clustering</a> Github: - <a href="https://github.com/oliverc1623/Running-On-Numbers-Public">Running on Numbers</a></p>
</div>
</div>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->

</section>

 ]]></description>
  <category>MLB</category>
  <category>graph theory</category>
  <category>data visualization</category>
  <guid>https://runningonnumbers.com/posts/mlb-realignment-graph-theory/</guid>
  <pubDate>Thu, 04 Sep 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/mlb-realignment-graph-theory/main.png" medium="image" type="image/png" height="96" width="144"/>
</item>
<item>
  <title>Principal Component Analysis Explained: A Practical Example with MLB Data in Python</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/principal-component-analysis-python-baseball/</link>
  <description><![CDATA[ 





<iframe src="https://streamable.com/m/cade-horton-in-play-out-s-to-taylor-ward?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>Principal component analysis (PCA) applied to Pete Crow-Armstrong. I am willing to bet that every data scientist in an MLB organization has thought of this pun at least once. For good reason: PCA is a powerful tool for dimensionality reduction and feature extraction. In this post, I will walk through the steps of performing PCA on a dataset of Pete Crow-Armstrong’s game-by-game statistics from the 2025 MLB season. Let’s dig into some formalities.</p>
<section id="understanding-pca---the-methodology" class="level3">
<h3 class="anchored" data-anchor-id="understanding-pca---the-methodology">Understanding PCA - the Methodology</h3>
<p>To first understand why PCA is useful, we need to understand the <a href="https://en.wikipedia.org/wiki/Curse_of_dimensionality">curse of dimensionality</a>. Observe Table&nbsp;1 which shows the exponential growth of possible values with binary variables.</p>
<div id="tbl-exp" 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-exp-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Exponential Growth of Possible Values with Binary Variables
</figcaption>
<div aria-describedby="tbl-exp-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<table class="caption-top table">
<thead>
<tr class="header">
<th>n</th>
<th>Possible Values</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1</td>
<td><img src="https://latex.codecogs.com/png.latex?2%5E1%20=%202"></td>
</tr>
<tr class="even">
<td>2</td>
<td><img src="https://latex.codecogs.com/png.latex?2%5E2%20=%204"></td>
</tr>
<tr class="odd">
<td>3</td>
<td><img src="https://latex.codecogs.com/png.latex?2%5E3%20=%208"></td>
</tr>
<tr class="even">
<td>…</td>
<td>…</td>
</tr>
<tr class="odd">
<td>10</td>
<td><img src="https://latex.codecogs.com/png.latex?2%5E%7B10%7D%20=%201024"></td>
</tr>
<tr class="even">
<td>20</td>
<td><img src="https://latex.codecogs.com/png.latex?2%5E%7B20%7D%20=%201,048,576"></td>
</tr>
</tbody>
</table>
</div>
</figure>
</div>
<p>When <img src="https://latex.codecogs.com/png.latex?n=1">, the possible values are 0 or 1. Now, consider a dataset with two binary variables. This dataset can take on four values: (0,0), (0,1), (1,0), and (1,1). As we add more binary variables, the number of possible combinations grows exponentially. For example, with 10 binary variables, there are 1,024 possible combinations. With 20 binary variables, there are 1,048,576 possible combinations. This example illustrates the curse of dimensionality: as the number of dimensions increases, the volume of the space increases so quickly that the available data becomes sparse.</p>
<p>Now consider a dataset with continuous variables for game-by-game statistics. In the statcast era, there are hundreds of <a href="https://www.mlb.com/glossary">statistics</a> available for each player. How do we reduce the number of dimensions while retaining the most important information? PCA transforms the original variables into a new set of variables, called principal components, which are linear combinations of the original variables. The principal components are ordered such that the first component explains the largest amount of variance in the data, the second component explains the second largest amount of variance, and so on. By selecting a subset of the principal components, we can reduce the dimensionality of the data while retaining most of the important information.</p>
<div id="cell-fig-pca-vectors" class="cell" data-execution_count="1">
<details class="code-fold">
<summary>Code</summary>
<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="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-2"><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-3"></span>
<span id="cb1-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> plot_pca_vectors():</span>
<span id="cb1-5">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""</span></span>
<span id="cb1-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    Generates 2D data, calculates PCA, and plots the data points</span></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    with eigenvectors scaled by eigenvalues overlaid.</span></span>
<span id="cb1-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">    """</span></span>
<span id="cb1-9">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- 1. Generate Sample Data ---</span></span>
<span id="cb1-10">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use a random seed for reproducibility</span></span>
<span id="cb1-11">    np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-12">    </span>
<span id="cb1-13">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create 200 data points (n=200) with 2 features (p=2)</span></span>
<span id="cb1-14">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define a mean to shift the data away from the origin</span></span>
<span id="cb1-15">    mean <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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]</span>
<span id="cb1-16">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define a covariance matrix that creates a stretched, diagonal cloud of points</span></span>
<span id="cb1-17">    cov <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 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;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>]] </span>
<span id="cb1-18">    X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.multivariate_normal(mean, cov, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>)</span>
<span id="cb1-19"></span>
<span id="cb1-20">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- 2. Perform PCA Calculations ---</span></span>
<span id="cb1-21">    </span>
<span id="cb1-22">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Step 2a: Calculate the mean of the data</span></span>
<span id="cb1-23">    data_mean <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean(X, 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;">0</span>)</span>
<span id="cb1-24">    </span>
<span id="cb1-25">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Step 2b: Center the data (though not strictly necessary for covariance calculation with np.cov)</span></span>
<span id="cb1-26">    X_centered <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> data_mean</span>
<span id="cb1-27">    </span>
<span id="cb1-28">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Step 2c: Calculate the covariance matrix</span></span>
<span id="cb1-29">    cov_matrix <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.cov(X_centered, rowvar<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="cb1-30">    </span>
<span id="cb1-31">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Step 2d: Calculate eigenvectors and eigenvalues</span></span>
<span id="cb1-32">    eigenvalues, eigenvectors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.eig(cov_matrix)</span>
<span id="cb1-33"></span>
<span id="cb1-34">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- 3. Create the Plot ---</span></span>
<span id="cb1-35">    plt.style.use(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seaborn-v0_8-whitegrid'</span>)</span>
<span id="cb1-36">    fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<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;">5</span>))</span>
<span id="cb1-37"></span>
<span id="cb1-38">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot the original data points</span></span>
<span id="cb1-39">    ax.scatter(X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</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.6</span>, label<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 Points'</span>)</span>
<span id="cb1-40">    </span>
<span id="cb1-41">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot the mean of the data</span></span>
<span id="cb1-42">    ax.scatter(data_mean[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], data_mean[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</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;">'red'</span>, s<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;">150</span>, zorder<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>, label<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="cb1-43"></span>
<span id="cb1-44">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- 4. Plot the Eigenvectors ---</span></span>
<span id="cb1-45">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The eigenvectors are the directions.</span></span>
<span id="cb1-46">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The eigenvalues are the magnitude (variance) in those directions.</span></span>
<span id="cb1-47">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># We scale the vectors by the sqrt of the eigenvalue to represent standard deviation.</span></span>
<span id="cb1-48">    </span>
<span id="cb1-49">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Eigenvalues:"</span>, eigenvalues)</span>
<span id="cb1-50">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Eigenvectors:</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, eigenvectors)</span>
<span id="cb1-51"></span>
<span id="cb1-52">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot each eigenvector as a vector originating from the mean</span></span>
<span id="cb1-53">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(eigenvalues)):</span>
<span id="cb1-54">        eigenvec <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> eigenvectors[:, i]</span>
<span id="cb1-55">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The vector's components are scaled by the sqrt of the eigenvalue</span></span>
<span id="cb1-56">        scaled_vec <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> eigenvec <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.sqrt(eigenvalues[i]) <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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Multiply by 2 for better visibility</span></span>
<span id="cb1-57">        </span>
<span id="cb1-58">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use ax.quiver to draw an arrow</span></span>
<span id="cb1-59">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The arguments are: start_x, start_y, direction_x, direction_y</span></span>
<span id="cb1-60">        ax.quiver(data_mean[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], data_mean[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], scaled_vec[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], scaled_vec[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb1-61">                  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;">'g'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> i <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="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'m'</span>, <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Different colors for PC1 and PC2</span></span>
<span id="cb1-62">                  angles<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;">'xy'</span>, scale_units<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;">'xy'</span>, scale<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-63">                  width<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-64">                  label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<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 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="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>eigenvalues[i]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)'</span>)</span>
<span id="cb1-65"></span>
<span id="cb1-66">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- 5. Finalize the Plot ---</span></span>
<span id="cb1-67">    ax.set_aspect(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'equal'</span>, adjustable<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;">'box'</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Ensures vectors that are orthogonal appear at 90 degrees</span></span>
<span id="cb1-68">    ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Scatter Plot of Data with PCA Eigenvectors'</span>, fontsize<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;">16</span>)</span>
<span id="cb1-69">    ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Feature 1'</span>, fontsize<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;">12</span>)</span>
<span id="cb1-70">    ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Feature 2'</span>, fontsize<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;">12</span>)</span>
<span id="cb1-71">    ax.legend()</span>
<span id="cb1-72">    ax.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb1-73">    plt.show()</span>
<span id="cb1-74"></span>
<span id="cb1-75"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Run the function</span></span>
<span id="cb1-76">plot_pca_vectors()</span></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>Eigenvalues: [0.9302595  8.25726304]
Eigenvectors:
 [[-0.71461768 -0.69951524]
 [ 0.69951524 -0.71461768]]</code></pre>
</div>
<div class="cell-output cell-output-display">
<div id="fig-pca-vectors" class="quarto-float quarto-figure quarto-figure-center anchored" alt="A scatter plot with two eigenvectors overlaid.">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-pca-vectors-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/principal-component-analysis-python-baseball/index_files/figure-html/fig-pca-vectors-output-2.png" alt="A scatter plot with two eigenvectors overlaid." width="453" height="449" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-pca-vectors-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Scatter Plot of Data with PCA Eigenvectors
</figcaption>
</figure>
</div>
</div>
</div>
<p>Let <img src="https://latex.codecogs.com/png.latex?X"> be an <img src="https://latex.codecogs.com/png.latex?n%20%5Ctimes%20p"> data matrix, where <img src="https://latex.codecogs.com/png.latex?n"> is the number of observations and <img src="https://latex.codecogs.com/png.latex?p"> is the number of variables. PCA finds a vector <img src="https://latex.codecogs.com/png.latex?w"> such that the projection of the data onto <img src="https://latex.codecogs.com/png.latex?w"> maximizes the variance; <img src="https://latex.codecogs.com/png.latex?w"> are the principal components. We’re mapping the original data to a new coordinates <img src="https://latex.codecogs.com/png.latex?t">. So a data point <img src="https://latex.codecogs.com/png.latex?x_i"> maps to <img src="https://latex.codecogs.com/png.latex?t_i"> by finding <img src="https://latex.codecogs.com/png.latex?x_i%20%5Cdot%20w_k">. Since we’re dealing with matrices, we can express this transformation as <img src="https://latex.codecogs.com/png.latex?T=XW">, resulting in a new <img src="https://latex.codecogs.com/png.latex?n%5Ctimes%20k"> matrix which is more compact than <img src="https://latex.codecogs.com/png.latex?X">. How is <img src="https://latex.codecogs.com/png.latex?W"> found? We use <a href="https://en.wikipedia.org/wiki/Eigendecomposition_of_a_matrix">eigendecomposition</a>. Observe Figure&nbsp;1 which shows the original data and the principal components. We are treading in linear algebra territory, and, admittedly, its been several years since I took linear algebra, so I encourage you all to read the wikipedia page. This is exactly that computer science majors mean when they say “linear algebra is a useful math course”.</p>
</section>
</section>
<section id="understanding-pca---the-player" class="level2">
<h2 class="anchored" data-anchor-id="understanding-pca---the-player">Understanding PCA - the Player</h2>
<p>Let’s start by looking at the data. We will use Pete Crow-Armstrong’s game-by-game statistics from the 2025 MLB season. The data is sourced from <a href="https://baseballsavant.mlb.com/statcast_search?hfPT=&amp;hfAB=&amp;hfGT=R%7C&amp;hfPR=&amp;hfZ=&amp;hfStadium=&amp;hfBBL=&amp;hfNewZones=&amp;hfPull=&amp;hfC=&amp;hfSea=2025%7C&amp;hfSit=&amp;player_type=batter&amp;hfOuts=&amp;hfOpponent=&amp;pitcher_throws=&amp;batter_stands=&amp;hfSA=&amp;game_date_gt=&amp;game_date_lt=&amp;hfMo=&amp;hfTeam=&amp;home_road=&amp;hfRO=&amp;position=&amp;hfInfield=&amp;hfOutfield=&amp;hfInn=&amp;hfBBT=&amp;batters_lookup%5B%5D=691718&amp;hfFlag=&amp;metric_1=&amp;group_by=name-date&amp;min_pitches=0&amp;min_results=0&amp;min_pas=0&amp;sort_col=pitches&amp;player_event_sort=api_p_release_speed&amp;sort_order=desc&amp;chk_stats_ba=on&amp;chk_stats_xba=on&amp;chk_stats_obp=on&amp;chk_stats_xobp=on&amp;chk_stats_slg=on&amp;chk_stats_xslg=on&amp;chk_stats_woba=on&amp;chk_stats_xwoba=on&amp;chk_stats_barrels_total=on&amp;chk_stats_iso=on&amp;chk_stats_swing_miss_percent=on&amp;chk_stats_launch_speed=on&amp;chk_stats_launch_angle=on&amp;chk_stats_bbdist=on&amp;chk_stats_hardhit_percent=on&amp;chk_stats_barrels_per_pa_percent=on&amp;chk_stats_sweetspot_speed_mph=on&amp;chk_stats_attack_angle=on&amp;chk_stats_swing_length=on&amp;chk_stats_attack_direction=on&amp;chk_stats_swing_path_tilt=on&amp;chk_stats_rate_ideal_attack_angle=on&amp;chk_stats_intercept_ball_minus_batter_pos_x_inches=on&amp;chk_stats_intercept_ball_minus_batter_pos_y_inches=on#results">Baseball Savant’s</a> search tool. The query I used grabs traditional statistics, expected statistics, and swing mechanic statistics. This <a href="https://youtu.be/E4z2LUJRLJ4?si=GqgBERMszgsyilO9">video</a> also serves as good tutorial for understanding how to use PCA (he also uses Pete Crow-Armstrong as an example). Some of my results below are inspired by this video but all code, analysis, and visualizations are my own. We also expand upon his analysis by including statcast metrics.</p>
<div class="callout callout-style-default callout-tip 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">
Tip
</div>
</div>
<div class="callout-body-container callout-body">
<p>You can either download the results (middle icon) with your query from the search tool as a CSV file or the entire data (right icon) prior to any filtering on baseball savant. <img src="https://runningonnumbers.com/posts/principal-component-analysis-python-baseball/Screenshot 2025-08-24 at 2.17.14 PM.png" class="img-fluid"></p>
</div>
</div>
<div id="e6b04e34" class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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 class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> pybaseball <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> statcast_batter</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> pybaseball <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> playerid_lookup</span>
<span id="cb3-3"><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="cb3-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb3-5">sns.set_theme(style<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;">"whitegrid"</span>, palette<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;">"pastel"</span>)</span>
<span id="cb3-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.decomposition <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PCA</span>
<span id="cb3-7"><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> StandardScaler</span>
<span id="cb3-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> stats</span>
<span id="cb3-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> factor_analyzer.rotator <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Rotator</span>
<span id="cb3-10"></span>
<span id="cb3-11">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"savant_data.csv"</span>)</span>
<span id="cb3-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Number of columns: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(df.columns.to_list())<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></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>Number of columns: 78</code></pre>
</div>
</div>
<p>The original data contains 78 columns. Our goal is to reduce this to fewer than 10 columns. It would be impractical to plot scatter plots for every pair of variables to find correlations. Instead, let’s use a heatmap to visualize the correlations between the variables, as shown in Figure&nbsp;2.</p>
<div id="cell-fig-heatmap" class="cell" data-execution_count="3">
<details class="code-fold">
<summary>Code</summary>
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># select relevant features</span></span>
<span id="cb5-2">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;">"ba"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"iso"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"slg"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"woba"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xwoba"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xba"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hits"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"launch_speed"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"launch_angle"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"velocity"</span>, </span>
<span id="cb5-3">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"whiffs"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bat_speed"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"swing_length"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"singles"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"doubles"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"triples"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hrs"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"so"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bb"</span>,</span>
<span id="cb5-4">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"obp"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrels_total"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xobp"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xslg"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"attack_angle"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"attack_direction"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"swing_path_tilt"</span>,</span>
<span id="cb5-5">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rate_ideal_attack_angle"</span>]</span>
<span id="cb5-6">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[features]</span>
<span id="cb5-7">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.dropna()</span>
<span id="cb5-8">scaler <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler()</span>
<span id="cb5-9">X_scaled <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> scaler.fit_transform(X)</span>
<span id="cb5-10"></span>
<span id="cb5-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># heatmap</span></span>
<span id="cb5-12">corr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.corr()</span>
<span id="cb5-13">mask <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.triu(np.ones_like(corr, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">bool</span>))</span>
<span id="cb5-14">f, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<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>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>))</span>
<span id="cb5-15">cmap <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sns.diverging_palette(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">230</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, as_cmap<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="cb5-16">sns.heatmap(corr, mask<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>mask, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>cmap, vmax<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.0</span>, center<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="cb5-17">            square<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>, linewidths<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;">.5</span>, cbar_kws<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;">"shrink"</span>: <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">.5</span>})</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-heatmap" class="quarto-float quarto-figure quarto-figure-center anchored" alt="A heatmap showing correlations.">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-heatmap-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/principal-component-analysis-python-baseball/index_files/figure-html/fig-heatmap-output-1.png" alt="A heatmap showing correlations." width="794" height="706" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-heatmap-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Pete Crow-Armstrong’s 2025 Game-by-Game Statistics Correlation Heatmap
</figcaption>
</figure>
</div>
</div>
</div>
<p>Observe how some variables, such as <code>slg</code>, <code>woba</code>, and <code>xwoba</code>, are highly correlated. Meanwhile, variables like strikeouts and whiffs show weaker or even opposite correlations with these metrics. If we were to plug this entire dataset into a regression model, such as <a href="https://runningonnumbers.com/posts/ops-linear-regression/">linear regression</a>, we might run into issues with <a href="https://en.wikipedia.org/wiki/Multicollinearity">multicollinearity</a>.</p>
<section id="performing-pca-with-two-components" class="level3">
<h3 class="anchored" data-anchor-id="performing-pca-with-two-components">Performing PCA with Two Components</h3>
<p>Let’s perform PCA with two components to get a feel for how PCA works. We will use the <code>scikit-learn</code> library. Table Table&nbsp;2 shows the communalities for each feature. This value represents the amount of variance in each variable that is accounted for by the principal components. The “Initial” column shows the initial communality, which is always 1.0 for PCA since each variable is perfectly correlated with itself. The “Extraction” column shows the communality after extracting the principal components. For example, the <code>woba</code> feature has an extraction communality of 0.877, meaning that 87.7% of the variance in <code>woba</code> is explained by the two principal components. Conversely, triples are not well captured (4.0%) given their rare occurrences.</p>
<div class="cell" data-tbl-alt="A table showing the communalities for each feature." data-execution_count="4">
<details class="code-fold">
<summary>Code</summary>
<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 class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> IPython.display <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Markdown</span>
<span id="cb6-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> tabulate <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> tabulate</span>
<span id="cb6-3"></span>
<span id="cb6-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Perform PCA with 2 components for exploration</span></span>
<span id="cb6-5">pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA(n_components<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="cb6-6">pca.fit(X_scaled)</span>
<span id="cb6-7"></span>
<span id="cb6-8">loadings <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca.components_.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.sqrt(pca.explained_variance_)</span>
<span id="cb6-9">loadings_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(loadings, </span>
<span id="cb6-10">                           columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<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 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> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)], </span>
<span id="cb6-11">                           index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>X.columns)</span>
<span id="cb6-12"></span>
<span id="cb6-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create the Communalities table</span></span>
<span id="cb6-14">communalities <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb6-15">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The 'Initial' communality is always 1.0 for PCA</span></span>
<span id="cb6-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Initial'</span>: <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>,</span>
<span id="cb6-17">    </span>
<span id="cb6-18">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 'Extraction' is the sum of the squared loadings for each variable</span></span>
<span id="cb6-19">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Extraction'</span>: (loadings_df <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 class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</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="cb6-20">})</span>
<span id="cb6-21">communalities.index.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;">'Features'</span></span>
<span id="cb6-22"></span>
<span id="cb6-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># sort by Extraction value descending</span></span>
<span id="cb6-24">communalities <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> communalities.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;">'Extraction'</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="cb6-25">Markdown(tabulate(communalities.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), headers<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;">'keys'</span>))</span></code></pre></div>
</details>
<div id="tbl-communalities" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="4" data-tbl-alt="A table showing the communalities for each feature.">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-communalities-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;2: Communalities Table
</figcaption>
<div aria-describedby="tbl-communalities-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display cell-output-markdown" data-execution_count="4">
<table class="do-not-create-environment cell caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;">Features</th>
<th style="text-align: right;">Initial</th>
<th style="text-align: right;">Extraction</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">woba</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.877</td>
</tr>
<tr class="even">
<td style="text-align: left;">slg</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.86</td>
</tr>
<tr class="odd">
<td style="text-align: left;">ba</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.822</td>
</tr>
<tr class="even">
<td style="text-align: left;">xwoba</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.813</td>
</tr>
<tr class="odd">
<td style="text-align: left;">obp</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.782</td>
</tr>
<tr class="even">
<td style="text-align: left;">xslg</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.779</td>
</tr>
<tr class="odd">
<td style="text-align: left;">hits</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.76</td>
</tr>
<tr class="even">
<td style="text-align: left;">xba</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.712</td>
</tr>
<tr class="odd">
<td style="text-align: left;">iso</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.712</td>
</tr>
<tr class="even">
<td style="text-align: left;">xobp</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.67</td>
</tr>
<tr class="odd">
<td style="text-align: left;">barrels_total</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.612</td>
</tr>
<tr class="even">
<td style="text-align: left;">attack_angle</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.582</td>
</tr>
<tr class="odd">
<td style="text-align: left;">hrs</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.575</td>
</tr>
<tr class="even">
<td style="text-align: left;">swing_length</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.568</td>
</tr>
<tr class="odd">
<td style="text-align: left;">bat_speed</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.5</td>
</tr>
<tr class="even">
<td style="text-align: left;">launch_speed</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.421</td>
</tr>
<tr class="odd">
<td style="text-align: left;">singles</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.343</td>
</tr>
<tr class="even">
<td style="text-align: left;">so</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.291</td>
</tr>
<tr class="odd">
<td style="text-align: left;">launch_angle</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.233</td>
</tr>
<tr class="even">
<td style="text-align: left;">whiffs</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.188</td>
</tr>
<tr class="odd">
<td style="text-align: left;">rate_ideal_attack_angle</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.123</td>
</tr>
<tr class="even">
<td style="text-align: left;">doubles</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.113</td>
</tr>
<tr class="odd">
<td style="text-align: left;">triples</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.04</td>
</tr>
<tr class="even">
<td style="text-align: left;">swing_path_tilt</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.015</td>
</tr>
<tr class="odd">
<td style="text-align: left;">velocity</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.014</td>
</tr>
<tr class="even">
<td style="text-align: left;">bb</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.006</td>
</tr>
<tr class="odd">
<td style="text-align: left;">attack_direction</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0.004</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
</div>
<p>Generally, a communality above 0.7 is considered good, indicating that the variable is well captured. So we can see that with only two components, we are able to explain a significant amount of variance in most of the features, namely the main offensive metrics. However, let’s investigate further by examining a technique to determine the optimal number of components to retain.</p>
</section>
<section id="determining-the-optimal-number-of-components" class="level3">
<h3 class="anchored" data-anchor-id="determining-the-optimal-number-of-components">Determining the Optimal Number of Components</h3>
<p>Similarly to <a href="https://runningonnumbers.com/posts/k-means/">k-means clustering</a>, we can use the elbow method to determine the optimal number of components for PCA. The idea is to fit the PCA model with the number of components equal to the number of features, and then plot the explained variance to see where the “elbow” point is. Figure&nbsp;3 shows the scree plot. As a <a href="https://en.wikipedia.org/wiki/Factor_analysis#Older_methods">general rule of thumb</a>, we want to select eigenvalues greater than 1.0.</p>
<div id="cell-fig-scree" class="cell" data-execution_count="5">
<details class="code-fold">
<summary>Code</summary>
<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">pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA()</span>
<span id="cb7-2">pca.fit(X_scaled)</span>
<span id="cb7-3"></span>
<span id="cb7-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Display explained variance ratio as a table</span></span>
<span id="cb7-5">explained_var_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb7-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Eigenvalue"</span>: np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca.explained_variance_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb7-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Explained Variance Ratio"</span>: np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca.explained_variance_ratio_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb7-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cumulative Explained Variance"</span>: np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.cumsum(pca.explained_variance_ratio_), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb7-9">}, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<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 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> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(pca.explained_variance_))])</span>
<span id="cb7-10">explained_var_df.index.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;">"Component"</span></span>
<span id="cb7-11"></span>
<span id="cb7-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use the 'eigenvalues' from the previous step</span></span>
<span id="cb7-13">eigenvalues <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca.explained_variance_</span>
<span id="cb7-14">plt.figure(figsize<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;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb7-15">plt.plot(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(eigenvalues) <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>), eigenvalues, marker<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>, linestyle<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-16">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Scree Plot'</span>)</span>
<span id="cb7-17">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Number of Components'</span>)</span>
<span id="cb7-18">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Eigenvalue (Explained Variance)'</span>)</span>
<span id="cb7-19">plt.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb7-20">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-scree" class="quarto-float quarto-figure quarto-figure-center anchored" alt="A scree plot showing the eigenvalues.">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-scree-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/principal-component-analysis-python-baseball/index_files/figure-html/fig-scree-output-1.png" alt="A scree plot showing the eigenvalues." width="655" height="529" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-scree-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: Scree Plot
</figcaption>
</figure>
</div>
</div>
</div>
<p>Table&nbsp;3 shows the explained variance table. We can see that the first eight components have eigenvalues greater than 1.0 and together explain 79.6% of the variance. Therefore, we will retain eight components for our final PCA model. For sports analytics, retaining 75% to 80% of the variance is sufficient for most applications.</p>
<div class="cell" data-tbl-alt="A table showing the explained variance for each component." data-execution_count="6">
<details class="code-fold">
<summary>Code</summary>
<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">Markdown(tabulate(explained_var_df, headers<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;">'keys'</span>))</span></code></pre></div>
</details>
<div id="tbl-explained-variance" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="6" data-tbl-alt="A table showing the explained variance for each component.">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-explained-variance-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;3: Explained Variance Table
</figcaption>
<div aria-describedby="tbl-explained-variance-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display cell-output-markdown" data-execution_count="6">
<table class="do-not-create-environment cell caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: right;">Component</th>
<th style="text-align: right;">Eigenvalue</th>
<th style="text-align: right;">Explained Variance Ratio</th>
<th style="text-align: right;">Cumulative Explained Variance</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">1</td>
<td style="text-align: right;">9.264</td>
<td style="text-align: right;">0.34</td>
<td style="text-align: right;">0.34</td>
</tr>
<tr class="even">
<td style="text-align: right;">2</td>
<td style="text-align: right;">3.151</td>
<td style="text-align: right;">0.116</td>
<td style="text-align: right;">0.456</td>
</tr>
<tr class="odd">
<td style="text-align: right;">3</td>
<td style="text-align: right;">2.124</td>
<td style="text-align: right;">0.078</td>
<td style="text-align: right;">0.534</td>
</tr>
<tr class="even">
<td style="text-align: right;">4</td>
<td style="text-align: right;">1.856</td>
<td style="text-align: right;">0.068</td>
<td style="text-align: right;">0.602</td>
</tr>
<tr class="odd">
<td style="text-align: right;">5</td>
<td style="text-align: right;">1.598</td>
<td style="text-align: right;">0.059</td>
<td style="text-align: right;">0.661</td>
</tr>
<tr class="even">
<td style="text-align: right;">6</td>
<td style="text-align: right;">1.379</td>
<td style="text-align: right;">0.051</td>
<td style="text-align: right;">0.712</td>
</tr>
<tr class="odd">
<td style="text-align: right;">7</td>
<td style="text-align: right;">1.224</td>
<td style="text-align: right;">0.045</td>
<td style="text-align: right;">0.757</td>
</tr>
<tr class="even">
<td style="text-align: right;">8</td>
<td style="text-align: right;">1.074</td>
<td style="text-align: right;">0.039</td>
<td style="text-align: right;">0.796</td>
</tr>
<tr class="odd">
<td style="text-align: right;">9</td>
<td style="text-align: right;">0.954</td>
<td style="text-align: right;">0.035</td>
<td style="text-align: right;">0.831</td>
</tr>
<tr class="even">
<td style="text-align: right;">10</td>
<td style="text-align: right;">0.918</td>
<td style="text-align: right;">0.034</td>
<td style="text-align: right;">0.865</td>
</tr>
<tr class="odd">
<td style="text-align: right;">11</td>
<td style="text-align: right;">0.823</td>
<td style="text-align: right;">0.03</td>
<td style="text-align: right;">0.895</td>
</tr>
<tr class="even">
<td style="text-align: right;">12</td>
<td style="text-align: right;">0.7</td>
<td style="text-align: right;">0.026</td>
<td style="text-align: right;">0.921</td>
</tr>
<tr class="odd">
<td style="text-align: right;">13</td>
<td style="text-align: right;">0.622</td>
<td style="text-align: right;">0.023</td>
<td style="text-align: right;">0.944</td>
</tr>
<tr class="even">
<td style="text-align: right;">14</td>
<td style="text-align: right;">0.467</td>
<td style="text-align: right;">0.017</td>
<td style="text-align: right;">0.961</td>
</tr>
<tr class="odd">
<td style="text-align: right;">15</td>
<td style="text-align: right;">0.316</td>
<td style="text-align: right;">0.012</td>
<td style="text-align: right;">0.972</td>
</tr>
<tr class="even">
<td style="text-align: right;">16</td>
<td style="text-align: right;">0.261</td>
<td style="text-align: right;">0.01</td>
<td style="text-align: right;">0.982</td>
</tr>
<tr class="odd">
<td style="text-align: right;">17</td>
<td style="text-align: right;">0.185</td>
<td style="text-align: right;">0.007</td>
<td style="text-align: right;">0.989</td>
</tr>
<tr class="even">
<td style="text-align: right;">18</td>
<td style="text-align: right;">0.112</td>
<td style="text-align: right;">0.004</td>
<td style="text-align: right;">0.993</td>
</tr>
<tr class="odd">
<td style="text-align: right;">19</td>
<td style="text-align: right;">0.067</td>
<td style="text-align: right;">0.002</td>
<td style="text-align: right;">0.995</td>
</tr>
<tr class="even">
<td style="text-align: right;">20</td>
<td style="text-align: right;">0.065</td>
<td style="text-align: right;">0.002</td>
<td style="text-align: right;">0.998</td>
</tr>
<tr class="odd">
<td style="text-align: right;">21</td>
<td style="text-align: right;">0.035</td>
<td style="text-align: right;">0.001</td>
<td style="text-align: right;">0.999</td>
</tr>
<tr class="even">
<td style="text-align: right;">22</td>
<td style="text-align: right;">0.015</td>
<td style="text-align: right;">0.001</td>
<td style="text-align: right;">1</td>
</tr>
<tr class="odd">
<td style="text-align: right;">23</td>
<td style="text-align: right;">0.005</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">1</td>
</tr>
<tr class="even">
<td style="text-align: right;">24</td>
<td style="text-align: right;">0.003</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">1</td>
</tr>
<tr class="odd">
<td style="text-align: right;">25</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">1</td>
</tr>
<tr class="even">
<td style="text-align: right;">26</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">1</td>
</tr>
<tr class="odd">
<td style="text-align: right;">27</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">1</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
</div>
</section>
<section id="our-magic-number-is-eight" class="level3">
<h3 class="anchored" data-anchor-id="our-magic-number-is-eight">Our Magic Number is Eight</h3>
<p>Finally, let’s fit a PCA model with eight components.</p>
<div class="cell" data-tbl-alt="A table showing the explained variance for each component." data-execution_count="7">
<details class="code-fold">
<summary>Code</summary>
<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">pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA(n_components<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;">8</span>)</span>
<span id="cb9-2">pca.fit(X_scaled)</span>
<span id="cb9-3"></span>
<span id="cb9-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Display explained variance ratio as a table</span></span>
<span id="cb9-5">explained_var_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb9-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Eigenvalue"</span>: np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca.explained_variance_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb9-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Explained Variance Ratio"</span>: np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca.explained_variance_ratio_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb9-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Cumulative Explained Variance"</span>: np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(np.cumsum(pca.explained_variance_ratio_), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb9-9">}, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<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 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> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(pca.explained_variance_))])</span>
<span id="cb9-10">explained_var_df.index.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;">"Component"</span></span>
<span id="cb9-11"></span>
<span id="cb9-12">Markdown(tabulate(explained_var_df, headers<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;">'keys'</span>))</span></code></pre></div>
</details>
<div id="tbl-explained-variance-8" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="7" data-tbl-alt="A table showing the explained variance for each component.">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-explained-variance-8-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;4: Explained Variance Table with 8 Components
</figcaption>
<div aria-describedby="tbl-explained-variance-8-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display cell-output-markdown" data-execution_count="7">
<table class="do-not-create-environment cell caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: right;">Component</th>
<th style="text-align: right;">Eigenvalue</th>
<th style="text-align: right;">Explained Variance Ratio</th>
<th style="text-align: right;">Cumulative Explained Variance</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">1</td>
<td style="text-align: right;">9.264</td>
<td style="text-align: right;">0.34</td>
<td style="text-align: right;">0.34</td>
</tr>
<tr class="even">
<td style="text-align: right;">2</td>
<td style="text-align: right;">3.151</td>
<td style="text-align: right;">0.116</td>
<td style="text-align: right;">0.456</td>
</tr>
<tr class="odd">
<td style="text-align: right;">3</td>
<td style="text-align: right;">2.124</td>
<td style="text-align: right;">0.078</td>
<td style="text-align: right;">0.534</td>
</tr>
<tr class="even">
<td style="text-align: right;">4</td>
<td style="text-align: right;">1.856</td>
<td style="text-align: right;">0.068</td>
<td style="text-align: right;">0.602</td>
</tr>
<tr class="odd">
<td style="text-align: right;">5</td>
<td style="text-align: right;">1.598</td>
<td style="text-align: right;">0.059</td>
<td style="text-align: right;">0.661</td>
</tr>
<tr class="even">
<td style="text-align: right;">6</td>
<td style="text-align: right;">1.379</td>
<td style="text-align: right;">0.051</td>
<td style="text-align: right;">0.712</td>
</tr>
<tr class="odd">
<td style="text-align: right;">7</td>
<td style="text-align: right;">1.224</td>
<td style="text-align: right;">0.045</td>
<td style="text-align: right;">0.757</td>
</tr>
<tr class="even">
<td style="text-align: right;">8</td>
<td style="text-align: right;">1.074</td>
<td style="text-align: right;">0.039</td>
<td style="text-align: right;">0.796</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
</div>
<p>Looking at Table&nbsp;4, the first component explains 35% of the variance; its eigenvalue of 9.26 means that this component explains as much variance as 9.26 of the original variables. The second component explains an additional 11.6% of the variance, and so on. The weakest component is PC8, which explains 3.9% of the variance, but its eigenvalue is still greater than 1, suggesting it captures some meaningful information.</p>
<p>To see which features fall under each component, we can look at the component matrix (or loadings) in Table&nbsp;5. The loadings represent the correlation between each original variable and the principal components. High absolute values indicate a strong relationship. For clarity, we will display only loadings with an absolute value greater than 0.3.</p>
<div class="cell" data-tbl-alt="A table showing the component matrix (loadings) for each feature" data-execution_count="8">
<details class="code-fold">
<summary>Code</summary>
<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"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate the Component Matrix (loadings)</span></span>
<span id="cb10-2">loadings <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca.components_.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.sqrt(pca.explained_variance_)</span>
<span id="cb10-3"></span>
<span id="cb10-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Format into a pandas DataFrame</span></span>
<span id="cb10-5">component_matrix <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(loadings, </span>
<span id="cb10-6">                                columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<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 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> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)], </span>
<span id="cb10-7">                                index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>X.columns)</span>
<span id="cb10-8">component_matrix <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> component_matrix.applymap(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> x: <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</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;">:.3f}</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;">if</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span>)</span>
<span id="cb10-9"></span>
<span id="cb10-10">Markdown(tabulate(component_matrix, headers<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;">'keys'</span>))</span></code></pre></div>
</details>
<div id="tbl-component-matrix" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="8" data-tbl-alt="A table showing the component matrix (loadings) for each feature">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-component-matrix-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;5: Component Matrix (Loadings)
</figcaption>
<div aria-describedby="tbl-component-matrix-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display cell-output-markdown" data-execution_count="8">
<table class="do-not-create-environment cell caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;">Features</th>
<th style="text-align: left;">PC1</th>
<th style="text-align: left;">PC2</th>
<th style="text-align: left;">PC3</th>
<th style="text-align: left;">PC4</th>
<th style="text-align: left;">PC5</th>
<th style="text-align: left;">PC6</th>
<th style="text-align: left;">PC7</th>
<th style="text-align: left;">PC8</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">ba</td>
<td style="text-align: left;">0.886</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.370</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">iso</td>
<td style="text-align: left;">0.800</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.435</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">slg</td>
<td style="text-align: left;">0.921</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.327</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">woba</td>
<td style="text-align: left;">0.936</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">xwoba</td>
<td style="text-align: left;">0.901</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">xba</td>
<td style="text-align: left;">0.823</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.311</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">hits</td>
<td style="text-align: left;">0.851</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.399</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">launch_speed</td>
<td style="text-align: left;">0.408</td>
<td style="text-align: left;">0.505</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.395</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">launch_angle</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.474</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.330</td>
<td style="text-align: left;">0.371</td>
</tr>
<tr class="even">
<td style="text-align: left;">velocity</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.444</td>
<td style="text-align: left;">0.310</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">whiffs</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.330</td>
<td style="text-align: left;">0.511</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.468</td>
</tr>
<tr class="even">
<td style="text-align: left;">bat_speed</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.676</td>
<td style="text-align: left;">-0.349</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">swing_length</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.751</td>
<td style="text-align: left;">-0.426</td>
<td style="text-align: left;">0.301</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">singles</td>
<td style="text-align: left;">0.394</td>
<td style="text-align: left;">-0.433</td>
<td style="text-align: left;">-0.363</td>
<td style="text-align: left;">0.495</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">doubles</td>
<td style="text-align: left;">0.334</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.328</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.416</td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">triples</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.384</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.311</td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">hrs</td>
<td style="text-align: left;">0.694</td>
<td style="text-align: left;">0.305</td>
<td style="text-align: left;">0.312</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">so</td>
<td style="text-align: left;">-0.462</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.540</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">bb</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.387</td>
<td style="text-align: left;">0.765</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">obp</td>
<td style="text-align: left;">0.844</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.403</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">barrels_total</td>
<td style="text-align: left;">0.703</td>
<td style="text-align: left;">0.343</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.408</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">xobp</td>
<td style="text-align: left;">0.760</td>
<td style="text-align: left;">-0.304</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.388</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">xslg</td>
<td style="text-align: left;">0.871</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.383</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">attack_angle</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.762</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.339</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">attack_direction</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.707</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;">swing_path_tilt</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.354</td>
<td style="text-align: left;">0.653</td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td style="text-align: left;">rate_ideal_attack_angle</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.307</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.346</td>
<td style="text-align: left;">0.543</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
</div>
<p>Table&nbsp;5 can be overwhelming at first glance because it shows feature membership across all eight components. To make it more interpretable, we can apply a varimax rotation to the component matrix. The goal of varimax rotation is to maximize the variance of the squared loadings within each component, which tends to produce a simpler and more interpretable structure. After rotation, each feature will ideally load highly on one component and have low loadings on others, making it easier to identify which features are associated with each principal component.</p>
<p>Table&nbsp;6 shows the rotated component matrix, sorted by the feature with the highest absolute loading. Here, we can see clusters of features that load highly on specific components. For example, PC1 has high loadings for <code>iso</code>, <code>slg</code>, <code>woba</code>, <code>xba</code>, <code>launch_speed</code>, <code>xslg</code>, and <code>barrels_total</code>, indicating that this component captures overall offensive performance.</p>
<p>PC2 has high loadings for <code>attack_angle</code>, <code>bat_speed</code>, and <code>swing_length</code>, suggesting it represents swing mechanics. Other components capture different aspects of performance, such as plate discipline (PC3 with <code>bb</code> and <code>obp</code>) and contact quality (PC4 with <code>hits</code> and <code>singles</code>).</p>
<div class="cell" data-tbl-alt="A table showing the rotated component matrix (loadings) for each feature" data-execution_count="9">
<details class="code-fold">
<summary>Code</summary>
<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">rotator <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Rotator(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;">'varimax'</span>)</span>
<span id="cb11-2">rotated_loadings <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rotator.fit_transform(loadings)</span>
<span id="cb11-3"></span>
<span id="cb11-4">rotated_loadings_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(</span>
<span id="cb11-5">    rotated_loadings,</span>
<span id="cb11-6">    columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<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 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> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(rotated_loadings.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])],</span>
<span id="cb11-7">    index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>features</span>
<span id="cb11-8">)</span>
<span id="cb11-9"></span>
<span id="cb11-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Sort by the component with the highest absolute loading for better visualization</span></span>
<span id="cb11-11">max_loading_component <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rotated_loadings_df.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>().idxmax(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="cb11-12">sorted_index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> max_loading_component.sort_values().index</span>
<span id="cb11-13">rotated_component_matrix_sorted <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rotated_loadings_df.loc[sorted_index]</span>
<span id="cb11-14">rotated_component_matrix_sorted <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rotated_component_matrix_sorted.applymap(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> x: <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</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;">:.3f}</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;">if</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span>)</span>
<span id="cb11-15"></span>
<span id="cb11-16">Markdown(tabulate(rotated_component_matrix_sorted, headers<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;">'keys'</span>))</span></code></pre></div>
</details>
<div id="tbl-rotated-component-matrix" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="9" data-tbl-alt="A table showing the rotated component matrix (loadings) for each feature">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-rotated-component-matrix-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;6: Rotated Component Matrix (Loadings)
</figcaption>
<div aria-describedby="tbl-rotated-component-matrix-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display cell-output-markdown" data-execution_count="9">
<table class="do-not-create-environment cell caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th></th>
<th style="text-align: left;">PC1</th>
<th style="text-align: left;">PC2</th>
<th style="text-align: left;">PC3</th>
<th style="text-align: left;">PC4</th>
<th style="text-align: left;">PC5</th>
<th style="text-align: left;">PC6</th>
<th style="text-align: left;">PC7</th>
<th style="text-align: left;">PC8</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>iso</td>
<td style="text-align: left;">0.899</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>slg</td>
<td style="text-align: left;">0.813</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.487</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>woba</td>
<td style="text-align: left;">0.687</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.640</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>xwoba</td>
<td style="text-align: left;">0.789</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.362</td>
<td style="text-align: left;">0.331</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>xba</td>
<td style="text-align: left;">0.593</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.389</td>
<td style="text-align: left;">0.503</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>launch_speed</td>
<td style="text-align: left;">0.477</td>
<td style="text-align: left;">0.416</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.335</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>xslg</td>
<td style="text-align: left;">0.876</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.313</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>barrels_total</td>
<td style="text-align: left;">0.855</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>hrs</td>
<td style="text-align: left;">0.862</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>attack_angle</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.852</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>bat_speed</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.803</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>swing_length</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.901</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>rate_ideal_attack_angle</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.400</td>
<td style="text-align: left;">-0.512</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.372</td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>whiffs</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.831</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>so</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.729</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>obp</td>
<td style="text-align: left;">0.400</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.808</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.342</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>ba</td>
<td style="text-align: left;">0.455</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.861</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>hits</td>
<td style="text-align: left;">0.418</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.872</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>singles</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.877</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>velocity</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.632</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>attack_direction</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.719</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>bb</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.902</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>xobp</td>
<td style="text-align: left;">0.489</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.347</td>
<td style="text-align: left;">0.465</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.564</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>swing_path_tilt</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.737</td>
<td style="text-align: left;"></td>
</tr>
<tr class="odd">
<td>triples</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">-0.551</td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td>doubles</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.676</td>
</tr>
<tr class="odd">
<td>launch_angle</td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.324</td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">0.687</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
</div>
<p>In summary, Pete Crow-Armstrong’s game-by-game statistics can be categorized into eight groups:</p>
<ol type="1">
<li><strong>Overall Offensive Performance</strong>: PC1</li>
</ol>
<ul>
<li>Key variables: <code>iso</code>, <code>slg</code>, <code>woba</code>, <code>xba</code>, <code>launch_speed</code>, <code>xslg</code>, <code>barrels_total</code></li>
</ul>
<ol start="2" type="1">
<li><strong>Swing Mechanics</strong>: PC2</li>
</ol>
<ul>
<li>Key variables: <code>attack_angle</code>, <code>bat_speed</code>, <code>swing_length</code></li>
</ul>
<ol start="3" type="1">
<li><strong>Swing-and-Miss vs Contact</strong>: PC3</li>
</ol>
<ul>
<li>Key variables: <code>whiffs</code>, <code>so</code>, <code>xwoba</code>, <code>xslg</code></li>
</ul>
<ol start="4" type="1">
<li><strong>On-Base Ability and Batting Average</strong>: PC4</li>
</ol>
<ul>
<li>Key variables: <code>hits</code>, <code>singles</code>, <code>obp</code>, <code>ba</code></li>
</ul>
<ol start="5" type="1">
<li><strong>Performance Against Pitch Velocity</strong>: PC5</li>
</ol>
<ul>
<li>Key variables: <code>launch_speed</code>, <code>velocity</code>, <code>attack_direction</code></li>
</ul>
<ol start="6" type="1">
<li><strong>Plate Discipline</strong>: PC6</li>
</ol>
<ul>
<li>Key variables: <code>bb</code>, <code>obp</code>, <code>xobp</code></li>
</ul>
<ol start="7" type="1">
<li><strong>“All-or-Nothing” Launch Angle Hitter</strong>: PC7</li>
</ol>
<ul>
<li>Key variables: <code>rate_ideal_attack_angle</code>, <code>swing_path_tilt</code>, <code>triples</code></li>
</ul>
<ol start="8" type="1">
<li><strong>Gap Power &amp; Launch Angle</strong>: PC8</li>
</ol>
<ul>
<li>Key variables: <code>doubles</code>, <code>launch_angle</code></li>
</ul>
<p>For convenience,</p>
<div id="tbl-summary" 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-summary-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;7: Summary of Principal Components and Their Interpreted Themes
</figcaption>
<div aria-describedby="tbl-summary-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<table class="caption-top table">
<thead>
<tr class="header">
<th>Component</th>
<th>Interpreted Theme / Skill</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>PC1</td>
<td>Elite Power &amp; Contact Quality 🚀</td>
</tr>
<tr class="even">
<td>PC2</td>
<td>Swing Mechanics ⚙️</td>
</tr>
<tr class="odd">
<td>PC3</td>
<td>Swing-and-Miss Tendency</td>
</tr>
<tr class="even">
<td>PC4</td>
<td>On-Base Ability &amp; Batting Average ⚾</td>
</tr>
<tr class="odd">
<td>PC5</td>
<td>Performance Against Pitch Velocity 🔥</td>
</tr>
<tr class="even">
<td>PC6</td>
<td>Plate Discipline 👀</td>
</tr>
<tr class="odd">
<td>PC7</td>
<td>“All-or-Nothing” Swing Path</td>
</tr>
<tr class="even">
<td>PC8</td>
<td>Gap Power &amp; Launch Angle</td>
</tr>
</tbody>
</table>
</div>
</figure>
</div>
</section>
<section id="how-to-actually-use-pca-in-ml-practice" class="level3">
<h3 class="anchored" data-anchor-id="how-to-actually-use-pca-in-ml-practice">How to actually use PCA in ML practice?</h3>
<div id="ba3d28f1" class="cell" data-execution_count="10">
<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">X_pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pca.transform(X_scaled)</span>
<span id="cb12-2">df_pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(X_pca, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PC</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<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 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> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(X_pca.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])])</span>
<span id="cb12-3">df_pca[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Game"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.arange(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(df_pca) <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="cb12-4"></span>
<span id="cb12-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Original shape:"</span>, X_scaled.shape)</span>
<span id="cb12-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Transformed shape:"</span>, X_pca.shape)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Original shape: (125, 27)
Transformed shape: (125, 8)</code></pre>
</div>
</div>
<p>As of writing this, Pete Crow-Armstrong is in a slump. His OPS barely sits above 0.802 and his rolling xwOBA is currently at 0.281. Given our newly found PCA features, let’s plot his performance over the season. Figure&nbsp;4 shows the rolling average of each principal component over the season. We can see that his elite power and contact quality (PC1) has been declining, as well as his swing mechanics (PC2). His on-base ability (PC4) has also been below average. This visualization can help identify areas for improvement and track progress over time.</p>
<div class="cell" data-execution_count="11">
<details class="code-fold">
<summary>Code</summary>
<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"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.graph_objs <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> go</span>
<span id="cb14-2"></span>
<span id="cb14-3">window <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="cb14-4"></span>
<span id="cb14-5">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Figure()</span>
<span id="cb14-6"></span>
<span id="cb14-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use a less saturated, pastel color palette</span></span>
<span id="cb14-8">colors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb14-9">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mediumseagreen'</span>,   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># muted green</span></span>
<span id="cb14-10">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC3'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lightsalmon'</span>,      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># soft orange</span></span>
<span id="cb14-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC4'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cornflowerblue'</span>    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># soft blue</span></span>
<span id="cb14-12">}</span>
<span id="cb14-13"></span>
<span id="cb14-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># PC1</span></span>
<span id="cb14-15">fig.add_trace(go.Scatter(</span>
<span id="cb14-16">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_pca[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Game'</span>],</span>
<span id="cb14-17">    y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_pca[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC1'</span>].rolling(window).mean(),</span>
<span id="cb14-18">    mode<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'</span>,</span>
<span id="cb14-19">    name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PC1: Elite Power &amp; Contact Quality (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>window<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;">-game avg)'</span>,</span>
<span id="cb14-20">    line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</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;">'gold'</span>, 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;">2</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># light yellow</span></span>
<span id="cb14-21">))</span>
<span id="cb14-22"></span>
<span id="cb14-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># PC2</span></span>
<span id="cb14-24">fig.add_trace(go.Scatter(</span>
<span id="cb14-25">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_pca[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Game'</span>],</span>
<span id="cb14-26">    y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_pca[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>].rolling(window).mean(),</span>
<span id="cb14-27">    mode<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'</span>,</span>
<span id="cb14-28">    name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PC2: Swing Mechanics (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>window<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;">-game avg)'</span>,</span>
<span id="cb14-29">    line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>colors[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC2'</span>], 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;">2</span>)</span>
<span id="cb14-30">))</span>
<span id="cb14-31"></span>
<span id="cb14-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># PC3</span></span>
<span id="cb14-33">fig.add_trace(go.Scatter(</span>
<span id="cb14-34">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_pca[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Game'</span>],</span>
<span id="cb14-35">    y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_pca[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC3'</span>].rolling(window).mean(),</span>
<span id="cb14-36">    mode<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'</span>,</span>
<span id="cb14-37">    name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PC3: Swing and Miss Tendencies (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>window<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;">-game avg)'</span>,</span>
<span id="cb14-38">    line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>colors[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC3'</span>], 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;">2</span>)</span>
<span id="cb14-39">))</span>
<span id="cb14-40"></span>
<span id="cb14-41"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># PC4</span></span>
<span id="cb14-42">fig.add_trace(go.Scatter(</span>
<span id="cb14-43">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_pca[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Game'</span>],</span>
<span id="cb14-44">    y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_pca[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC4'</span>].rolling(window).mean(),</span>
<span id="cb14-45">    mode<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'</span>,</span>
<span id="cb14-46">    name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'PC4: On-Base Ability (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>window<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;">-game avg)'</span>,</span>
<span id="cb14-47">    line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>colors[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PC4'</span>], 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;">2</span>)</span>
<span id="cb14-48">))</span>
<span id="cb14-49"></span>
<span id="cb14-50">fig.add_hline(y<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>, line_dash<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;">"dash"</span>, 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;">"grey"</span>, line_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;">1</span>)</span>
<span id="cb14-51"></span>
<span id="cb14-52">fig.update_layout(</span>
<span id="cb14-53">    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;">"Player's Skill Profile Over the Season (Rolling Avg)"</span>,</span>
<span id="cb14-54">    xaxis_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;">'Game Number'</span>,</span>
<span id="cb14-55">    yaxis_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;">'Component Score (Rolling Mean)'</span>,</span>
<span id="cb14-56">    legend_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;">'Principal Components'</span>,</span>
<span id="cb14-57">    xaxis<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">125</span>]),</span>
<span id="cb14-58">    template<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;">'simple_white'</span>,</span>
<span id="cb14-59">    legend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb14-60">        orientation<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;">"h"</span>,</span>
<span id="cb14-61">        yanchor<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="cb14-62">        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.25</span>,</span>
<span id="cb14-63">        xanchor<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="cb14-64">        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.5</span></span>
<span id="cb14-65">    )</span>
<span id="cb14-66">)</span>
<span id="cb14-67"></span>
<span id="cb14-68">fig.show()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div>
</details>
<div id="fig-pca-skill-profile" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="11">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-pca-skill-profile-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div id="fig-pca-skill-profile-1" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-subfloat-fig figure">
<div aria-describedby="fig-pca-skill-profile-1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
        <script type="text/javascript">
        window.PlotlyConfig = {MathJaxConfig: 'local'};
        if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}
        </script>
        <script type="module">import "https://cdn.plot.ly/plotly-3.0.1.min"</script>
        
</div>
<figcaption class="quarto-float-caption-bottom quarto-subfloat-caption quarto-subfloat-fig" id="fig-pca-skill-profile-1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
(a) Pete Crow-Armstrong’s Skill Profile Over the Season (Rolling Avg)
</figcaption>
</figure>
</div>
<div id="fig-pca-skill-profile-2" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-subfloat-fig figure">
<div aria-describedby="fig-pca-skill-profile-2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="735d00e6-01bb-45e2-a1cd-6a83b289936d" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("735d00e6-01bb-45e2-a1cd-6a83b289936d")) {                    Plotly.newPlot(                        "735d00e6-01bb-45e2-a1cd-6a83b289936d",                        [{"line":{"color":"gold","width":2},"mode":"lines","name":"PC1: Elite Power & Contact Quality (10-game avg)","x":{"dtype":"i1","bdata":"AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4\u002fQEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH0="},"y":{"dtype":"f8","bdata":"AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fAAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fAAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fTc2wZ0Hr1T\u002fj11ALEO7IP+AXYFZo\u002fZe\u002fhm2tqhw9zr+azcpkq\u002frWPzbNTEVmbK2\u002f8DP+wzMi5b+yulmS0Tbfv4Vk9sK7wuO\u002fK6hvXgUd8L8TQY7eScHzv+jsfh\u002fIIPG\u002fInfzSYtB7b+JUhhW0OHlvyR+mtTpG+e\u002f0zNnXnyK7r+adDjR1ezKv5ARb4VG8t6\u002fOO4Ur\u002f\u002fb47+eJV7Bm9Pvv4Ab4uM3i6C\u002ftRFQBN6J0L+yEE\u002fpOUbSvy1QKoO9MN8\u002fCDiKEuAs3j+CsM8ZE+HdP54JMlwqHtC\u002f9jLn+vS01z8qU6i34W\u002fiP67cwpFti\u002fE\u002f574CIl060j\u002fOZo2E2fjyPxbnWjZDOfM\u002ffQ7pA3eetr9T24lvPa\u002fAvzfffXLYrec\u002f8IZ+rPk16j+jUBBCC7\u002fIP63InlEdHtw\u002fDOlAJGgVwD9mtrAJbA+FP+DzJ+dynee\u002f2UGrsBbC578AKqhXIWx2v+TldOwNI9e\u002f2wLoQQ973786OSsmtVTfv9L71Cg1sMq\u002fIOuNNaniuL9oR53GlrzAP1YHFm8EUes\u002ffwMh5hDQ8D9OoSMOZe\u002fwP9RLVDiCVeI\u002fZT1qvjXR5D89RztB1aXjPz\u002f3jN+Tt\u002fI\u002f8vfnJ8lN7T+gjSi59M\u002fhP\u002fBQve\u002fZD8I\u002fPaGbJaa43r\u002fgyKVLXdDQv059ExqMGeO\u002fRjUFZI5z5T\u002fyUKNO6vTjP0YlucUXPaU\u002fIM0\u002fFTkGy7\u002fiUf7w6VDQv0UPlzkJaN6\u002f7vBEHtBe0r8InhhQF5HgPz7ZK5MUfNM\u002fkaXr9L9m0j+2QTbh\u002fbbSv\u002fMzi5qblM6\u002fYCRTbxwGzb+FXtT6O+bav\u002fWrLsaKhcM\u002fwCg69GUf2j8xWXHi9vPkP3t71m2l8ss\u002fvnaiTpUzyL\u002fmG0cw1dnWPzOKyAoRNbM\u002fo3P\u002fvdXr7T\u002flFF2boRjxPwLsECmH6fM\u002fGlTREm4t7T9t6JhlLFHdP29ID\u002f3dHNY\u002fx6OKRCO64D8EdhQdsorkPwJDU3QiTcA\u002fAEiBdpsip78I7KBJyKDrv+OD1WQxQuO\u002fc9NmIdJ68L9tGK8i17rFv1bqEy8IYLE\u002ffLqKQgoGwj\u002fdBY4YERDfvwDv2j7tpMq\u002fA6grF7nUvL9ndZy1ZkPRv7YrGRCykM6\u002fhQ\u002foxN7i3L8W8qoXTF3ev7OrJXv4K\u002fi\u002fnQMV1+vS+r\u002fCnnNQPeXyv9BbdAMGD9+\u002fxqUgjfeVzb94dAwGllLQv2ZvlsfPnL6\u002fckTwgasHob\u002fwQCIapHe5vw=="},"type":"scatter"},{"line":{"color":"mediumseagreen","width":2},"mode":"lines","name":"PC2: Swing Mechanics (10-game avg)","x":{"dtype":"i1","bdata":"AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4\u002fQEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH0="},"y":{"dtype":"f8","bdata":"AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fAAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fAAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fAEIv5aJmrr\u002fAUDVODfynv+pBE349r6q\u002f8F+eqmLTvz9oL9+WC\u002fTPvxSfluhTc8S\u002felndzbM91b8quGvVi6HWv9qNdMUNuru\u002fgHrYMJ9\u002fsD+rWMRMCf3hP2DCw2jnkec\u002fchuiCd+p4D+NlzxC42eeP253nTOA6sk\u002fgL52PNhDwT93TaaJLtbGP\u002fp+2nN49LQ\u002fw+NN0ipxur+JgkzOP5nHP\u002fr2h12alsM\u002fc3Q8NRVTgj9djLOriP3BPzzS1FOsS+I\u002fdR7Hf6TU5z+bqQ4v7STZP7gRzqQLPtM\u002fAZ88K8GC1D\u002fGBUErOIvhP83k6Tv0kXq\u002f1JfGsfhvxL\u002fWet+Y043hv+lvWq5pseG\u002fFIpr78Q16L9le2nU9nXwv94la0x5guS\u002fW9ga6HUy6b8EmepFWO3lv974UC914uq\u002f02he\u002fVgS3L+DfnT8oYbXv0hTzpVMF7+\u002fNjH26LE0xD+t1EnofcDWP1uI1dG53d8\u002fPk8cNXlk4D8CywrCQ2TpPyY+LzPs6+Y\u002fAA\u002fz1YgO5T+2TUuNQqXnP7MwYAyh0ug\u002fYNg+jQom8T9XfHabf+LyP95gWnYfY+0\u002fw6EQnCK28T8DMpPgJ7nkP6qVbR1PueU\u002fMENy47mO6j8C6+Jx+BftP6JqomvxOus\u002fJqaKZgW16T\u002fdTumT5gHkP5JfSbkQ5tk\u002fFu9k1qbg4j8rXyMSnW3aPzXg2WXUHOs\u002f2yqWURWy4z+h+15Po1jjP213qNDp9OE\u002fN1rBF0WO5T\u002fEIbwIm+3iP9ZI9zyo\u002fdI\u002fwOjJMm7vzD9nlaYjknjSP0tSlnaOC88\u002f4Lovlx6n2L\u002fWELa70HjTv9C9FDxwEu+\u002f4UH6xw4t8r9OZfRDu631v9ohGtqVPfK\u002fOq2QLf7p67\u002fYqvShuwLjv3QO+5jKJee\u002fAKfjxYfE47+yG74B9om2v+KwKfEZoqc\u002f1vbDsuad5D8TQsGgEUHqP73zVLu+7uc\u002fVKt3d7315D8uT9GwK4PkPxp6LYBIO+M\u002fhiZZdEbQ1T+VDrFHd97OPw6WQo2YoMk\u002f56OvlLcS1z\u002f5rZdNqMXUPxBsXuN2Jcw\u002fZIZmhDzO0z9xjkSQLRzTv3jCYap2eea\u002foJ\u002fKIh1t67\u002fuvDo\u002fCizmv8JVCxFE8d2\u002fr2KUEflf4r9KnzQldlL2v8TPfU7UVfW\u002fzoEyBbzS9b\u002fvglsvyi35vw9zpPJ69PO\u002fKkCv0+vp6L8vbC6HGg\u002fpv+I5\u002fsdTOO+\u002fZOvvVI2L8b9lyD5bAYDzvw=="},"type":"scatter"},{"line":{"color":"lightsalmon","width":2},"mode":"lines","name":"PC3: Swing and Miss Tendencies (10-game avg)","x":{"dtype":"i1","bdata":"AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4\u002fQEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH0="},"y":{"dtype":"f8","bdata":"AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fAAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fAAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fiN5UDlqv6T9tG6\u002fcTIfpP0N2lmyHSug\u002fPvwY9\u002fe15T8W8iLuRU3YPwrT3ZBEA9c\u002fXFTV5tFLuT\u002f+ZnWOaW+yPyDe1SURi7+\u002frrLT3vm\u002f0r8ozttvdMHJv1D1A9ljPMG\u002fIC40J+fthb8yJ4S7EF3AP1qBjo2YV5Q\u002f4H9QM\u002ff6yj8j5Q6+GGvTPycmfQYVl9Q\u002fzfM0tUBUzj9p0kJyonzXP2OY0RQ6Xcs\u002f0XlTpa6Itz92TuwX0HyZvyrjD0ytapM\u002fIJeXj1We2z9zqB+RXILYPx3LyDkDctg\u002fKJ+Fct+V2z+N7bYX+hbkPw72Kq1rneE\u002f4A29wZ7q6T9EW\u002ftcZWXoP2bTGPG6He0\u002fOhNm2saz7z9GZXEmXxHxPxIE4n1ugfA\u002f+zkRXlcI7D8Isy8q2bjqP5azj3qPoOo\u002fqte2ye3g5D\u002fyQgiMs2LgP784q1QyAuU\u002fvOmaElss5T\u002fKOhqzubDlP3o0KT+H69k\u002flk3l3t7ZyT+tkYcao5y5P4Ba3DovHra\u002fS1GcS3372L+a+2LEKUXev8g9EuG45+S\u002fIurwm\u002fND2r8l6ncC10Pav6YDA+syVua\u002fKree1HrU6b+7EGYXwcnqv9midvZjIua\u002fkOdn6mkf4r+jS4ipgQ3fv13\u002fP6\u002fUsMe\u002f4LireG1ssb8\u002fRoV14rnGvyOjK1ywM8q\u002fLMr\u002feHSBxr+jh4bdk0OYv6DW5ezoEKg\u002fYBMjDUoay7\u002f21F8bhlGtv3N08SQO2Ha\u002fHxC3FDkjwz8T5lwZP4ayv2ZJImun7tS\u002fpjeyLiy30b9mLu+PmURcvzCCEvKecao\u002foVnSkW7K2D8w0RJtoD7kP+XUKm+voOI\u002feq6wU6ZX3T\u002f60hek0sTFP1AUU7X859s\u002fgUsJzmTp4z+eZewNsWzkP8aTQc25J90\u002fK5KwCWvX1z+a0dMeA6DPP1aH\u002fuXnK7O\u002fiATzYbMG27\u002f48C\u002fwI7rVv6d+CvJOGdi\u002f6EQ6K8hn3L95qWC3Hbfjv6AI0bpjp+q\u002fi6Mr30rY6796TDdJJUzvv8qt7sXpePO\u002fjUDtfntA7r+AeftSfA\u002fEvz0IKCK\u002fkMq\u002f9C6bM4yu0r+hUahT8VjGvxTEicGGV8i\u002fcMzkeZ1Nz7\u002fqbTZWXTXav4oWSkAEut+\u002fNOPNgo0F1r+t85yzFqKpvyJLO\u002f\u002fNseS\u002fDPUsblOD47+kplIduj\u002fWv0xc6iMUIdG\u002fS\u002f9Rx2gk2r+QIyjyLqbYvz7elakc7Ne\u002fOIkZTWnk3L\u002fzAko3tNbevw=="},"type":"scatter"},{"line":{"color":"cornflowerblue","width":2},"mode":"lines","name":"PC4: On-Base Ability (10-game avg)","x":{"dtype":"i1","bdata":"AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4\u002fQEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH0="},"y":{"dtype":"f8","bdata":"AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fAAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fAAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh\u002fP5fWuds75j8taIsJ+5XqP2IgvLkufuc\u002fO2P7+Os+1z\u002fUJMPw6a3TP9C\u002fKKPbfOk\u002feDPLbKJV4j8bvihumw\u002fhP6eFVqovXtg\u002fEFJkX3d01z+Irr04u9nZP4Aoaojhf9w\u002fLtB\u002fH2rx1T82cSMnuCLlP6ZlgW8WLek\u002f5Gdihcti4j+iBcPQbK3nP0Z7IVpKa+Q\u002fYeQXInen5z9NPnvpuvziP83zl2OozMw\u002fzUD3JYKFtT+fnuYDxnOiP8DcjxjILs6\u002f246cMB3n3b+\u002fGX7soBPiv8bR0wE2feS\u002foOuiRM6Q179Vw3jz6cbev1A20ZjUOtW\u002fqTKKu1P1wT8Dcc04l9fYP3Rd83kPt9U\u002fpNDMUEju1z\u002fwBwwZWZ7kP2alqTtdYuc\u002fssSWFXqi3z\u002fqDql3P2vUP6CY9h6oH7Q\u002fKgV65A0Zw79aEIl67DDVvzuiVnGqc96\u002fa9KWy4oA1r8hurM8Lh7RvyoGskgzr+C\u002fCnPAJ28i5r8OmkqajiXhvwNpwWl8b+C\u002f5nwUpvcVgb\u002f3297clCLRv4givD0F1OK\u002fAQfOZ\u002fiX5b9eGyfEb7jlv30nw01VHeS\u002fcvx8QVk427+adVdxSnyNv6sdNIDq4re\u002fMifVGvnCpr++KIrDPd\u002fUvwqPofsFNLK\u002fWq82xICW3T+o4H+JJJjTP\u002fagvYv6W8w\u002fd3InKkmEtT8ArYLWvoxXP3CT\u002fNI4gMu\u002fY7S6J\u002f3kg7\u002f6kVdLOQO0v+tHYhn2vrY\u002fZYOgzWiK1z+G0oiP5yLbP8\u002fIAvdsEuc\u002fi3xPXmpf5D8RrJuTLVnnPz0oqhzLk94\u002f6C17JH553D8tUlp1BNbZP8Ufa8JDFto\u002fK8s2E2xe2z\u002f9CPYlqWLRP3H98Uvp5LO\u002f8+rawayhy78icRwhsVvHv9YGOk+Ns8O\u002fe4pcC97Iv7+M8Kd2OXCSv8oUtAH5868\u002fknV+1E0LuL9EdgwwyCnUv5cWphAdFde\u002fyseGwZT1zr+SgnVKg0jTv0HWS6jJmse\u002fXbgf9ePTu7+6oirhhRW2v8befHrh7aG\u002fkyA98FzGlr\u002f9hjOZ\u002fBqiP7v2Vv9DJ8M\u002fc\u002f0+gj0Me7+oGt33DVHUv6P+ZVdzAdq\u002f74zDH2OG4L8L69Nm9WvhvzKvSn+1c9+\u002fpx3m\u002fbKI4b9Cafyl4Nrsv2b\u002fBjBl1eq\u002fIEEy5DY78L8dQOXAK2\u002fuvx7udHfOvea\u002fol6XwZbP5b8lNgHVtITmv+pf9NVNs+e\u002f17jeRvo84b8ucBD4GuDhvw=="},"type":"scatter"}],                        {"template":{"data":{"barpolar":[{"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"bar":[{"error_x":{"color":"rgb(36,36,36)"},"error_y":{"color":"rgb(36,36,36)"},"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"carpet":[{"aaxis":{"endlinecolor":"rgb(36,36,36)","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"rgb(36,36,36)"},"baxis":{"endlinecolor":"rgb(36,36,36)","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"rgb(36,36,36)"},"type":"carpet"}],"choropleth":[{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"},"type":"choropleth"}],"contourcarpet":[{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"},"type":"contourcarpet"}],"contour":[{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"},"colorscale":[[0.0,"#440154"],[0.1111111111111111,"#482878"],[0.2222222222222222,"#3e4989"],[0.3333333333333333,"#31688e"],[0.4444444444444444,"#26828e"],[0.5555555555555556,"#1f9e89"],[0.6666666666666666,"#35b779"],[0.7777777777777778,"#6ece58"],[0.8888888888888888,"#b5de2b"],[1.0,"#fde725"]],"type":"contour"}],"heatmap":[{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"},"colorscale":[[0.0,"#440154"],[0.1111111111111111,"#482878"],[0.2222222222222222,"#3e4989"],[0.3333333333333333,"#31688e"],[0.4444444444444444,"#26828e"],[0.5555555555555556,"#1f9e89"],[0.6666666666666666,"#35b779"],[0.7777777777777778,"#6ece58"],[0.8888888888888888,"#b5de2b"],[1.0,"#fde725"]],"type":"heatmap"}],"histogram2dcontour":[{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"},"colorscale":[[0.0,"#440154"],[0.1111111111111111,"#482878"],[0.2222222222222222,"#3e4989"],[0.3333333333333333,"#31688e"],[0.4444444444444444,"#26828e"],[0.5555555555555556,"#1f9e89"],[0.6666666666666666,"#35b779"],[0.7777777777777778,"#6ece58"],[0.8888888888888888,"#b5de2b"],[1.0,"#fde725"]],"type":"histogram2dcontour"}],"histogram2d":[{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"},"colorscale":[[0.0,"#440154"],[0.1111111111111111,"#482878"],[0.2222222222222222,"#3e4989"],[0.3333333333333333,"#31688e"],[0.4444444444444444,"#26828e"],[0.5555555555555556,"#1f9e89"],[0.6666666666666666,"#35b779"],[0.7777777777777778,"#6ece58"],[0.8888888888888888,"#b5de2b"],[1.0,"#fde725"]],"type":"histogram2d"}],"histogram":[{"marker":{"line":{"color":"white","width":0.6}},"type":"histogram"}],"mesh3d":[{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"},"type":"mesh3d"}],"parcoords":[{"line":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"type":"parcoords"}],"pie":[{"automargin":true,"type":"pie"}],"scatter3d":[{"line":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"marker":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"type":"scatter3d"}],"scattercarpet":[{"marker":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"type":"scattercarpet"}],"scattergeo":[{"marker":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"type":"scattergeo"}],"scattergl":[{"marker":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"type":"scattergl"}],"scattermapbox":[{"marker":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"type":"scattermapbox"}],"scattermap":[{"marker":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"type":"scattermap"}],"scatterpolargl":[{"marker":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"type":"scatterpolargl"}],"scatterpolar":[{"marker":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"type":"scatterpolar"}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"scatterternary":[{"marker":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"type":"scatterternary"}],"surface":[{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"},"colorscale":[[0.0,"#440154"],[0.1111111111111111,"#482878"],[0.2222222222222222,"#3e4989"],[0.3333333333333333,"#31688e"],[0.4444444444444444,"#26828e"],[0.5555555555555556,"#1f9e89"],[0.6666666666666666,"#35b779"],[0.7777777777777778,"#6ece58"],[0.8888888888888888,"#b5de2b"],[1.0,"#fde725"]],"type":"surface"}],"table":[{"cells":{"fill":{"color":"rgb(237,237,237)"},"line":{"color":"white"}},"header":{"fill":{"color":"rgb(217,217,217)"},"line":{"color":"white"}},"type":"table"}]},"layout":{"annotationdefaults":{"arrowhead":0,"arrowwidth":1},"autotypenumbers":"strict","coloraxis":{"colorbar":{"outlinewidth":1,"tickcolor":"rgb(36,36,36)","ticks":"outside"}},"colorscale":{"diverging":[[0.0,"rgb(103,0,31)"],[0.1,"rgb(178,24,43)"],[0.2,"rgb(214,96,77)"],[0.3,"rgb(244,165,130)"],[0.4,"rgb(253,219,199)"],[0.5,"rgb(247,247,247)"],[0.6,"rgb(209,229,240)"],[0.7,"rgb(146,197,222)"],[0.8,"rgb(67,147,195)"],[0.9,"rgb(33,102,172)"],[1.0,"rgb(5,48,97)"]],"sequential":[[0.0,"#440154"],[0.1111111111111111,"#482878"],[0.2222222222222222,"#3e4989"],[0.3333333333333333,"#31688e"],[0.4444444444444444,"#26828e"],[0.5555555555555556,"#1f9e89"],[0.6666666666666666,"#35b779"],[0.7777777777777778,"#6ece58"],[0.8888888888888888,"#b5de2b"],[1.0,"#fde725"]],"sequentialminus":[[0.0,"#440154"],[0.1111111111111111,"#482878"],[0.2222222222222222,"#3e4989"],[0.3333333333333333,"#31688e"],[0.4444444444444444,"#26828e"],[0.5555555555555556,"#1f9e89"],[0.6666666666666666,"#35b779"],[0.7777777777777778,"#6ece58"],[0.8888888888888888,"#b5de2b"],[1.0,"#fde725"]]},"colorway":["#1F77B4","#FF7F0E","#2CA02C","#D62728","#9467BD","#8C564B","#E377C2","#7F7F7F","#BCBD22","#17BECF"],"font":{"color":"rgb(36,36,36)"},"geo":{"bgcolor":"white","lakecolor":"white","landcolor":"white","showlakes":true,"showland":true,"subunitcolor":"white"},"hoverlabel":{"align":"left"},"hovermode":"closest","mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30},"paper_bgcolor":"white","plot_bgcolor":"white","polar":{"angularaxis":{"gridcolor":"rgb(232,232,232)","linecolor":"rgb(36,36,36)","showgrid":false,"showline":true,"ticks":"outside"},"bgcolor":"white","radialaxis":{"gridcolor":"rgb(232,232,232)","linecolor":"rgb(36,36,36)","showgrid":false,"showline":true,"ticks":"outside"}},"scene":{"xaxis":{"backgroundcolor":"white","gridcolor":"rgb(232,232,232)","gridwidth":2,"linecolor":"rgb(36,36,36)","showbackground":true,"showgrid":false,"showline":true,"ticks":"outside","zeroline":false,"zerolinecolor":"rgb(36,36,36)"},"yaxis":{"backgroundcolor":"white","gridcolor":"rgb(232,232,232)","gridwidth":2,"linecolor":"rgb(36,36,36)","showbackground":true,"showgrid":false,"showline":true,"ticks":"outside","zeroline":false,"zerolinecolor":"rgb(36,36,36)"},"zaxis":{"backgroundcolor":"white","gridcolor":"rgb(232,232,232)","gridwidth":2,"linecolor":"rgb(36,36,36)","showbackground":true,"showgrid":false,"showline":true,"ticks":"outside","zeroline":false,"zerolinecolor":"rgb(36,36,36)"}},"shapedefaults":{"fillcolor":"black","line":{"width":0},"opacity":0.3},"ternary":{"aaxis":{"gridcolor":"rgb(232,232,232)","linecolor":"rgb(36,36,36)","showgrid":false,"showline":true,"ticks":"outside"},"baxis":{"gridcolor":"rgb(232,232,232)","linecolor":"rgb(36,36,36)","showgrid":false,"showline":true,"ticks":"outside"},"bgcolor":"white","caxis":{"gridcolor":"rgb(232,232,232)","linecolor":"rgb(36,36,36)","showgrid":false,"showline":true,"ticks":"outside"}},"title":{"x":0.05},"xaxis":{"automargin":true,"gridcolor":"rgb(232,232,232)","linecolor":"rgb(36,36,36)","showgrid":false,"showline":true,"ticks":"outside","title":{"standoff":15},"zeroline":false,"zerolinecolor":"rgb(36,36,36)"},"yaxis":{"automargin":true,"gridcolor":"rgb(232,232,232)","linecolor":"rgb(36,36,36)","showgrid":false,"showline":true,"ticks":"outside","title":{"standoff":15},"zeroline":false,"zerolinecolor":"rgb(36,36,36)"}}},"shapes":[{"line":{"color":"grey","dash":"dash","width":1},"type":"line","x0":0,"x1":1,"xref":"x domain","y0":0,"y1":0,"yref":"y"}],"xaxis":{"title":{"text":"Game Number"},"range":[1,125]},"legend":{"title":{"text":"Principal Components"},"orientation":"h","yanchor":"top","y":-0.25,"xanchor":"center","x":0.5},"title":{"text":"Player's Skill Profile Over the Season (Rolling Avg)"},"yaxis":{"title":{"text":"Component Score (Rolling Mean)"}}},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('735d00e6-01bb-45e2-a1cd-6a83b289936d');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-subfloat-caption quarto-subfloat-fig" id="fig-pca-skill-profile-2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
(b)
</figcaption>
</figure>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig quarto-uncaptioned" id="fig-pca-skill-profile-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4
</figcaption>
</figure>
</div>
</div>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>In this post, we performed PCA on Pete Crow-Armstrong’s game-by-game statistics from the 2025 MLB season. We started by exploring the data and visualizing correlations between variables. We then applied PCA to reduce the dimensionality of the dataset while retaining most of the important information. By examining the communalities and scree plot, we determined that retaining eight components was optimal. Finally, we interpreted the components using a varimax rotation, which revealed distinct themes related to offensive performance, swing mechanics, plate discipline, and more.</p>
<p>We started with 27 features and ended with eight rotated components, distilling Pete Crow-Armstrong’s season into actionable levers. A spike in the decision component alongside a flat contact-quality component suggests selectivity gains arriving before slug; a swing-path surge without decision support hints at over-aggression masquerading as form.</p>
<p>In daily box scores, noise drowns signal. Principal component analysis doesn’t tell us whether a hot streak is coming; it shows how one would be built—better decisions, a cleaner path, louder contact, pressure after contact—so that when one dial twitches, everyone knows which adjustment matters next. Let’s hope Pete Crow-Armstrong finds the right signal among the noise.</p>
<iframe src="https://streamable.com/m/pete-crow-armstrong-homers-28-on-a-fly-ball-to-right-center-field?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<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>Past articles: - <a href="https://runningonnumbers.com/posts/k-nearest-neighbors/">K-Nearest Neighbors</a> - <a href="https://runningonnumbers.com/posts/support-vector-machine/">Support Vector Machine</a> - <a href="https://runningonnumbers.com/posts/k-means/">K-Means Clustering</a> Github: - <a href="https://github.com/oliverc1623/Running-On-Numbers-Public">Running on Numbers</a></p>
</div>
</div>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->

</section>

 ]]></description>
  <category>dimensionality reduction</category>
  <category>PCA</category>
  <category>scikit-learn</category>
  <category>cubs</category>
  <guid>https://runningonnumbers.com/posts/principal-component-analysis-python-baseball/</guid>
  <pubDate>Sun, 24 Aug 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/principal-component-analysis-python-baseball/player-shadow.png" medium="image" type="image/png" height="96" width="144"/>
</item>
<item>
  <title>K-Nearest Neighbors</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/k-nearest-neighbors/</link>
  <description><![CDATA[ 





<iframe src="https://streamable.com/m/nathan-eovaldi-strikes-out-varsho?partnerId=web_video-playback-page_video-share" width="560" height="315" alt="nathan eovaldi strikes out varsho">
</iframe>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>Pitch tunneling is the art of deception. It’s a pitcher’s ability to make multiple, distinct pitches look identical as they leave the hand. From the batter’s perspective, two pitches can travel through the same “tunnel” partway to the plate before diverging. What looked like a hittable fastball suddenly drops off the table - a devastating curveball for a swinging strike. Effective tunneling neutralizes a batter’s ability to recognize a pitch, forcing a split-second, and often wrong, decision.</p>
Here’s a clip by @<a href="https://x.com/PitchingNinja">PitchingNinja</a> to illustrate pitch tunneling:
<blockquote class="twitter-tweet blockquote" data-media-max-width="560">
<p lang="en" dir="ltr">
Tyler Glasnow, 99mph Two Seamer and 84mph Curveball, Overlay <a href="https://t.co/7tq1KcoqKj">pic.twitter.com/7tq1KcoqKj</a>
</p>
— Rob Friedman (<span class="citation" data-cites="PitchingNinja">(<strong>PitchingNinja?</strong>)</span>) <a href="https://twitter.com/PitchingNinja/status/1946395819667534336?ref_src=twsrc%5Etfw">July 19, 2025</a>
</blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Notice how both pitches erupt from the exact same arm slot and follow the same initial trajectory. The batter sees the same initial trajectory for both pitches, making it difficult to distinguish between the two until it’s too late.</p>
<p>In this article, we are going to quantify how well a pitcher tunnels certain pitches. This project is inspired by <a href="https://baseballsavant.mlb.com/leaderboard/pitcher-arm-angles">Baseball Savant’s</a> page on arm angle. While resources like Baseball Savant provide ample data on release points and arm angles, a dedicated metric for tunneling effectiveness is surprisingly absent. This project aims to fill that gap. In order to quantify pitch tunneling, we will use K-Nearest Neighbors (K-NN) to find similar pitches in terms of release point and movement. We can then see what percentage of those similar pitches are of the same pitch type. A high percentage indicates good tunneling ability, while a low percentage suggests that the pitcher is telegraphing their pitches.</p>
</section>
<section id="k-nearest-neighbor" class="level2">
<h2 class="anchored" data-anchor-id="k-nearest-neighbor">K-Nearest Neighbor</h2>
<p>We turn to K-Nearest Neighbor (K-NN), a non-parametric machine learning algorithm used for classification and regression tasks (<span class="citation" data-cites="enwiki:1285981318">Wikipedia contributors (2025)</span>). Other methods like <a href="https://runningonnumbers.com/posts/logistic-regression/">Logistic Regression</a> or <a href="https://runningonnumbers.com/posts/support-vector-machine/">Support Vector Machines</a> usually have a training phase that involves stochastic gradient descent to find optimal parameters. K-NN’s training phase is much simpler. In K-NN, the training phase stores the feature vectors and class labels in memory - that’s it. So the training phase takes no time to complete. This implies that K-NN works best with smaller amounts of data. In general, K-NN works well on low-dimensional and low-volume data.</p>
<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>Professor Fei Fei Li over at Stanford has a good <a href="https://cs231n.github.io/classification/">lecture</a> on when NOT to use K-NN.</p>
</div>
</div>
<p>The bulk of K-NN happens in the inference phase. Given some positive integer, <img src="https://latex.codecogs.com/png.latex?k">, K-NN assigns a label to a query (<img src="https://latex.codecogs.com/png.latex?x_i">) based on the most frequent <img src="https://latex.codecogs.com/png.latex?k"> training samples nearby <img src="https://latex.codecogs.com/png.latex?x_i">. K-NN commonly uses Euclidean distance to measure nearness, but other distance metrics like Manhattan distance or Minkowski distance can also be used. Here’s a rundown of the three distance metrics (<span class="citation" data-cites="noauthor_k-nearest_nodate"><span>“K-<span>Nearest</span> <span>Neighbor</span>(<span>KNN</span>) <span>Algorithm</span> - <span>GeeksforGeeks</span>”</span> (n.d.)</span>). <img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7BEuclidean%20Distance%7D(x_i,%20y_i)%20=%20%5Csqrt%7B%5Csum_%7Bj=1%7D%5E%7Bn%7D%20(x_%7Bi%7D%20-%20y_%7Bi%7D)%5E2%7D%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7BManhattan%20Distance%7D(x_%7Bi%7D,%20y_%7Bi%7D)%20=%20%5Csum_%7Bj=1%7D%5E%7Bn%7D%20%7Cx_%7Bi%7D%20-%20y_%7Bi%7D%7C%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7BMinkowski%20Distance%7D(x_%7Bi%7D,%20y_%7Bi%7D)%20=%20%5Cleft(%20%5Csum_%7Bj=1%7D%5E%7Bn%7D%20%7Cx_%7Bi%7D%20-%20y_%7Bi%7D%7C%5Ep%20%5Cright)%5E%7B1/p%7D%0A"> Note that when <img src="https://latex.codecogs.com/png.latex?p=2">, Minkowski distance is equivalent to Euclidean distance, and when <img src="https://latex.codecogs.com/png.latex?p=1">, it is equivalent to Manhattan distance.</p>
<p>Since there is no training phase, we just need to implement the inference phase. This is done using a brute-force approach. For each query point, we will compute the distance to all training points and select the <img src="https://latex.codecogs.com/png.latex?k"> nearest neighbors.</p>
<section id="formalizing-k-nn" class="level3">
<h3 class="anchored" data-anchor-id="formalizing-k-nn">Formalizing K-NN</h3>
<p>Suppose we have a training dataset of size <img src="https://latex.codecogs.com/png.latex?n">, where each data point <img src="https://latex.codecogs.com/png.latex?x"> has a corresponding label <img src="https://latex.codecogs.com/png.latex?y">. That is, <img src="https://latex.codecogs.com/png.latex?(X_1,%20Y_1),%20(X_2,%20Y_2),%20%5Cldots,%20(X_n,%20Y_n)"> maps to values in <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BR%7D%5Ed%5Ctimes%20%5C%7B1,2%5C%7D">, there <img src="https://latex.codecogs.com/png.latex?d"> is the number of features and <img src="https://latex.codecogs.com/png.latex?%5C%7B1,2%5C%7D"> denotes a binary label. <img src="https://latex.codecogs.com/png.latex?X%20%7C%20Y%20=%20r%20%5Csim%20P_r"> for <img src="https://latex.codecogs.com/png.latex?r%20%5Cin%20%5C%7B1,2%5C%7D">. In other words, a data point <img src="https://latex.codecogs.com/png.latex?X"> given its label <img src="https://latex.codecogs.com/png.latex?Y=r"> follows some distribution <img src="https://latex.codecogs.com/png.latex?P_r">. Given a query point <img src="https://latex.codecogs.com/png.latex?x"> and some distance metric, we reorder the training data based on distance to <img src="https://latex.codecogs.com/png.latex?x">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5C%7C%20X_%7B(1)%7D%20-%20x%20%5C%7C%20%5Cleq%20%5C%7C%20X_%7B(2)%7D%20-%20x%20%5C%7C%20%5Cleq%20%5Cldots%20%5Cleq%20%5C%7C%20X_%7B(n)%7D%20-%20x%20%5C%7C%0A"> where <img src="https://latex.codecogs.com/png.latex?X_%7B(i)%7D"> is the <img src="https://latex.codecogs.com/png.latex?i">-th nearest neighbor to x. Hence, <img src="https://latex.codecogs.com/png.latex?(X_1,%20Y_1),%20(X_2,%20Y_2),%20%5Cldots,%20(X_n,%20Y_n)"> is reordered. <img src="https://latex.codecogs.com/png.latex?(X_1,%20Y_1)"> is the closest neighbor to x, <img src="https://latex.codecogs.com/png.latex?(X_2,%20Y_2)"> is the second closest, and so on.</p>
<p>This setup allows us to define the K-NN classifier. The K-NN classifier assigns a label to <img src="https://latex.codecogs.com/png.latex?x"> based on the most frequent label among its <img src="https://latex.codecogs.com/png.latex?k"> nearest neighbors.</p>
<ol type="1">
<li>Choose a value for <img src="https://latex.codecogs.com/png.latex?k"> (a positive integer).</li>
<li>Look at the <img src="https://latex.codecogs.com/png.latex?k"> nearest neighbors of <img src="https://latex.codecogs.com/png.latex?x">: <img src="https://latex.codecogs.com/png.latex?(X_%7B(1)%7D,%20Y_%7B(1)%7D),%20(X_%7B(2)%7D,%20Y_%7B(2)%7D),%20%5Cldots,%20(X_%7B(k)%7D,%20Y_%7B(k)%7D)">.</li>
<li>Assign to <img src="https://latex.codecogs.com/png.latex?x"> the label that is most common among these <img src="https://latex.codecogs.com/png.latex?k"> neighbors.</li>
</ol>
</section>
<section id="implementation" class="level3">
<h3 class="anchored" data-anchor-id="implementation">Implementation</h3>
<p>K-NN can easily be implemented using <code>NumPy</code> and built-in Python libraries.</p>
<div id="b3b85089" class="cell" data-execution_count="1">
<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="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-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> collections <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Counter</span>
<span id="cb1-3"></span>
<span id="cb1-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> euclidean_distance(a, b):</span>
<span id="cb1-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.sqrt(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>((a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> b) <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="cb1-6"></span>
<span id="cb1-7"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> knn_predict(X_train, y_train, x_query, k):</span>
<span id="cb1-8">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compute distances from the query point to all training points</span></span>
<span id="cb1-9">    distances <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [euclidean_distance(x_query, x_train) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> x_train <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> X_train]</span>
<span id="cb1-10">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># sort distances and get indices of k nearest neighbors</span></span>
<span id="cb1-11">    k_indices <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.argsort(distances)[:k]</span>
<span id="cb1-12">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Extract the labels of the k nearest neighbors</span></span>
<span id="cb1-13">    k_nearest_labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [y_train[i] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> k_indices]</span>
<span id="cb1-14">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Return the most common label among the k nearest neighbors</span></span>
<span id="cb1-15">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Counter(k_nearest_labels).most_common(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</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></code></pre></div>
</div>
<p>Let’s visualize K-NN with a simple 2D dataset.</p>
<div id="cell-fig-knn-k-values" class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># import blobs</span></span>
<span id="cb2-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.datasets <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_blobs</span>
<span id="cb2-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb2-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="cb2-5"><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="cb2-6"></span>
<span id="cb2-7">sns.set_theme(style<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;">"whitegrid"</span>, palette<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;">"pastel"</span>)</span>
<span id="cb2-8"></span>
<span id="cb2-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create a synthetic dataset</span></span>
<span id="cb2-10">X, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_blobs(n_samples<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>, centers<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>, 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;">47</span>, center_box<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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>))</span>
<span id="cb2-11"></span>
<span id="cb2-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define k values to test</span></span>
<span id="cb2-13">k_values <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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>]</span>
<span id="cb2-14">plot_data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb2-15"></span>
<span id="cb2-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Apply K-NN for each k</span></span>
<span id="cb2-17"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> k_values:</span>
<span id="cb2-18">    predictions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [knn_predict(X, y, x_query, k) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> x_query <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> X]</span>
<span id="cb2-19">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Store results for plotting</span></span>
<span id="cb2-20">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(X)):</span>
<span id="cb2-21">        plot_data.append({</span>
<span id="cb2-22">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'feature1'</span>: X[i, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>],</span>
<span id="cb2-23">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'feature2'</span>: X[i, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb2-24">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'prediction'</span>: predictions[i],</span>
<span id="cb2-25">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k'</span>: k</span>
<span id="cb2-26">        })</span>
<span id="cb2-27"></span>
<span id="cb2-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Convert to DataFrame</span></span>
<span id="cb2-29">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(plot_data)</span>
<span id="cb2-30"></span>
<span id="cb2-31"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create a facet grid</span></span>
<span id="cb2-32">g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sns.FacetGrid(df, 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;">"k"</span>, hue<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>, height<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="cb2-33">g.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">map</span>(sns.scatterplot, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"feature1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"feature2"</span>, edgecolor<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;">'k'</span>)</span>
<span id="cb2-34">g.add_legend()</span>
<span id="cb2-35">g.set_axis_labels(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Feature 1"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Feature 2"</span>)</span>
<span id="cb2-36">g.set_titles(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"k = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{col_name}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb2-37">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-knn-k-values" class="quarto-float quarto-figure quarto-figure-center anchored" alt="A scatter plot showing K-NN classification results.">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-knn-k-values-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/k-nearest-neighbors/index_files/figure-html/fig-knn-k-values-output-1.png" alt="A scatter plot showing K-NN classification results." width="642" height="272" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-knn-k-values-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: K-NN Classification with Different k Values
</figcaption>
</figure>
</div>
</div>
</div>
<p>Observe how the decision boundary changes with different values of <img src="https://latex.codecogs.com/png.latex?k">. A smaller <img src="https://latex.codecogs.com/png.latex?k"> (e.g., <img src="https://latex.codecogs.com/png.latex?k=2">) leads to a more complex decision boundary that closely follows the training data, while a larger <img src="https://latex.codecogs.com/png.latex?k"> (e.g., <img src="https://latex.codecogs.com/png.latex?k=10">) results in a smoother boundary that generalizes better.</p>
<p>Enough math. Let’s ball.</p>
</section>
</section>
<section id="pitch-tunneling-with-k-nn" class="level2">
<h2 class="anchored" data-anchor-id="pitch-tunneling-with-k-nn">Pitch Tunneling with K-NN</h2>
<p>For the first time in this blog, we will use <a href="https://github.com/jldbc/pybaseball">PyBaseball</a> to fetch data. PyBaseball is a Python package that provides an easy way to access baseball data from various sources, including MLB’s Statcast and Baseball Savant. We will first examine pitcher, Joe Ryan. According to baseball savant, Ryan currently has the highest fastball run value in 2025.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/k-nearest-neighbors/ff-run-value.png" class="img-fluid figure-img"></p>
<figcaption>Top 10 pitchers by run value for fastball.</figcaption>
</figure>
</div>
<p>Let’s first query the data for Joe Ryan.</p>
<p>Now that we have the data, let’s preprocess it to extract the relevant features and labels. We will focus on the <code>release_pos_x</code>, <code>release_pos_z</code>, and <code>release_extension</code> columns, as well as the <code>pitch_type</code> column. In addition, we will normalize the data to ensure that the features are on the same scale.</p>
<p>Magic time. The key step for using K-NN in this application is to not classify the pitches, but rather to find the nearest neighbors based on the features. We will use the <code>NearestNeighbors</code> class from <code>scikit-learn</code> to find the <img src="https://latex.codecogs.com/png.latex?k"> nearest neighbors for each pitch. Below is a Shiny app that allows you to analyze a pitcher’s tunneling ability using K-NN. By entering the pitcher’s first and last name, my app’s backend will fetch the pitcher’s data and compute the K-NN scores for the selected pitch type. The app will then display a report and a plot of the pitch types and their tunneling ability.</p>
<iframe height="600" width="100%" frameborder="no" src="https://runningonnumbers.shinyapps.io/pitch-tunnel-analysis/">
</iframe>
<p>You can view the full app <a href="https://runningonnumbers.shinyapps.io/pitch-tunnel-analysis/">here</a>.</p>
<p>The main limitation to using K-NN for pitch tunneling is that pitch types are evenly distributed. If a pitcher throws a pitch type very infrequently, then the K-NN scores will show a higher percentage of different pitch types. This is because the K-NN algorithm will find more pitches that are not of the same type, simply because there are fewer of that type in the dataset. This is why I set a minimum pitch threshold of 25 pitches for the target pitch type. If a pitcher has fewer than 25 pitches of a certain type, then the K-NN scores will not be reliable. Having said that, there is still merit in comparing the K-NN scores for a player’s main pitch.</p>
<p>To address the issue of uneven pitch distribution, we also provide a Log-Likelihood method to analyze pitch tunneling. This method calculates the likelihood of a pitch being of a certain type given its features, and it can be more robust to uneven distributions. We leverage the <code>scipy.stats</code> library to compute the log-likelihood of the pitch type given the features and compare it against the most frequently used other pitch (in other words, the secondary pitch). The app allows you to switch between K-NN and Log-Likelihood methods for analysis. The closer the log-likelihood score is to zero, the better the tunneling ability of the pitcher.</p>
<section id="the-payoff-results" class="level3">
<h3 class="anchored" data-anchor-id="the-payoff-results">The Payoff: Results</h3>
<p>Since we listed the top 10 pitchers by fastball run value, let’s analyze the tunneling ability of those pitchers. We refer to the K-NN Deception Score as “K-Score” and the log-likelihood score as “L-Score”.</p>
<table class="table-striped table-hover caption-top table">
<caption>Tunneling Metrics for Fastballs by Highest Run-Value</caption>
<thead>
<tr class="header">
<th>Pitcher</th>
<th>K-Score</th>
<th>L-Score</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1. Joe Ryan</td>
<td>40.86%</td>
<td>-0.32</td>
</tr>
<tr class="even">
<td>2. Nick Pivetta</td>
<td>41.58%</td>
<td>-0.34</td>
</tr>
<tr class="odd">
<td>3. Bryan Woo</td>
<td>48.71%</td>
<td>-0.23</td>
</tr>
<tr class="even">
<td>4. Hunter Brown</td>
<td>49.68%</td>
<td>-0.45</td>
</tr>
<tr class="odd">
<td>5. Ryne Nelson</td>
<td>24.36%</td>
<td>-0.84</td>
</tr>
<tr class="even">
<td>6. Andrew Abbott</td>
<td>40.66%</td>
<td>-0.46</td>
</tr>
<tr class="odd">
<td>7. Kevin Gausman</td>
<td>21.14%</td>
<td>-1.96</td>
</tr>
<tr class="even">
<td>8. Paul Skenes</td>
<td>52.06%</td>
<td>-0.37</td>
</tr>
<tr class="odd">
<td>9. Jacob deGrom</td>
<td>42.84%</td>
<td>-0.38</td>
</tr>
<tr class="even">
<td>10. Cade Smith</td>
<td>18.81%</td>
<td>-1.24</td>
</tr>
<tr class="odd">
<td><strong>Average</strong></td>
<td><strong>38.07%</strong></td>
<td><strong>-0.66</strong></td>
</tr>
</tbody>
</table>
<p>Sure, it is a small sample size but the top 10 are consistent with a K-Score of around 40% and an L-Score of around -0.3. The K-Score indicates that around 40% of the nearest neighbors for a pitch are of a different type, while the L-Score indicates that the log-likelihood of the pitch being of a certain type is close to zero, suggesting good tunneling ability.</p>
<p>Let’s see the bottom 10 pitchers by fastball run value.</p>
<table class="table-striped table-hover caption-top table">
<caption>Tunneling Metrics for Fastballs by Lowest Run-Value</caption>
<thead>
<tr class="header">
<th>Pitcher</th>
<th>K-Score</th>
<th>L-Score</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1. Germán Márquez</td>
<td>61.52%</td>
<td>-1.62</td>
</tr>
<tr class="even">
<td>2. Antonio Senzatela</td>
<td>34.33%</td>
<td>-1.04</td>
</tr>
<tr class="odd">
<td>3. Grant Holmes</td>
<td>62.81%</td>
<td>-0.11</td>
</tr>
<tr class="even">
<td>4. Angel Chivilli</td>
<td>46.16%</td>
<td>-0.35</td>
</tr>
<tr class="odd">
<td>5. Walker Buehler</td>
<td>65.59%</td>
<td>-0.13</td>
</tr>
<tr class="even">
<td>6. Chase Dollander</td>
<td>36.09%</td>
<td>-1.85</td>
</tr>
<tr class="odd">
<td>7. Bradley Blalock</td>
<td>31.08%</td>
<td>-3.37</td>
</tr>
<tr class="even">
<td>8. Austin Gomber</td>
<td>53.94%</td>
<td>-0.77</td>
</tr>
<tr class="odd">
<td>9. Osvaldo Bido</td>
<td>55.24%</td>
<td>-1.12</td>
</tr>
<tr class="even">
<td>10. Charlie Morton</td>
<td>56.79%</td>
<td>-0.72</td>
</tr>
<tr class="odd">
<td><strong>Average</strong></td>
<td><strong>50.36%</strong></td>
<td><strong>-1.11</strong></td>
</tr>
</tbody>
</table>
<p>Observe that this is where accounting for uneven pitch distribution is important. The average K-Score is around 50%, which is higher than the top 10 pitchers. However, the L-Score is around -1.11, which indicates that the log-likelihood of the pitch being of a certain type is further from zero, suggesting poorer tunneling ability. This is sizably lower than the top 10 pitchers, which had an average L-Score of around -0.66.</p>
<p>Let’s also take a look at the top 10 pitchers by slider run value in 2025.</p>
<table class="table-striped table-hover caption-top table">
<caption>Tunneling Metrics for Sliders by Highest Run-Value</caption>
<thead>
<tr class="header">
<th>Pitcher</th>
<th>K-Score</th>
<th>L-Score</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1. Chris Sale</td>
<td>23.48%</td>
<td>-1.76</td>
</tr>
<tr class="even">
<td>2. Andrés Muñoz</td>
<td>32.83%</td>
<td>-0.63</td>
</tr>
<tr class="odd">
<td>3. Steven Okert</td>
<td>39.92%</td>
<td>-0.21</td>
</tr>
<tr class="even">
<td>4. Carlos Rodón</td>
<td>24.77%</td>
<td>-7.70</td>
</tr>
<tr class="odd">
<td>5. Jacob deGrom</td>
<td>47.87%</td>
<td>-0.43</td>
</tr>
<tr class="even">
<td>6. Dylan Lee</td>
<td>30.26%</td>
<td>-1.20</td>
</tr>
<tr class="odd">
<td>7. Ryan Helsley</td>
<td>48.46%</td>
<td>-0.36</td>
</tr>
<tr class="even">
<td>8. Grant Holmes</td>
<td>62.64%</td>
<td>-0.14</td>
</tr>
<tr class="odd">
<td>9. Bennett Sousa</td>
<td>34.65%</td>
<td>-0.72</td>
</tr>
<tr class="even">
<td>10. Josh Hader</td>
<td>21.88%</td>
<td>-3.61</td>
</tr>
<tr class="odd">
<td><strong>Average</strong></td>
<td><strong>36.68%</strong></td>
<td><strong>-1.68</strong></td>
</tr>
</tbody>
</table>
<p>The bottom 10 pitchers by slider run value in 2025.</p>
<table class="table-striped table-hover caption-top table">
<caption>Tunneling Metrics for Sliders by Lowest Run-Value</caption>
<thead>
<tr class="header">
<th>Pitcher</th>
<th>K-Score</th>
<th>L-Score</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1. Scott Blewett</td>
<td>45.01%</td>
<td>-0.98</td>
</tr>
<tr class="even">
<td>2. Ryan Pepiot</td>
<td>68.63%</td>
<td>-2.06</td>
</tr>
<tr class="odd">
<td>3. Brandon Eisert</td>
<td>56.90%</td>
<td>-0.08</td>
</tr>
<tr class="even">
<td>4. Sean Burke</td>
<td>53.49%</td>
<td>-0.98</td>
</tr>
<tr class="odd">
<td>5. Bailey Falter</td>
<td>56.74%</td>
<td>-2.37</td>
</tr>
<tr class="even">
<td>6. Mitch Spence</td>
<td>38.11%</td>
<td>-1.66</td>
</tr>
<tr class="odd">
<td>7. Antonio Senzatela</td>
<td>60.22%</td>
<td>-0.86</td>
</tr>
<tr class="even">
<td>8. Justin Verlander</td>
<td>68.12%</td>
<td>-0.71</td>
</tr>
<tr class="odd">
<td>9. Patrick Corbin</td>
<td>52.00%</td>
<td>-1.58</td>
</tr>
<tr class="even">
<td>10. Chad Green</td>
<td>46.17%</td>
<td>-0.23</td>
</tr>
<tr class="odd">
<td><strong>Average</strong></td>
<td><strong>54.54%</strong></td>
<td><strong>-1.15</strong></td>
</tr>
</tbody>
</table>
<p>Among sliders, we see a different trend. The comparing the top 10 pitchers by slider run value to the bottom 10 pitchers by slider run value, we see that the K-Score is lower for the top 10 pitchers (36.68%) compared to the bottom 10 pitchers (54.54%). However, the L-Score is also lower for the top 10 pitchers (-1.68) compared to the bottom 10 pitchers (-1.15). This sort of contradictcs a hypothesis I had that the top pitchers would have a higher K-Score and a lower L-Score. There is something to be said about pitch movement and how “unhittable” a pitch is. If we really wanted to quantify pitch tunneling, we would need to consider the movement of the pitches as well - but that’s a topic for another day.</p>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>Pitch tunneling has always felt more like art than science, a ‘you know it when you see it’ kind of skill. The goal here was to drag it out of the shadows of intuition and into the bright, unforgiving light of data. We started with two statistical tools, K-Nearest Neighbors and Log-Likelihood, not as perfect solutions, but as instruments to see what could be seen.</p>
<p>From these methods, we developed the K-Score and L-Score, our first-draft attempt at a true deception metric. They represent a new way to look at the game’s oldest duel: pitcher versus batter. But a new number on a spreadsheet is just that—a number. The real work begins now. These scores need to be tested against more seasons, more pitchers, and more outcomes. We need to see if the pitchers who score well are, in fact, the same ones who consistently make the best hitters look foolish.</p>
<p>This is less of an endpoint and more of a promising lead. The search is on for a reliable, quantifiable measure of a pitcher’s craft. If the K-Score and L-Score—or some future, more refined version of them—can prove their mettle, they could offer a new edge in evaluating talent, a new tool for pitchers honing their art, and for the rest of us, a new window into the subtle genius of keeping a hitter guessing.</p>
<iframe src="https://streamable.com/m/shea-langeliers-strikes-out-swinging-1wyem6?partnerId=web_video-playback-page_video-share" width="560" height="315" alt="Joe Ryan striking out Shea Langeliers">
</iframe>
<hr>
<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>Past articles: - <a href="https://runningonnumbers.com/posts/logistic-regression/">Logistic Regression</a> - <a href="https://runningonnumbers.com/posts/support-vector-machine/">Support Vector Machine</a> - <a href="https://runningonnumbers.com/posts/k-means/">K-Means Clustering</a> Github: - <a href="https://github.com/oliverc1623/Running-On-Numbers-Public">Running on Numbers</a></p>
</div>
</div>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->


</section>

<div id="quarto-appendix" class="default"><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" data-entry-spacing="0">
<div id="ref-noauthor_k-nearest_nodate" class="csl-entry">
<span>“K-<span>Nearest</span> <span>Neighbor</span>(<span>KNN</span>) <span>Algorithm</span> - <span>GeeksforGeeks</span>.”</span> n.d. Accessed August 18, 2025. <a href="https://www.geeksforgeeks.org/machine-learning/k-nearest-neighbours/">https://www.geeksforgeeks.org/machine-learning/k-nearest-neighbours/</a>.
</div>
<div id="ref-enwiki:1285981318" class="csl-entry">
Wikipedia contributors. 2025. <span>“K-Nearest Neighbors Algorithm — <span>Wikipedia</span><span>,</span> the Free Encyclopedia.”</span> <a href="https://en.wikipedia.org/w/index.php?title=K-nearest_neighbors_algorithm&amp;oldid=1285981318">https://en.wikipedia.org/w/index.php?title=K-nearest_neighbors_algorithm&amp;oldid=1285981318</a>.
</div>
</div></section></div> ]]></description>
  <category>data science</category>
  <category>k-nearest neighbors</category>
  <category>scikit-learn</category>
  <category>python</category>
  <guid>https://runningonnumbers.com/posts/k-nearest-neighbors/</guid>
  <pubDate>Tue, 19 Aug 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/k-nearest-neighbors/pitch-tunnel.png" medium="image" type="image/png" height="96" width="144"/>
</item>
<item>
  <title>K-Means Clustering</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/k-means/</link>
  <description><![CDATA[ 





<iframe src="https://streamable.com/m/blake-parker-swinging-strike-to-leury-garcia-hn5edr?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<section id="introduction-the-problem-of-player-comps" class="level2">
<h2 class="anchored" data-anchor-id="introduction-the-problem-of-player-comps">Introduction: The Problem of “Player Comps”</h2>
<p>“Who does this guy remind you of?” For decades, player comparisons—or “comps”—have been a cornerstone of how we talk about baseball. We’ve relied on simple, useful archetypes: the “power hitter,” the “contact hitter,” the “speedster,” the “ace.” While handy, these labels have always been oversimplified. Take a modern star like Juan Soto. Is he just a “power hitter”? This label would ignore his elite plate discipline and on-base skills.</p>
<p>In today’s Statcast era, we have access to a wealth of data that can help us move beyond these simplistic labels. Can we create a more nuanced understanding of player similarities? Instead of relying on subjective comparisons, we can use data-driven methods to identify player archetypes based on their actual performance metrics.</p>
<section id="enter-k-means-clustering" class="level3">
<h3 class="anchored" data-anchor-id="enter-k-means-clustering">Enter K-Means Clustering</h3>
<p>In this post, we’ll explore how to use K-Means clustering, an unsupervised machine learning technique, to group players based on their statistical profiles. By doing so, we can uncover natural groupings of players that share similar characteristics, leading to more meaningful and accurate player comparisons. We will first cluster players based on a broad range of statcast metrics, and then we will focus on a subset of three key metrics to illustrate the process.</p>
<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>In our previous posts, we have covered <a href="https://runningonnumbers.com/posts/logistic-regression/">logistic regression</a>, <a href="https://runningonnumbers.com/posts/support-vector-machine/">support vector machines</a>, and <a href="https://runningonnumbers.com/posts/fast-swings-and-barrels/">decision trees</a> - these are all supervised learning techniques. K-Means clustering is a different beast altogether, as it is an unsupervised learning technique. This means we do not have labeled data to train on; instead, we are trying to find patterns in the data without any prior knowledge of the outcomes.</p>
</div>
</div>
<p>The data we will use comes from <a href="https://baseballsavant.mlb.com/">Baseball Savant</a>, specifically the percentile rankings for various offensive metrics. You can download the data <a href="https://baseballsavant.mlb.com/leaderboard/percentile-rankings?type=batter&amp;team=">here</a>. We use the 2025 season data for this analysis. The reason why we use percentile rankings is that they standardize the metrics, allowing us to compare players on a relative scale. They put every player on a 0-100 scale for each metric, making it easier to identify similarities and differences.</p>
</section>
</section>
<section id="k-means-clustering-overview" class="level2">
<h2 class="anchored" data-anchor-id="k-means-clustering-overview">K-Means Clustering Overview</h2>
<p>Picture this: you are a shelf-stocker at a grocery store. Your goal is to organize items in a giant, messy supermarket into neat, organized sections. You want to group similar items together, like all the cereals in one aisle, all the snacks in another, and so on. This is essentially what K-Means clustering does with data.</p>
<p>Step 1: <strong>Choose the Number of Clusters (K)</strong> - You decide how many groups (clusters) you want to create. This is like deciding how many aisles you want in the store. For example, you might choose 5 aisles for cereals, snacks, beverages, dairy, and produce.</p>
<p>Step 2: <strong>Randomly Place Cluster Centers</strong> - You randomly place a few points in the store to represent the center of each aisle. These points are called “centroids.” They are like the managers of each aisle, guiding where items should go.</p>
<p>Step 3: <strong>Assign Items to Clusters</strong> - You look at each item in the store and decide which aisle it belongs to based on its proximity to the centroids. If a cereal box is closest to the cereal aisle centroid, you put it there. This is like assigning items to the right shelves based on their characteristics.</p>
<p>Step 4: <strong>Update Cluster Centers</strong> - After assigning items, you check the centroids again. You calculate the average position of all items in each aisle and move the centroids to these new positions. This is like the aisle managers adjusting their positions based on where the items are now located.</p>
<p>Step 5: <strong>Repeat Until Stable</strong> - You repeat steps 3 and 4 until the centroids stop moving significantly. This means the aisles are now stable, and items are grouped as best as possible. You have successfully organized the store!</p>
<p>In our baseball analogy, the players are the items in the store, and the clusters are the aisles. The metrics we use to compare players are like the characteristics of the items. By applying K-Means clustering, we can group players with similar performance profiles together, just like organizing items into their respective aisles.</p>
<section id="under-the-hood-how-k-means-works" class="level3">
<h3 class="anchored" data-anchor-id="under-the-hood-how-k-means-works">Under the Hood: How K-Means Works</h3>
<p>The goal of K-means is the partition a dataset into sets, <img src="https://latex.codecogs.com/png.latex?S=%5C%7BS_1,%20S_2,%20%5Cdots,%20S_k%5C%7D">. Each set is to minimize the within-cluster sum of squares (WCSS), in other words, variance. More formally,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bargmin%7D_s%20%5Csum_%7Bi=1%7D%5E%7Bk%7D%20%5Csum_%7Bx%20%5Cin%20S_i%7D%20%5C%7Cx%20-%20%5Cmu_i%5C%7C%5E2%20=%20%5Ctext%7Bargmin%7D_s%20%5Csum_%7Bi=1%7D%5E%7Bk%7D%20%7CS_i%7C%5E2%20Var%20S_i"> where <img src="https://latex.codecogs.com/png.latex?%5Cmu_i"> is the centroid of cluster <img src="https://latex.codecogs.com/png.latex?S_i"> and <img src="https://latex.codecogs.com/png.latex?%7CS_i%7C"> is the number of points in cluster <img src="https://latex.codecogs.com/png.latex?S_i">. The algorithm works by iteratively updating the centroids and reassigning points to clusters until convergence. This is based off Wikipedia’s <a href="https://en.wikipedia.org/wiki/K-means_clustering">K-means clustering</a> article.</p>
<p>The algorithm itself goes as follows: Given a set of <img src="https://latex.codecogs.com/png.latex?k"> clusters, <img src="https://latex.codecogs.com/png.latex?C%20=%20%5C%7Bc_1,%20c_2,%20%5Cdots,%20c_k%5C%7D">, and a set of data points <img src="https://latex.codecogs.com/png.latex?X%20=%20%5C%7Bx_1,%20x_2,%20%5Cdots,%20x_n%5C%7D">:</p>
<ol type="1">
<li><strong>Assignment Step</strong>: Assign each data point <img src="https://latex.codecogs.com/png.latex?x_i"> to the cluster <img src="https://latex.codecogs.com/png.latex?c_j"> that is closest to it, based on the distance metric (usually Euclidean distance). <img src="https://latex.codecogs.com/png.latex?%20S_j%5E%7B(t)%7D%20=%20%5C%7Bx_i%20%5Cin%20X%20%5C;%20%7C%20%5C;%20%5C%7Cx_i%20-%20c_j%5C%7C%5E2%20%5Cleq%20%5C%7Cx_i%20-%20c_k%5C%7C%5E2,%20%5Cforall%20k%20%5Cneq%20j%5C%7D%20"></li>
<li><strong>Update Step</strong>: Recalculate the centroids of each cluster based on the assigned points. <img src="https://latex.codecogs.com/png.latex?%20c_j%5E%7B(t+1)%7D%20=%20%5Cfrac%7B1%7D%7B%7CS_j%5E%7B(t)%7D%7C%7D%20%5Csum_%7Bx%20%5Cin%20S_j%5E%7B(t)%7D%7D%20x%20"> where <img src="https://latex.codecogs.com/png.latex?S_j%5E%7B(t)%7D"> is the set of points assigned to cluster <img src="https://latex.codecogs.com/png.latex?c_j"> at iteration <img src="https://latex.codecogs.com/png.latex?t">.</li>
<li><strong>Repeat</strong>: Repeat the assignment and update steps until the centroids do not change significantly or a maximum number of iterations is reached.</li>
</ol>
<p>The million dollar question is how many clusters should we use? The answer is not always straightforward, but there are methods to help us decide. The <strong>Elbow-Method</strong> is a common technique to determine the optimal number of clusters. It involves plotting the sum of squared distances (inertia) between data points and their assigned cluster centers for different values of K. The idea is to find the “elbow” point in the plot, where adding more clusters yields diminishing returns in reducing inertia. Let’s visualize this with sample data.</p>
<div id="66e06498" class="cell" data-execution_count="1">
<details class="code-fold">
<summary>Code</summary>
<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="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-2"><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-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.cluster <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> KMeans</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.datasets <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_blobs</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create synthetic dataset</span></span>
<span id="cb1-8">X, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_blobs(n_samples<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;">300</span>, centers<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;">4</span>, cluster_std<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.60</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;">0</span>)</span>
<span id="cb1-9">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(X, 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;">'feature1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'feature2'</span>])</span>
<span id="cb1-10"></span>
<span id="cb1-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate inertia for different values of K</span></span>
<span id="cb1-12">inertia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb1-13">k_range <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</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;">11</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Testing K from 2 to 10</span></span>
<span id="cb1-14"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> k_range:</span>
<span id="cb1-15">    kmeans <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KMeans(n_clusters<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k, init<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;">'k-means++'</span>, n_init<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;">'auto'</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="cb1-16">    kmeans.fit(df)</span>
<span id="cb1-17">    inertia.append(kmeans.inertia_)</span>
<span id="cb1-18"></span>
<span id="cb1-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plotting the Elbow Method</span></span>
<span id="cb1-20">plt.figure(figsize<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb1-21">plt.plot(k_range, inertia, marker<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="cb1-22">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Elbow Method for Optimal K'</span>)</span>
<span id="cb1-23">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Number of Clusters (K)'</span>)</span>
<span id="cb1-24">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Inertia (Sum of Squared Distances)'</span>)</span>
<span id="cb1-25">plt.xticks(k_range)</span>
<span id="cb1-26">plt.grid()</span>
<span id="cb1-27">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/k-means/index_files/figure-html/cell-2-output-1.png" width="825" height="523" class="figure-img"></p>
<figcaption>Elbow Method for Optimal K</figcaption>
</figure>
</div>
</div>
</div>
<p>Based on the elbow plot, we can see that the inertia decreases as we increase K, but there is a point where the decrease becomes less significant. This point is where we should choose our optimal K. For the iris dataset, it appears that K=3 is a good choice, as the inertia reduction slows down significantly after that point. Now that we have our optimal K, we can proceed with clustering the data.</p>
<div id="2004e27e" class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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 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="cb2-2"></span>
<span id="cb2-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> SimpleKMeans:</span>
<span id="cb2-4">    <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>, n_clusters<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;">4</span>, max_iters<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>, 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="cb2-5">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.n_clusters <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> n_clusters</span>
<span id="cb2-6">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.max_iters <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> max_iters</span>
<span id="cb2-7">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.random_state <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> random_state</span>
<span id="cb2-8">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.centroids <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="cb2-9">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.labels <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="cb2-10"></span>
<span id="cb2-11">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> _initialize_centroids(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, X):</span>
<span id="cb2-12">        np.random.seed(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.random_state)</span>
<span id="cb2-13">        random_indices <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.permutation(X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb2-14">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.centroids <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[random_indices[:<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.n_clusters]]</span>
<span id="cb2-15"></span>
<span id="cb2-16">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> _assign_clusters(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, X):</span>
<span id="cb2-17">        distances <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sqrt(((X <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>.centroids[:, np.newaxis])<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 class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</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;">2</span>))</span>
<span id="cb2-18">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.argmin(distances, 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;">0</span>)</span>
<span id="cb2-19"></span>
<span id="cb2-20">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> _update_centroids(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, X, labels):</span>
<span id="cb2-21">        new_centroids <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros((<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.n_clusters, X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]))</span>
<span id="cb2-22">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.n_clusters):</span>
<span id="cb2-23">            cluster_points <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> k]</span>
<span id="cb2-24">            <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;">len</span>(cluster_points) <span class="op" 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>
<span id="cb2-25">                new_centroids[k] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cluster_points.mean(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;">0</span>)</span>
<span id="cb2-26">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> new_centroids</span>
<span id="cb2-27"></span>
<span id="cb2-28">    <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):</span>
<span id="cb2-29">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>._initialize_centroids(X)</span>
<span id="cb2-30">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.max_iters):</span>
<span id="cb2-31">            <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.labels <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>._assign_clusters(X)</span>
<span id="cb2-32">            new_centroids <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>._update_centroids(X, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.labels)</span>
<span id="cb2-33">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">all</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.centroids <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> new_centroids):</span>
<span id="cb2-34">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span></span>
<span id="cb2-35">            <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.centroids <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> new_centroids</span>
<span id="cb2-36">        <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="cb2-37"></span>
<span id="cb2-38"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Using the same synthetic data from before</span></span>
<span id="cb2-39">X, _ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_blobs(n_samples<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;">300</span>, centers<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;">4</span>, cluster_std<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.60</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;">0</span>)</span>
<span id="cb2-40"></span>
<span id="cb2-41"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit the custom KMeans model</span></span>
<span id="cb2-42">custom_kmeans <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SimpleKMeans(n_clusters<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;">4</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="cb2-43">custom_kmeans.fit(X)</span>
<span id="cb2-44">custom_labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> custom_kmeans.labels</span>
<span id="cb2-45"></span>
<span id="cb2-46"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot the results</span></span>
<span id="cb2-47">plt.figure(figsize<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb2-48">sns.scatterplot(x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], hue<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>custom_labels, palette<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;">'viridis'</span>, s<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="cb2-49">plt.scatter(custom_kmeans.centroids[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], custom_kmeans.centroids[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], </span>
<span id="cb2-50">            s<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;">300</span>, c<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;">'red'</span>, marker<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;">'X'</span>, label<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;">'Centroids'</span>)</span>
<span id="cb2-51">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'K-Means Clustering from Scratch'</span>)</span>
<span id="cb2-52">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Feature 1'</span>)</span>
<span id="cb2-53">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Feature 2'</span>)</span>
<span id="cb2-54">plt.legend()</span>
<span id="cb2-55">plt.grid()</span>
<span id="cb2-56">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/k-means/index_files/figure-html/cell-3-output-1.png" width="799" height="523" class="figure-img"></p>
<figcaption>K-Means Clustering from Scratch</figcaption>
</figure>
</div>
</div>
</div>
<p>The algorithm has successfully grouped the data points into clusters based on their features. Each color represents a different cluster, and we can see how the points are distributed across the feature space.</p>
</section>
</section>
<section id="the-payoff---profiling-mlb-players-with-k-means" class="level2">
<h2 class="anchored" data-anchor-id="the-payoff---profiling-mlb-players-with-k-means">The Payoff - Profiling MLB Players with K-Means</h2>
<p>Now that we have a solid understanding of K-Means clustering, let’s apply it to our baseball data. We will use the percentile rankings for various offensive metrics to cluster players and identify their profiles.</p>
<div id="259fe122" class="cell" data-execution_count="3">
<details class="code-fold">
<summary>Code</summary>
<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">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"percentile_rankings.csv"</span>)</span>
<span id="cb3-2">df.sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xwoba"</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>).head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="3">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">player_name</th>
<th data-quarto-table-cell-role="th">player_id</th>
<th data-quarto-table-cell-role="th">year</th>
<th data-quarto-table-cell-role="th">xwoba</th>
<th data-quarto-table-cell-role="th">xba</th>
<th data-quarto-table-cell-role="th">xslg</th>
<th data-quarto-table-cell-role="th">xiso</th>
<th data-quarto-table-cell-role="th">xobp</th>
<th data-quarto-table-cell-role="th">brl</th>
<th data-quarto-table-cell-role="th">brl_percent</th>
<th data-quarto-table-cell-role="th">...</th>
<th data-quarto-table-cell-role="th">k_percent</th>
<th data-quarto-table-cell-role="th">bb_percent</th>
<th data-quarto-table-cell-role="th">whiff_percent</th>
<th data-quarto-table-cell-role="th">chase_percent</th>
<th data-quarto-table-cell-role="th">arm_strength</th>
<th data-quarto-table-cell-role="th">sprint_speed</th>
<th data-quarto-table-cell-role="th">oaa</th>
<th data-quarto-table-cell-role="th">bat_speed</th>
<th data-quarto-table-cell-role="th">squared_up_rate</th>
<th data-quarto-table-cell-role="th">swing_length</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">326</td>
<td>Soto, Juan</td>
<td>665742</td>
<td>2025</td>
<td>100.0</td>
<td>98.0</td>
<td>99.0</td>
<td>99.0</td>
<td>100.0</td>
<td>98.0</td>
<td>96.0</td>
<td>...</td>
<td>63.0</td>
<td>100.0</td>
<td>64.0</td>
<td>100.0</td>
<td>58.0</td>
<td>14</td>
<td>2.0</td>
<td>69.0</td>
<td>91.0</td>
<td>77.0</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">536</td>
<td>Judge, Aaron</td>
<td>592450</td>
<td>2025</td>
<td>100.0</td>
<td>99.0</td>
<td>100.0</td>
<td>100.0</td>
<td>99.0</td>
<td>100.0</td>
<td>100.0</td>
<td>...</td>
<td>20.0</td>
<td>99.0</td>
<td>1.0</td>
<td>75.0</td>
<td>89.0</td>
<td>37</td>
<td>79.0</td>
<td>97.0</td>
<td>14.0</td>
<td>2.0</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">529</td>
<td>Schwarber, Kyle</td>
<td>656941</td>
<td>2025</td>
<td>99.0</td>
<td>73.0</td>
<td>99.0</td>
<td>99.0</td>
<td>97.0</td>
<td>98.0</td>
<td>99.0</td>
<td>...</td>
<td>16.0</td>
<td>97.0</td>
<td>8.0</td>
<td>87.0</td>
<td>NaN</td>
<td>16</td>
<td>NaN</td>
<td>98.0</td>
<td>36.0</td>
<td>19.0</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">78</td>
<td>Ohtani, Shohei</td>
<td>660271</td>
<td>2025</td>
<td>99.0</td>
<td>86.0</td>
<td>100.0</td>
<td>100.0</td>
<td>94.0</td>
<td>100.0</td>
<td>100.0</td>
<td>...</td>
<td>14.0</td>
<td>96.0</td>
<td>3.0</td>
<td>59.0</td>
<td>NaN</td>
<td>67</td>
<td>NaN</td>
<td>95.0</td>
<td>36.0</td>
<td>3.0</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">173</td>
<td>Guerrero Jr., Vladimir</td>
<td>665489</td>
<td>2025</td>
<td>98.0</td>
<td>100.0</td>
<td>94.0</td>
<td>78.0</td>
<td>100.0</td>
<td>95.0</td>
<td>84.0</td>
<td>...</td>
<td>88.0</td>
<td>93.0</td>
<td>70.0</td>
<td>91.0</td>
<td>36.0</td>
<td>34</td>
<td>22.0</td>
<td>97.0</td>
<td>84.0</td>
<td>19.0</td>
</tr>
</tbody>
</table>

<p>5 rows × 23 columns</p>
</div>
</div>
</div>
<p>The percentile rankings dataset contains various offensive metrics for players, such as xwOBA, xBA, and xSLG. For this application, we will use <code>xba</code>, <code>xslg</code>, <code>xiso</code>, and <code>xobp</code>. These metrics provide a comprehensive view of a player’s offensive performance, allowing us to cluster players based on their hitting profiles.</p>
<div id="50e06364" class="cell" data-execution_count="4">
<details class="code-fold">
<summary>Code</summary>
<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">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;">"xba"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xslg"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xiso"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xobp"</span>]</span>
<span id="cb4-2">df_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[features]</span>
<span id="cb4-3">df_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_k.dropna()</span>
<span id="cb4-4">df_k <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_k.sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xslg"</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="cb4-5">df_k.head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="4">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">xba</th>
<th data-quarto-table-cell-role="th">xslg</th>
<th data-quarto-table-cell-role="th">xiso</th>
<th data-quarto-table-cell-role="th">xobp</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">78</td>
<td>86.0</td>
<td>100.0</td>
<td>100.0</td>
<td>94.0</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">536</td>
<td>99.0</td>
<td>100.0</td>
<td>100.0</td>
<td>99.0</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">529</td>
<td>73.0</td>
<td>99.0</td>
<td>99.0</td>
<td>97.0</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">326</td>
<td>98.0</td>
<td>99.0</td>
<td>99.0</td>
<td>100.0</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">475</td>
<td>94.0</td>
<td>98.0</td>
<td>96.0</td>
<td>97.0</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>Let’s apply the Elbow method to determine the optimal number of clusters for our baseball data. We will plot the inertia for different values of K and look for the “elbow” point.</p>
<div id="7fd4ce2c" class="cell" data-execution_count="5">
<details class="code-fold">
<summary>Code</summary>
<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 class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.cluster <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> KMeans</span>
<span id="cb5-2"><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="cb5-3"></span>
<span id="cb5-4">inertia <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb5-5">k_values <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>)</span>
<span id="cb5-6"></span>
<span id="cb5-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> k_values:</span>
<span id="cb5-8">    kmeans <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KMeans(n_clusters<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>k, 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="cb5-9">    kmeans.fit(df_k)</span>
<span id="cb5-10">    inertia.append(kmeans.inertia_)</span>
<span id="cb5-11"></span>
<span id="cb5-12">plt.figure(figsize<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb5-13">plt.plot(k_values, inertia, marker<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-14">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Elbow Method for Optimal K'</span>)</span>
<span id="cb5-15">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Number of Clusters (K)'</span>)</span>
<span id="cb5-16">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Inertia'</span>)</span>
<span id="cb5-17">plt.xticks(k_values)</span>
<span id="cb5-18">plt.grid()</span>
<span id="cb5-19">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/k-means/index_files/figure-html/cell-6-output-1.png" width="842" height="523" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>Looking at the elbow plot, we can see that the inertia decreases as we increase K, but there is a point where the decrease becomes less significant. This point is where we should choose our optimal K. For our dataset, it appears that <img src="https://latex.codecogs.com/png.latex?K=6"> is a good choice, as the inertia reduction slows down significantly after that point.</p>
<section id="the-final-clustering" class="level3">
<h3 class="anchored" data-anchor-id="the-final-clustering">The Final Clustering</h3>
<div id="b8fd246c" class="cell" data-execution_count="6">
<details class="code-fold">
<summary>Code</summary>
<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">optimal_k <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;">6</span></span>
<span id="cb6-2">final_kmeans <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KMeans(n_clusters<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>optimal_k, init<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;">'k-means++'</span>, n_init<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;">'auto'</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="cb6-3">clusters <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> final_kmeans.fit_predict(df_k)</span>
<span id="cb6-4"></span>
<span id="cb6-5">cluster_names <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 class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Elite Slugger"</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;">"High-Average Hitter"</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;">"Contact Specialist"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Three True Outcome Hitter"</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;">"Low-Average Power Threat"</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;">"Struggling Hitter"</span>}</span>
<span id="cb6-6"></span>
<span id="cb6-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add the cluster labels back to a copy of our original dataframe</span></span>
<span id="cb6-8">results_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_k.loc[df_k.index].copy()</span>
<span id="cb6-9">results_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> clusters</span>
<span id="cb6-10"></span>
<span id="cb6-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># map cluster names to the cluster labels</span></span>
<span id="cb6-12">results_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> results_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">map</span>(cluster_names)</span>
<span id="cb6-13"></span>
<span id="cb6-14">cluster_profiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> results_df.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</span>)[features].mean().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb6-15">cluster_profiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cluster_profiles.sort_values(by<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>features, 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="cb6-16"></span>
<span id="cb6-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--- Cluster Profiles (Average Percentiles) ---"</span>)</span>
<span id="cb6-18">cluster_profiles.to_clipboard()</span>
<span id="cb6-19"></span>
<span id="cb6-20">cluster_profiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cluster_profiles.rename(index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>cluster_names)</span>
<span id="cb6-21">cluster_profiles</span></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>--- Cluster Profiles (Average Percentiles) ---</code></pre>
</div>
<div class="cell-output cell-output-display" data-execution_count="6">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">xba</th>
<th data-quarto-table-cell-role="th">xslg</th>
<th data-quarto-table-cell-role="th">xiso</th>
<th data-quarto-table-cell-role="th">xobp</th>
</tr>
<tr class="even">
<th data-quarto-table-cell-role="th">cluster</th>
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th"></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">Elite Slugger</td>
<td>80.5</td>
<td>91.8</td>
<td>89.3</td>
<td>89.7</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">High-Average Hitter</td>
<td>75.8</td>
<td>64.9</td>
<td>55.8</td>
<td>72.8</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">Contact Specialist</td>
<td>59.0</td>
<td>26.0</td>
<td>18.3</td>
<td>60.4</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">Three True Outcome Hitter</td>
<td>56.2</td>
<td>81.8</td>
<td>82.8</td>
<td>40.5</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">Low-Average Power Threat</td>
<td>30.3</td>
<td>50.8</td>
<td>59.0</td>
<td>32.6</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">Struggling Hitter</td>
<td>17.2</td>
<td>14.3</td>
<td>20.5</td>
<td>18.6</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>Here are the descriptions of each cluster based on their expected offensive performance percentiles.</p>
<ul>
<li><strong>Elite Slugger</strong>: Players in this cluster are expected to excel in all major offensive categories, with particularly high percentiles in xBA, xSLG, and xOBP.</li>
<li><strong>High-Average Hitter</strong>: This group consists of players who may not have the same power as the elite sluggers but still maintain strong overall offensive numbers, especially in batting average and on-base percentage.</li>
<li><strong>Contact Specialist</strong>: Players here are characterized by their ability to make contact and avoid strikeouts, often at the expense of power numbers.</li>
<li><strong>Three True Outcome Hitter</strong>: This cluster includes players who can slug, walk, or strike out, with less emphasis on traditional batting average.</li>
<li><strong>Low-Average Power Threat</strong>: These players have power potential but struggle with consistency and making contact.</li>
<li><strong>Struggling Hitter</strong>: This group consists of players who are below average in most offensive categories and may be at risk of losing their roster spots.</li>
</ul>
<p>The figure below visualizes the average percentiles for each cluster across the four metrics we used. Each cluster is represented by a different color, and the radar chart allows us to see how each cluster compares across the metrics.</p>
<div id="3a0d2e18" class="cell" data-execution_count="7">
<details class="code-fold">
<summary>Code</summary>
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Data from the user</span></span>
<span id="cb8-2">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb8-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Elite Slugger'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'High-Average Hitter'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Contact Specialist'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Three True Outcome Hitter'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Low-Average Power Threat'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Struggling Hitter'</span>],</span>
<span id="cb8-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xba'</span>: [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">80.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">75.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">59.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">56.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">30.3</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">17.2</span>],</span>
<span id="cb8-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xslg'</span>: [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">91.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">64.9</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">26.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">81.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">50.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">14.3</span>],</span>
<span id="cb8-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xiso'</span>: [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">89.3</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">55.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">18.3</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">82.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">59.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">20.5</span>],</span>
<span id="cb8-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xobp'</span>: [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">89.7</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">72.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">60.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">40.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">32.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">18.6</span>]</span>
<span id="cb8-8">}</span>
<span id="cb8-9">df_vis <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(data)</span>
<span id="cb8-10">df_vis <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_vis.set_index(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</span>)</span>
<span id="cb8-11"></span>
<span id="cb8-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Number of variables we're plotting.</span></span>
<span id="cb8-13">num_vars <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(df_vis.columns)</span>
<span id="cb8-14"></span>
<span id="cb8-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compute angle for each axis.</span></span>
<span id="cb8-16">angles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<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;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.pi, num_vars, endpoint<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>).tolist()</span>
<span id="cb8-17"></span>
<span id="cb8-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The plot is a circle, so we need to "complete the loop"</span></span>
<span id="cb8-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># and append the start to the end.</span></span>
<span id="cb8-20">angles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> angles[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb8-21"></span>
<span id="cb8-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Labels for each axis</span></span>
<span id="cb8-23">labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_vis.columns</span>
<span id="cb8-24"></span>
<span id="cb8-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create the figure and subplots</span></span>
<span id="cb8-26">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">9</span>), nrows<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>, ncols<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>, subplot_kw<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(polar<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="cb8-27">axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> axes.flatten() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Flatten the 3x2 grid of axes for easy iteration</span></span>
<span id="cb8-28"></span>
<span id="cb8-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define colors for each cluster</span></span>
<span id="cb8-30">colors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.cm.viridis(np.linspace(<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;">1</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(df_vis)))</span>
<span id="cb8-31"></span>
<span id="cb8-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot each cluster on a separate subplot</span></span>
<span id="cb8-33"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, (cluster_name, row) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(df_vis.iterrows()):</span>
<span id="cb8-34">    ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> axes[i]</span>
<span id="cb8-35">    values <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> row.tolist()</span>
<span id="cb8-36">    values <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> values[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># complete the loop</span></span>
<span id="cb8-37"></span>
<span id="cb8-38">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot the data</span></span>
<span id="cb8-39">    ax.plot(angles, values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>colors[i], linewidth<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-40">    ax.fill(angles, values, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>colors[i], 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.25</span>)</span>
<span id="cb8-41"></span>
<span id="cb8-42">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Prettify the plot</span></span>
<span id="cb8-43">    ax.set_rlim(<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;">100</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Set radial limits to be consistent (0-100 for percentiles)</span></span>
<span id="cb8-44">    ax.set_yticklabels([<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;">25</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;">75</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>])</span>
<span id="cb8-45">    ax.set_xticks(angles[:<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="cb8-46">    ax.set_xticklabels(labels, 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;">8</span>)</span>
<span id="cb8-47">    ax.set_title(cluster_name, 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;">12</span>, 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;">1.1</span>)</span>
<span id="cb8-48"></span>
<span id="cb8-49"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Adjust layout to prevent titles from overlapping</span></span>
<span id="cb8-50">plt.tight_layout(pad<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;">3.0</span>)</span>
<span id="cb8-51">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/k-means/index_files/figure-html/cell-8-output-1.png" width="666" height="801" class="figure-img"></p>
<figcaption>Cluster Profiles Radar Chart</figcaption>
</figure>
</div>
</div>
</div>
<p>Let’s take a closer look at the top players in each cluster to see how they compare.</p>
<section id="elite-sluggers" class="level4">
<h4 class="anchored" data-anchor-id="elite-sluggers">Elite Sluggers</h4>
<div id="f76844dd" class="cell" data-execution_count="8">
<details class="code-fold">
<summary>Code</summary>
<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">results_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> results_df.sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xslg'</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-2">results_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> results_df.merge(df[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'player_name'</span>]], left_index<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>, right_index<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>, 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;">'left'</span>)</span>
<span id="cb9-3">results_df[results_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</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;">"Elite Slugger"</span>].sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xslg'</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>).head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="8">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">xba</th>
<th data-quarto-table-cell-role="th">xslg</th>
<th data-quarto-table-cell-role="th">xiso</th>
<th data-quarto-table-cell-role="th">xobp</th>
<th data-quarto-table-cell-role="th">cluster</th>
<th data-quarto-table-cell-role="th">player_name</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">78</td>
<td>86.0</td>
<td>100.0</td>
<td>100.0</td>
<td>94.0</td>
<td>Elite Slugger</td>
<td>Ohtani, Shohei</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">536</td>
<td>99.0</td>
<td>100.0</td>
<td>100.0</td>
<td>99.0</td>
<td>Elite Slugger</td>
<td>Judge, Aaron</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">529</td>
<td>73.0</td>
<td>99.0</td>
<td>99.0</td>
<td>97.0</td>
<td>Elite Slugger</td>
<td>Schwarber, Kyle</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">326</td>
<td>98.0</td>
<td>99.0</td>
<td>99.0</td>
<td>100.0</td>
<td>Elite Slugger</td>
<td>Soto, Juan</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">475</td>
<td>94.0</td>
<td>98.0</td>
<td>96.0</td>
<td>97.0</td>
<td>Elite Slugger</td>
<td>Seager, Corey</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>For example, the top players in the “Elite Slugger” cluster are expected to have high xSLG and xOBP, indicating their ability to hit for both power and average. On paper, <a href="https://www.baseball-reference.com/players/s/seageco01.shtml">Corey Seager</a> might not have as high of an OPS as some of the other players, but his expected statistics suggest he is a top-tier slugger. That said, this list contains the usual suspects like <a href="https://www.baseball-reference.com/players/o/ohtansh01.shtml">Shohei Ohtani</a> and <a href="https://www.baseball-reference.com/players/j/judgeaa01.shtml">Aaron Judge</a>.</p>
</section>
<section id="high-average-hitters" class="level4">
<h4 class="anchored" data-anchor-id="high-average-hitters">High-Average Hitters</h4>
<div id="f132fdd1" class="cell" data-execution_count="9">
<details class="code-fold">
<summary>Code</summary>
<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">results_df[results_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</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;">"High-Average Hitter"</span>].sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xba'</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>).head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="9">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">xba</th>
<th data-quarto-table-cell-role="th">xslg</th>
<th data-quarto-table-cell-role="th">xiso</th>
<th data-quarto-table-cell-role="th">xobp</th>
<th data-quarto-table-cell-role="th">cluster</th>
<th data-quarto-table-cell-role="th">player_name</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">339</td>
<td>100.0</td>
<td>80.0</td>
<td>61.0</td>
<td>73.0</td>
<td>High-Average Hitter</td>
<td>Bichette, Bo</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">444</td>
<td>97.0</td>
<td>71.0</td>
<td>48.0</td>
<td>77.0</td>
<td>High-Average Hitter</td>
<td>Correa, Carlos</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">320</td>
<td>96.0</td>
<td>59.0</td>
<td>39.0</td>
<td>88.0</td>
<td>High-Average Hitter</td>
<td>Henderson, Gunnar</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">448</td>
<td>96.0</td>
<td>75.0</td>
<td>52.0</td>
<td>63.0</td>
<td>High-Average Hitter</td>
<td>García Jr., Luis</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">458</td>
<td>96.0</td>
<td>71.0</td>
<td>49.0</td>
<td>82.0</td>
<td>High-Average Hitter</td>
<td>Kirk, Alejandro</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>What do <a href="https://baseballsavant.mlb.com/savant-player/bo-bichette-666182?stats=statcast-r-hitting-mlb">Bo Bichette</a>, <a href="https://baseballsavant.mlb.com/savant-player/carlos-correa-621043?stats=statcast-r-hitting-mlb">Carlos Correa</a>, and <a href="https://baseballsavant.mlb.com/savant-player/gunnar-henderson-683002?stats=statcast-r-hitting-mlb">Gunnar Henderson</a> have in common? They are all expected to have high batting averages and on-base percentages, making them valuable assets to their teams. These players may not hit for as much power as the elite sluggers, but they excel at getting on base and making contact.</p>
</section>
<section id="contact-specialists" class="level4">
<h4 class="anchored" data-anchor-id="contact-specialists">Contact Specialists</h4>
<div id="94ee631b" class="cell" data-execution_count="10">
<details class="code-fold">
<summary>Code</summary>
<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">results_df[results_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</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;">"Contact Specialist"</span>].sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xba'</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>).head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="10">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">xba</th>
<th data-quarto-table-cell-role="th">xslg</th>
<th data-quarto-table-cell-role="th">xiso</th>
<th data-quarto-table-cell-role="th">xobp</th>
<th data-quarto-table-cell-role="th">cluster</th>
<th data-quarto-table-cell-role="th">player_name</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">17</td>
<td>93.0</td>
<td>6.0</td>
<td>1.0</td>
<td>51.0</td>
<td>Contact Specialist</td>
<td>Simpson, Chandler</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">49</td>
<td>88.0</td>
<td>21.0</td>
<td>6.0</td>
<td>59.0</td>
<td>Contact Specialist</td>
<td>Hoerner, Nico</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">35</td>
<td>88.0</td>
<td>18.0</td>
<td>4.0</td>
<td>49.0</td>
<td>Contact Specialist</td>
<td>Wilson, Jacob</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">348</td>
<td>86.0</td>
<td>24.0</td>
<td>10.0</td>
<td>91.0</td>
<td>Contact Specialist</td>
<td>Freeman, Tyler</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">488</td>
<td>86.0</td>
<td>13.0</td>
<td>3.0</td>
<td>35.0</td>
<td>Contact Specialist</td>
<td>Arraez, Luis</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>The “Contact Specialist” cluster includes players like <a href="https://baseballsavant.mlb.com/savant-player/luis-arraez-650333?stats=statcast-r-hitting-mlb">Luis Arraez</a> and <a href="https://baseballsavant.mlb.com/savant-player/nico-hoerner-663538?stats=statcast-r-hitting-mlb">Nico Hoerner</a>. These players are expected to have high batting averages and low strikeout rates, making them valuable for their ability to put the ball in play consistently. They may not hit for as much power, but their contact skills make them effective hitters.</p>
</section>
<section id="three-true-outcome-hitters" class="level4">
<h4 class="anchored" data-anchor-id="three-true-outcome-hitters">Three True Outcome Hitters</h4>
<div id="8347d992" class="cell" data-execution_count="11">
<details class="code-fold">
<summary>Code</summary>
<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">results_df[results_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</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;">"Three True Outcome Hitter"</span>].sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xslg'</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>).head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="11">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">xba</th>
<th data-quarto-table-cell-role="th">xslg</th>
<th data-quarto-table-cell-role="th">xiso</th>
<th data-quarto-table-cell-role="th">xobp</th>
<th data-quarto-table-cell-role="th">cluster</th>
<th data-quarto-table-cell-role="th">player_name</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">164</td>
<td>19.0</td>
<td>95.0</td>
<td>98.0</td>
<td>73.0</td>
<td>Three True Outcome Hitter</td>
<td>Raleigh, Cal</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">474</td>
<td>86.0</td>
<td>93.0</td>
<td>89.0</td>
<td>44.0</td>
<td>Three True Outcome Hitter</td>
<td>Perez, Salvador</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">494</td>
<td>54.0</td>
<td>92.0</td>
<td>95.0</td>
<td>51.0</td>
<td>Three True Outcome Hitter</td>
<td>Buxton, Byron</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">459</td>
<td>44.0</td>
<td>92.0</td>
<td>95.0</td>
<td>6.0</td>
<td>Three True Outcome Hitter</td>
<td>Carpenter, Kerry</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">244</td>
<td>64.0</td>
<td>91.0</td>
<td>92.0</td>
<td>63.0</td>
<td>Three True Outcome Hitter</td>
<td>Suzuki, Seiya</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>The Three True Outcome Hitter. This group is significant in that they represent the new wave of hitters who rely on power, patience, and selectvity at the plate. They are the result of the shift in baseball towards a more analytical approach to hitting. Players like <a href="https://baseballsavant.mlb.com/savant-player/cal-raleigh-663728?stats=statcast-r-hitting-mlb">Cal Raleigh</a> and <a href="https://baseballsavant.mlb.com/savant-player/byron-buxton-621439?stats=statcast-r-hitting-mlb">Byron Buxton</a> are prime examples of this cluster, as they are expected to have high slugging percentages and walk rates, but also high strikeout rates.</p>
</section>
<section id="low-average-power-threats" class="level4">
<h4 class="anchored" data-anchor-id="low-average-power-threats">Low-Average Power Threats</h4>
<div id="dded4b14" class="cell" data-execution_count="12">
<details class="code-fold">
<summary>Code</summary>
<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">results_df[results_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</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;">"Low-Average Power Threat"</span>].sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xba'</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>).head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="12">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">xba</th>
<th data-quarto-table-cell-role="th">xslg</th>
<th data-quarto-table-cell-role="th">xiso</th>
<th data-quarto-table-cell-role="th">xobp</th>
<th data-quarto-table-cell-role="th">cluster</th>
<th data-quarto-table-cell-role="th">player_name</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">208</td>
<td>79.0</td>
<td>52.0</td>
<td>42.0</td>
<td>19.0</td>
<td>Low-Average Power Threat</td>
<td>Harris II, Michael</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">75</td>
<td>60.0</td>
<td>52.0</td>
<td>46.0</td>
<td>17.0</td>
<td>Low-Average Power Threat</td>
<td>Chourio, Jackson</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">534</td>
<td>60.0</td>
<td>54.0</td>
<td>50.0</td>
<td>39.0</td>
<td>Low-Average Power Threat</td>
<td>Bellinger, Cody</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">272</td>
<td>58.0</td>
<td>45.0</td>
<td>40.0</td>
<td>25.0</td>
<td>Low-Average Power Threat</td>
<td>Wagaman, Eric</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">385</td>
<td>49.0</td>
<td>56.0</td>
<td>58.0</td>
<td>15.0</td>
<td>Low-Average Power Threat</td>
<td>Castellanos, Nick</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>This is a one-dimensional group of players. They provide above-average power, as seen in their xslg and xiso percentiles. However, they are very poor at getting on base (xobp) and hitting for average (xba), with both metrics falling in the bottom third of the league. They are a significant risk offensively, offering power but little else. Enter <a href="https://baseballsavant.mlb.com/savant-player/cody-bellinger-641355?stats=statcast-r-hitting-mlb">Cody Bellinger</a> and <a href="https://baseballsavant.mlb.com/savant-player/nick-castellanos-592206?stats=statcast-r-hitting-mlb">Nick Castellanos</a>, two players who have shown flashes of brilliance in the past but have struggled with consistency. They are expected to have high slugging percentages, but their batting averages may not be as high as other players.</p>
</section>
<section id="struggling-hitters" class="level4">
<h4 class="anchored" data-anchor-id="struggling-hitters">Struggling Hitters</h4>
<div id="fcfb2243" class="cell" data-execution_count="13">
<details class="code-fold">
<summary>Code</summary>
<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">results_df[results_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</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;">"Struggling Hitter"</span>].sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xba'</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>).head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="13">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">xba</th>
<th data-quarto-table-cell-role="th">xslg</th>
<th data-quarto-table-cell-role="th">xiso</th>
<th data-quarto-table-cell-role="th">xobp</th>
<th data-quarto-table-cell-role="th">cluster</th>
<th data-quarto-table-cell-role="th">player_name</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">186</td>
<td>46.0</td>
<td>19.0</td>
<td>15.0</td>
<td>28.0</td>
<td>Struggling Hitter</td>
<td>Winn, Masyn</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">9</td>
<td>41.0</td>
<td>32.0</td>
<td>30.0</td>
<td>29.0</td>
<td>Struggling Hitter</td>
<td>Myers, Dane</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">425</td>
<td>41.0</td>
<td>2.0</td>
<td>1.0</td>
<td>11.0</td>
<td>Struggling Hitter</td>
<td>Kiner-Falefa, Isiah</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">129</td>
<td>39.0</td>
<td>21.0</td>
<td>18.0</td>
<td>32.0</td>
<td>Struggling Hitter</td>
<td>Toro, Abraham</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">110</td>
<td>37.0</td>
<td>5.0</td>
<td>5.0</td>
<td>27.0</td>
<td>Struggling Hitter</td>
<td>Frazier, Adam</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>This cluster represents the least productive offensive players. The average player ranks in the bottom 20th percent across all four expected categories. They struggle to get on base, hit for average, or generate any kind of power. These players are likely experiencing significant slumps or are simply overmatched.</p>
<p>For those who are curious…</p>
<div id="fb4f57fc" class="cell" data-execution_count="14">
<details class="code-fold">
<summary>Code</summary>
<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">results_df[results_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cluster'</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;">"Struggling Hitter"</span>].sort_values(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xba'</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>).tail(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="14">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">xba</th>
<th data-quarto-table-cell-role="th">xslg</th>
<th data-quarto-table-cell-role="th">xiso</th>
<th data-quarto-table-cell-role="th">xobp</th>
<th data-quarto-table-cell-role="th">cluster</th>
<th data-quarto-table-cell-role="th">player_name</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">538</td>
<td>2.0</td>
<td>2.0</td>
<td>9.0</td>
<td>4.0</td>
<td>Struggling Hitter</td>
<td>Walls, Taylor</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">373</td>
<td>1.0</td>
<td>6.0</td>
<td>22.0</td>
<td>1.0</td>
<td>Struggling Hitter</td>
<td>Bailey, Patrick</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">518</td>
<td>1.0</td>
<td>2.0</td>
<td>11.0</td>
<td>4.0</td>
<td>Struggling Hitter</td>
<td>Sweeney, Trey</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">472</td>
<td>1.0</td>
<td>19.0</td>
<td>41.0</td>
<td>3.0</td>
<td>Struggling Hitter</td>
<td>Toglia, Michael</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">251</td>
<td>1.0</td>
<td>13.0</td>
<td>35.0</td>
<td>34.0</td>
<td>Struggling Hitter</td>
<td>Jansen, Danny</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>Using K-Means clustering, we discovered six distinct player profiles based on their expected offensive performance metrics. This approach allows us to move beyond simplistic player comparisons and gain a more nuanced understanding of player archetypes. By clustering players based on their actual performance data, we can identify similarities and differences that may not be immediately apparent through traditional scouting methods.</p>
<p>K-means has its limitations, such as sensitivity to the initial placement of centroids and the need to specify the number of clusters beforehand. This method requires a careful selection of features and preprocessing steps to ensure meaningful results, in addition to a heuristic-based approach to determine the optimal number of clusters. However, it remains a powerful tool for uncovering patterns in data and can be applied to various domains beyond baseball.</p>
<p>Data science isn’t here to replace baseball wisdom but to enhance it. This kind of analysis provides a new, powerful lens through which we can appreciate the diverse skill sets of the players we love to watch.</p>
<p>Look at Cody Bellinger this season. The numbers show his bat speed is ticking up. Just a little. But it’s there. Data science sees it as a player beginning to migrate from one cluster to another, a tiny tremor that might signal a return to the guy who won an MVP in 2019. It’s a reminder that these profiles aren’t destiny. They’re just a moment in time.</p>
<p>The data points are clues, but the players are still people. And people, thank God, can still surprise you.</p>
<iframe src="https://streamable.com/m/cody-bellinger-homers-21-on-a-fly-ball-to-right-center-field-0urbp0?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<hr>
<p>Past Aricles</p>
<ul>
<li><a href="https://runningonnumbers.com/posts/logistic-regression/">Logistic Regression</a></li>
<li><a href="https://runningonnumbers.com/posts/support-vector-machine/">Support Vector Machines</a></li>
<li><a href="https://runningonnumbers.com/posts/fast-swings-and-barrels/">Decision Trees</a></li>
</ul>
<p>GitHub:</p>
<ul>
<li><a href="https://github.com/oliverc1623/Running-On-Numbers-Public/blob/main/posts/k-means/main.py">Code</a></li>
</ul>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->

</section>

 ]]></description>
  <category>unsupervised learning</category>
  <category>clustering</category>
  <category>k-means</category>
  <category>scikit-learn</category>
  <guid>https://runningonnumbers.com/posts/k-means/</guid>
  <pubDate>Tue, 12 Aug 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/k-means/main.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>Same wOBA, Different Story</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/machado-soto-suarez-woba-xwoba/</link>
  <description><![CDATA[ 





<iframe src="https://streamable.com/mlbfilmroom/00u91h9ad3Lty1uCX356/genosotochado?partnerId=web_multimedia-search_video-share" width="560" height="315">
</iframe>
<section id="introduction-the-beauty-of-baseballs-numbers" class="level2">
<h2 class="anchored" data-anchor-id="introduction-the-beauty-of-baseballs-numbers">Introduction: The Beauty of Baseball’s Numbers</h2>
<p>Manny Machado, Juan Soto, and Eugenio Suarez are three all-star caliber baseball players. The trio consistently set baseball discourse ablaze. But there’s one question in baseball circles that has been debated for years: “Who is better?”</p>
<blockquote class="blockquote">
<p>Difference between .300 and .275 hitter is one hit every two weeks. If you see both 15 games a year, there’s a 40% chance that the .275 hitter will have more hits than the .300 hitter. - <a href="https://en.wikipedia.org/wiki/Moneyball:_The_Art_of_Winning_an_Unfair_Game">Moneyball</a>, Michael Lewis</p>
</blockquote>
<p>Sure, we can all watch them play, but baseball is a game of numbers. We cannot rely on our eyes, heuristics, or biases. In following the MLB trade deadline on Twitter, I saw a tweet from <a href="https://x.com/JeffPassan/status/1951747434549289092">Jeff Passan</a> that described Soto, Suarez, and Machado in three different aspects.</p>
<blockquote class="twitter-tweet blockquote" data-conversation="none" data-theme="dark">
<p lang="en" dir="ltr">
Great question, John. For most of baseball history, the walk was sneered at – a lesser form of getting on base compared to the exceptional skill it takes to swing. The analytical revolution in the game changed that. If the objective of the game is to outscore a team, then the…
</p>
— Jeff Passan (<span class="citation" data-cites="JeffPassan">@JeffPassan</span>) <a href="https://twitter.com/JeffPassan/status/1951747434549289092?ref_src=twsrc%5Etfw">August 2, 2025</a>
</blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>To summarize, Passan describes three metrics: batting average (<a href="https://www.mlb.com/glossary/standard-stats/batting-average">BA</a>), on-base percentage (<a href="https://www.mlb.com/glossary/standard-stats/on-base-percentage">OBP</a>), and slugging (<a href="https://www.mlb.com/glossary/standard-stats/slugging-percentage">SLG</a>). Passan shares the Moneyball principle in that modern statistics have turn to other statistics to evaluate a hitter; old baseball viewed walks as a “lesser” hit. Each of these metrics tells a different story about the players. BA is the simplest, describing how often a player gets a hit. OBP is the percentage of times a player reaches base, which includes hits, walks, and hit by pitches. Slugging is the total number of bases a player gets per at-bat, which includes singles, doubles, triples, and home runs - its like batting average but weighted by the type of hit.</p>
<p>Following the definitions, Passan shares slashlines for Machado, Soto, and Suarez. A slashline is a shorthand way to describe a player’s hitting statistics, typically in the format <code>BA/OBP/SLG</code>.</p>
<ul>
<li>Machado: .301/.360/.505</li>
<li>Soto: .247/.380/.480</li>
<li>Suarez: .245/.316/.565</li>
</ul>
<p>Machado is described as the best “all-around hitter” of the three, with the highest batting average. Soto is praised for his exceptional on-base skills. He is also in the 100th percentile for walk rate. Suarez is noted for his power-hitting ability.</p>
<div id="2a2bfd76" class="cell" data-execution_count="1">
<details class="code-fold">
<summary>Code</summary>
<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="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.graph_objects <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> go</span>
<span id="cb1-2"><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-3"></span>
<span id="cb1-4">image_urls <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb1-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://img.mlbstatic.com/mlb-photos/image/upload/d_people:generic:headshot:67:current.png/w_426,q_auto:best/v1/people/592518/headshot/67/current"</span>, <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Machado</span></span>
<span id="cb1-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://img.mlbstatic.com/mlb-photos/image/upload/d_people:generic:headshot:67:current.png/w_426,q_auto:best/v1/people/665742/headshot/67/current"</span>, <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Soto</span></span>
<span id="cb1-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://img.mlbstatic.com/mlb-photos/image/upload/d_people:generic:headshot:67:current.png/w_426,q_auto:best/v1/people/553993/headshot/67/current"</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Suárez</span></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;"># Data for the three players</span></span>
<span id="cb1-11">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb1-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Player'</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Manny Machado'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Juan Soto'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Eugenio Suárez'</span>],</span>
<span id="cb1-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BA'</span>: [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.301</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.247</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.245</span>],</span>
<span id="cb1-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'OBP'</span>: [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.360</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.380</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.316</span>],</span>
<span id="cb1-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SLG'</span>: [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.505</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.480</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.565</span>]</span>
<span id="cb1-16">}</span>
<span id="cb1-17"></span>
<span id="cb1-18">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(data)</span>
<span id="cb1-19"></span>
<span id="cb1-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create the figure</span></span>
<span id="cb1-21">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Figure()</span>
<span id="cb1-22"></span>
<span id="cb1-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add a bar trace for each statistic</span></span>
<span id="cb1-24">fig.add_trace(go.Bar(</span>
<span id="cb1-25">    x<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;">'Player'</span>],</span>
<span id="cb1-26">    y<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;">'BA'</span>],</span>
<span id="cb1-27">    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;">'Batting Avg (BA)'</span>,</span>
<span id="cb1-28">    marker_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;">'rgba(54, 162, 235, 0.7)'</span>,</span>
<span id="cb1-29">    hovertemplate<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;">{y:.3f}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">&lt;extra&gt;&lt;/extra&gt;'</span></span>
<span id="cb1-30">))</span>
<span id="cb1-31"></span>
<span id="cb1-32">fig.add_trace(go.Bar(</span>
<span id="cb1-33">    x<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;">'Player'</span>],</span>
<span id="cb1-34">    y<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;">'OBP'</span>],</span>
<span id="cb1-35">    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;">'On-Base % (OBP)'</span>,</span>
<span id="cb1-36">    marker_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;">'rgba(75, 192, 192, 0.7)'</span>,</span>
<span id="cb1-37">    hovertemplate<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;">{y:.3f}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">&lt;extra&gt;&lt;/extra&gt;'</span></span>
<span id="cb1-38">))</span>
<span id="cb1-39"></span>
<span id="cb1-40">fig.add_trace(go.Bar(</span>
<span id="cb1-41">    x<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;">'Player'</span>],</span>
<span id="cb1-42">    y<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;">'SLG'</span>],</span>
<span id="cb1-43">    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;">'Slugging % (SLG)'</span>,</span>
<span id="cb1-44">    marker_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;">'rgba(255, 99, 132, 0.7)'</span>,</span>
<span id="cb1-45">    hovertemplate<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;">{y:.3f}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">&lt;extra&gt;&lt;/extra&gt;'</span></span>
<span id="cb1-46">))</span>
<span id="cb1-47"></span>
<span id="cb1-48"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Add Headshot Images ---</span></span>
<span id="cb1-49"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, player <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Player'</span>]):</span>
<span id="cb1-50">    fig.add_layout_image(</span>
<span id="cb1-51">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb1-52">            source<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>image_urls[i],</span>
<span id="cb1-53">            xref<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;">"x"</span>,</span>
<span id="cb1-54">            yref<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;">"paper"</span>,</span>
<span id="cb1-55">            x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>player,  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use player name to anchor on x-axis</span></span>
<span id="cb1-56">            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.30</span>,    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Position below the x-axis</span></span>
<span id="cb1-57">            sizex<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.25</span>, <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Size of the image</span></span>
<span id="cb1-58">            sizey<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.25</span>,</span>
<span id="cb1-59">            xanchor<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="cb1-60">            yanchor<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;">"bottom"</span></span>
<span id="cb1-61">        )</span>
<span id="cb1-62">    )</span>
<span id="cb1-63"></span>
<span id="cb1-64"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Update the layout for a clean, grouped bar chart</span></span>
<span id="cb1-65">fig.update_layout(</span>
<span id="cb1-66">    barmode<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;">'group'</span>,</span>
<span id="cb1-67">    title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{</span>
<span id="cb1-68">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'text'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'&lt;b&gt;Player "Slash Line" Comparison&lt;/b&gt;'</span>,</span>
<span id="cb1-69">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>:<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span>,</span>
<span id="cb1-70">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>:<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>,</span>
<span id="cb1-71">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xanchor'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'center'</span>,</span>
<span id="cb1-72">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'yanchor'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'top'</span></span>
<span id="cb1-73">    },</span>
<span id="cb1-74">    xaxis_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;">'Player'</span>,</span>
<span id="cb1-75">    yaxis_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;">'Rate'</span>,</span>
<span id="cb1-76">    yaxis_range<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="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>],</span>
<span id="cb1-77">    legend_title_text<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;">'Statistic:'</span>,</span>
<span id="cb1-78">    legend<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb1-79">        orientation<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;">"h"</span>,</span>
<span id="cb1-80">        yanchor<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;">"bottom"</span>,</span>
<span id="cb1-81">        xanchor<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-82">        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;">1.02</span>,</span>
<span id="cb1-83">        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.2</span>,</span>
<span id="cb1-84">    ),</span>
<span id="cb1-85">    template<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;">'plotly_white'</span>,</span>
<span id="cb1-86">    font<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb1-87">        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;">"Inter, sans-serif"</span>,</span>
<span id="cb1-88">        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;">12</span></span>
<span id="cb1-89">    ),</span>
<span id="cb1-90">    margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(b<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;">120</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Increase bottom margin to make space for images</span></span>
<span id="cb1-91">)</span>
<span id="cb1-92"></span>
<span id="cb1-93"></span>
<span id="cb1-94"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Show the figure</span></span>
<span id="cb1-95">fig.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
        <script type="text/javascript">
        window.PlotlyConfig = {MathJaxConfig: 'local'};
        if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}
        </script>
        <script type="module">import "https://cdn.plot.ly/plotly-3.0.1.min"</script>
        
</div>
<div class="cell-output cell-output-display">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="a73586a9-db3d-4794-97ba-a09659d5b02e" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("a73586a9-db3d-4794-97ba-a09659d5b02e")) {                    Plotly.newPlot(                        "a73586a9-db3d-4794-97ba-a09659d5b02e",                        [{"hovertemplate":"%{y:.3f}\u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(54, 162, 235, 0.7)"},"name":"Batting Avg (BA)","x":["Manny Machado","Juan Soto","Eugenio Suárez"],"y":{"dtype":"f8","bdata":"3SQGgZVD0z8EVg4tsp3PP1yPwvUoXM8\u002f"},"type":"bar"},{"hovertemplate":"%{y:.3f}\u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(75, 192, 192, 0.7)"},"name":"On-Base % (OBP)","x":["Manny Machado","Juan Soto","Eugenio Suárez"],"y":{"dtype":"f8","bdata":"CtejcD0K1z9SuB6F61HYP9NNYhBYOdQ\u002f"},"type":"bar"},{"hovertemplate":"%{y:.3f}\u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(255, 99, 132, 0.7)"},"name":"Slugging % (SLG)","x":["Manny Machado","Juan Soto","Eugenio Suárez"],"y":{"dtype":"f8","bdata":"KVyPwvUo4D+4HoXrUbjePxSuR+F6FOI\u002f"},"type":"bar"}],                        {"template":{"data":{"barpolar":[{"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"type":"carpet"}],"choropleth":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"choropleth"}],"contourcarpet":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"contourcarpet"}],"contour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"contour"}],"heatmap":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"heatmap"}],"histogram2dcontour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2dcontour"}],"histogram2d":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2d"}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"mesh3d":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"mesh3d"}],"parcoords":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"parcoords"}],"pie":[{"automargin":true,"type":"pie"}],"scatter3d":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatter3d"}],"scattercarpet":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattercarpet"}],"scattergeo":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergeo"}],"scattergl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergl"}],"scattermapbox":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermapbox"}],"scattermap":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermap"}],"scatterpolargl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolargl"}],"scatterpolar":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolar"}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"scatterternary":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterternary"}],"surface":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"surface"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}]},"layout":{"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"autotypenumbers":"strict","coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]],"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]},"colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"geo":{"bgcolor":"white","lakecolor":"white","landcolor":"white","showlakes":true,"showland":true,"subunitcolor":"#C8D4E3"},"hoverlabel":{"align":"left"},"hovermode":"closest","mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30},"paper_bgcolor":"white","plot_bgcolor":"white","polar":{"angularaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""},"bgcolor":"white","radialaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""}},"scene":{"xaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"yaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"zaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"ternary":{"aaxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"baxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"bgcolor":"white","caxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""}},"title":{"x":0.05},"xaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2},"yaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2}}},"images":[{"sizex":0.25,"sizey":0.25,"source":"https:\u002f\u002fimg.mlbstatic.com\u002fmlb-photos\u002fimage\u002fupload\u002fd_people:generic:headshot:67:current.png\u002fw_426,q_auto:best\u002fv1\u002fpeople\u002f592518\u002fheadshot\u002f67\u002fcurrent","x":"Manny Machado","xanchor":"center","xref":"x","y":-0.3,"yanchor":"bottom","yref":"paper"},{"sizex":0.25,"sizey":0.25,"source":"https:\u002f\u002fimg.mlbstatic.com\u002fmlb-photos\u002fimage\u002fupload\u002fd_people:generic:headshot:67:current.png\u002fw_426,q_auto:best\u002fv1\u002fpeople\u002f665742\u002fheadshot\u002f67\u002fcurrent","x":"Juan Soto","xanchor":"center","xref":"x","y":-0.3,"yanchor":"bottom","yref":"paper"},{"sizex":0.25,"sizey":0.25,"source":"https:\u002f\u002fimg.mlbstatic.com\u002fmlb-photos\u002fimage\u002fupload\u002fd_people:generic:headshot:67:current.png\u002fw_426,q_auto:best\u002fv1\u002fpeople\u002f553993\u002fheadshot\u002f67\u002fcurrent","x":"Eugenio Suárez","xanchor":"center","xref":"x","y":-0.3,"yanchor":"bottom","yref":"paper"}],"title":{"text":"\u003cb\u003ePlayer \"Slash Line\" Comparison\u003c\u002fb\u003e","y":0.9,"x":0.5,"xanchor":"center","yanchor":"top"},"yaxis":{"title":{"text":"Rate"},"range":[0,0.6]},"legend":{"title":{"text":"Statistic:"},"orientation":"h","yanchor":"bottom","xanchor":"left","y":1.02,"x":0.2},"font":{"family":"Inter, sans-serif","size":12},"margin":{"b":120},"barmode":"group","xaxis":{"title":{"text":"Player"}}},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('a73586a9-db3d-4794-97ba-a09659d5b02e');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
</div>
</section>
<section id="what-is-woba" class="level2">
<h2 class="anchored" data-anchor-id="what-is-woba">What is wOBA?</h2>
<p>What I found most interesting is that all three players have the same wOBA (weighted on-base average) of .370 (or .369 for Soto, to be precise). If they have the same overall grade, how are they so different? And what can a deeper dive into the numbers tell us about who might be the “best” of the three?</p>
<p><a href="https://www.mlb.com/glossary/advanced-stats/weighted-on-base-average">wOBA</a> is a more advanced metric that combines a player’s ability to get on base and hit for power into a single number. It assigns different weights to different types of hits and events, providing a more comprehensive measure of a player’s offensive contribution. Weights for wOBA are derived from the run expectancy of each event, making it a more accurate reflection of a player’s value than traditional stats like BA, OBP, or SLG.</p>
<p>You can think of wOBA as a GPA-like metric for hitters. A single is a C, a double is a B, a home run is an A, a walk is a B-, and a strikeout is an F. wOBA averages all those grades together. The grades are scaled by how much each event contributes to scoring runs.</p>
<p>Below is the formula for wOBA in 2025 per <a href="https://www.fangraphs.com/tools/guts?type=cn">FanGraphs</a>:</p>
<div style="height:100px;overflow:auto;">
<table class="caption-top table">
<colgroup>
<col style="width: 7%">
<col style="width: 5%">
<col style="width: 10%">
<col style="width: 5%">
<col style="width: 5%">
<col style="width: 5%">
<col style="width: 6%">
<col style="width: 6%">
<col style="width: 6%">
<col style="width: 6%">
<col style="width: 7%">
<col style="width: 6%">
<col style="width: 6%">
<col style="width: 6%">
</colgroup>
<thead>
<tr class="header">
<th>Season</th>
<th>wOBA</th>
<th>wOBAScale</th>
<th>wBB</th>
<th>wHBP</th>
<th>w1B</th>
<th>w2B</th>
<th>w3B</th>
<th>wHR</th>
<th>runSB</th>
<th>runCS</th>
<th>R/PA</th>
<th>R/W</th>
<th>cFIP</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>2025</td>
<td>.314</td>
<td>1.239</td>
<td>.692</td>
<td>.723</td>
<td>.884</td>
<td>1.256</td>
<td>1.591</td>
<td>2.048</td>
<td>.200</td>
<td>-.406</td>
<td>.117</td>
<td>9.710</td>
<td>3.102</td>
</tr>
</tbody>
</table>
</div>
<p>Looking at doubles (w2B) we see that they are worth 1.256 runs, while home runs (wHR) are worth 2.048 runs. Walks (wBB) are worth .692 runs. This means that a player who hits a lot of doubles and home runs will have a higher wOBA than a player who hits a lot of singles, even if they have the same batting average.</p>
</section>
<section id="going-deeper-xwoba-the-for-the-nerds-section" class="level2">
<h2 class="anchored" data-anchor-id="going-deeper-xwoba-the-for-the-nerds-section">Going Deeper: xwOBA (The “For the Nerds” Section)</h2>
<p><a href="https://www.mlb.com/glossary/statcast/expected-woba">xwOBA</a> (expected weighted on-base average) is a metric that estimates what a player’s wOBA should be based on the quality of their contact, strikeouts, and walks. It uses Statcast data to analyze the exit velocity and launch angle of batted balls, as well as the player’s plate discipline. According to MLB, xwOBA is more “indicative” of a player’s true talent level than wOBA, which can be influenced by luck.</p>
<p>For example, <a href="https://baseballsavant.mlb.com/savant-player/andrew-vaughn-683734?stats=statcast-r-hitting-mlb">Andrew Vaughn</a> has a wOBA of .289 but an xwOBA of .325. This suggests that Vaughn has been unlucky and should be hitting better than he has been. I actually think the Brewers made a brilliant move trading for Vaughn, given his expected statistics and age (27).</p>
<p>Put it simply, if</p>
<ul>
<li>wOBA &gt; xwOBA, the player has been lucky. Bloop hits, seeing-eye singles, or defensive misplays are contributing to their success. They might be due for some regression.</li>
<li>wOBA &lt; xwOBA, the player has been unlucky. They are hitting the ball hard, but right at defenders. They are “barreling up” the ball without the results to show for it. They could be due for a hot streak.</li>
</ul>
<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>Checkout my <a href="https://runningonnumbers.com/posts/lucky-hitters/">previous post</a> on lucky (and unlucky) hitters!</p>
</div>
</div>
</section>
<section id="analyzing-our-three-players-with-xwoba" class="level2">
<h2 class="anchored" data-anchor-id="analyzing-our-three-players-with-xwoba">Analyzing Our Three Players with xwOBA</h2>
<p>Here are the current xwOBA values for our three players:</p>
<ul>
<li>Machado: .394 (94th percentile)</li>
<li>Soto: .438 (100th percentile)</li>
<li>Suarez: .346 (66th percentile)</li>
</ul>
<p>Machado and Soto are both outperforming their wOBA, suggesting that they are hitting the ball with authority and their numbers should be better than they are. Suarez is underperforming his wOBA, suggesting that the quality of contact might not sustain this exact level of production.</p>
<div id="53ad123a" class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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 class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.graph_objects <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> go</span>
<span id="cb2-2"><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="cb2-3"></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Data Setup ---</span></span>
<span id="cb2-5">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb2-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Player'</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Manny Machado'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Juan Soto'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Eugenio Suárez'</span>],</span>
<span id="cb2-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'wOBA'</span>: [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.370</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.369</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.370</span>],</span>
<span id="cb2-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xwOBA'</span>: [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.394</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.438</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.346</span>]</span>
<span id="cb2-9">}</span>
<span id="cb2-10">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(data)</span>
<span id="cb2-11"></span>
<span id="cb2-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Player Headshot URLs ---</span></span>
<span id="cb2-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Using official MLB headshot images for better quality</span></span>
<span id="cb2-14">image_urls <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb2-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://img.mlbstatic.com/mlb-photos/image/upload/d_people:generic:headshot:67:current.png/w_426,q_auto:best/v1/people/592518/headshot/67/current"</span>, <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Machado</span></span>
<span id="cb2-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://img.mlbstatic.com/mlb-photos/image/upload/d_people:generic:headshot:67:current.png/w_426,q_auto:best/v1/people/665742/headshot/67/current"</span>, <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Soto</span></span>
<span id="cb2-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://img.mlbstatic.com/mlb-photos/image/upload/d_people:generic:headshot:67:current.png/w_426,q_auto:best/v1/people/553993/headshot/67/current"</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Suárez</span></span>
<span id="cb2-18">]</span>
<span id="cb2-19"></span>
<span id="cb2-20"></span>
<span id="cb2-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Chart Creation ---</span></span>
<span id="cb2-22">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Figure()</span>
<span id="cb2-23"></span>
<span id="cb2-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add bar traces</span></span>
<span id="cb2-25">fig.add_trace(go.Bar(</span>
<span id="cb2-26">    x<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;">'Player'</span>], y<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;">'wOBA'</span>], 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;">'wOBA (Actual)'</span>,</span>
<span id="cb2-27">    marker_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;">'rgba(54, 162, 235, 0.7)'</span>,</span>
<span id="cb2-28">    hovertemplate<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;">{y:.3f}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">&lt;extra&gt;&lt;/extra&gt;'</span></span>
<span id="cb2-29">))</span>
<span id="cb2-30">fig.add_trace(go.Bar(</span>
<span id="cb2-31">    x<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;">'Player'</span>], y<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;">'xwOBA'</span>], 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;">'xwOBA (Expected)'</span>,</span>
<span id="cb2-32">    marker_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;">'rgba(255, 159, 64, 0.7)'</span>,</span>
<span id="cb2-33">    hovertemplate<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;">{y:.3f}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">&lt;extra&gt;&lt;/extra&gt;'</span></span>
<span id="cb2-34">))</span>
<span id="cb2-35"></span>
<span id="cb2-36"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Add Headshot Images ---</span></span>
<span id="cb2-37"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, player <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Player'</span>]):</span>
<span id="cb2-38">    fig.add_layout_image(</span>
<span id="cb2-39">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb2-40">            source<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>image_urls[i],</span>
<span id="cb2-41">            xref<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;">"x"</span>,</span>
<span id="cb2-42">            yref<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;">"paper"</span>,</span>
<span id="cb2-43">            x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>player,  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use player name to anchor on x-axis</span></span>
<span id="cb2-44">            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.28</span>,    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Position below the x-axis</span></span>
<span id="cb2-45">            sizex<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.27</span>, <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Size of the image</span></span>
<span id="cb2-46">            sizey<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.27</span>,</span>
<span id="cb2-47">            xanchor<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="cb2-48">            yanchor<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;">"bottom"</span></span>
<span id="cb2-49">        )</span>
<span id="cb2-50">    )</span>
<span id="cb2-51"></span>
<span id="cb2-52"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Update Layout ---</span></span>
<span id="cb2-53">fig.update_layout(</span>
<span id="cb2-54">    barmode<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;">'group'</span>,</span>
<span id="cb2-55">    title<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{</span>
<span id="cb2-56">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'text'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'&lt;b&gt;wOBA vs. xwOBA Comparison&lt;/b&gt;'</span>,</span>
<span id="cb2-57">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>:<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.99</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x'</span>:<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'xanchor'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'center'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'yanchor'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'top'</span></span>
<span id="cb2-58">    },</span>
<span id="cb2-59">    xaxis_title<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="cb2-60">    yaxis_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;">'Value'</span>,</span>
<span id="cb2-61">    yaxis_range<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.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.45</span>],</span>
<span id="cb2-62">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># legend=dict(</span></span>
<span id="cb2-63">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     orientation="h", yanchor="bottom", y=1.02, xanchor="center", x=0.5</span></span>
<span id="cb2-64">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ),</span></span>
<span id="cb2-65">    template<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;">'plotly_white'</span>,</span>
<span id="cb2-66">    font<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</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;">"Inter, sans-serif"</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;">12</span>),</span>
<span id="cb2-67">    margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(b<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;">120</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Increase bottom margin to make space for images</span></span>
<span id="cb2-68">)</span>
<span id="cb2-69"></span>
<span id="cb2-70">fig.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="6cc86a54-7396-44ad-b036-b10ac96ebab6" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("6cc86a54-7396-44ad-b036-b10ac96ebab6")) {                    Plotly.newPlot(                        "6cc86a54-7396-44ad-b036-b10ac96ebab6",                        [{"hovertemplate":"%{y:.3f}\u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(54, 162, 235, 0.7)"},"name":"wOBA (Actual)","x":["Manny Machado","Juan Soto","Eugenio Suárez"],"y":{"dtype":"f8","bdata":"rkfhehSu1z8EVg4tsp3XP65H4XoUrtc\u002f"},"type":"bar"},{"hovertemplate":"%{y:.3f}\u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(255, 159, 64, 0.7)"},"name":"xwOBA (Expected)","x":["Manny Machado","Juan Soto","Eugenio Suárez"],"y":{"dtype":"f8","bdata":"nu+nxks32T\u002fVeOkmMQjcP76fGi\u002fdJNY\u002f"},"type":"bar"}],                        {"template":{"data":{"barpolar":[{"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"type":"carpet"}],"choropleth":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"choropleth"}],"contourcarpet":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"contourcarpet"}],"contour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"contour"}],"heatmap":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"heatmap"}],"histogram2dcontour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2dcontour"}],"histogram2d":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2d"}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"mesh3d":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"mesh3d"}],"parcoords":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"parcoords"}],"pie":[{"automargin":true,"type":"pie"}],"scatter3d":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatter3d"}],"scattercarpet":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattercarpet"}],"scattergeo":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergeo"}],"scattergl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergl"}],"scattermapbox":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermapbox"}],"scattermap":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermap"}],"scatterpolargl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolargl"}],"scatterpolar":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolar"}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"scatterternary":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterternary"}],"surface":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"surface"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}]},"layout":{"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"autotypenumbers":"strict","coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]],"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]},"colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"geo":{"bgcolor":"white","lakecolor":"white","landcolor":"white","showlakes":true,"showland":true,"subunitcolor":"#C8D4E3"},"hoverlabel":{"align":"left"},"hovermode":"closest","mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30},"paper_bgcolor":"white","plot_bgcolor":"white","polar":{"angularaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""},"bgcolor":"white","radialaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""}},"scene":{"xaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"yaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"zaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"ternary":{"aaxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"baxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"bgcolor":"white","caxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""}},"title":{"x":0.05},"xaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2},"yaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2}}},"images":[{"sizex":0.27,"sizey":0.27,"source":"https:\u002f\u002fimg.mlbstatic.com\u002fmlb-photos\u002fimage\u002fupload\u002fd_people:generic:headshot:67:current.png\u002fw_426,q_auto:best\u002fv1\u002fpeople\u002f592518\u002fheadshot\u002f67\u002fcurrent","x":"Manny Machado","xanchor":"center","xref":"x","y":-0.28,"yanchor":"bottom","yref":"paper"},{"sizex":0.27,"sizey":0.27,"source":"https:\u002f\u002fimg.mlbstatic.com\u002fmlb-photos\u002fimage\u002fupload\u002fd_people:generic:headshot:67:current.png\u002fw_426,q_auto:best\u002fv1\u002fpeople\u002f665742\u002fheadshot\u002f67\u002fcurrent","x":"Juan Soto","xanchor":"center","xref":"x","y":-0.28,"yanchor":"bottom","yref":"paper"},{"sizex":0.27,"sizey":0.27,"source":"https:\u002f\u002fimg.mlbstatic.com\u002fmlb-photos\u002fimage\u002fupload\u002fd_people:generic:headshot:67:current.png\u002fw_426,q_auto:best\u002fv1\u002fpeople\u002f553993\u002fheadshot\u002f67\u002fcurrent","x":"Eugenio Suárez","xanchor":"center","xref":"x","y":-0.28,"yanchor":"bottom","yref":"paper"}],"title":{"text":"\u003cb\u003ewOBA vs. xwOBA Comparison\u003c\u002fb\u003e","y":0.99,"x":0.5,"xanchor":"center","yanchor":"top"},"yaxis":{"title":{"text":"Value"},"range":[0.0,0.45]},"font":{"family":"Inter, sans-serif","size":12},"margin":{"b":120},"barmode":"group","xaxis":{"title":{}}},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('6cc86a54-7396-44ad-b036-b10ac96ebab6');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
</div>
</section>
<section id="conclusion-who-do-you-want-at-the-plate" class="level2">
<h2 class="anchored" data-anchor-id="conclusion-who-do-you-want-at-the-plate">Conclusion: Who do you want at the plate?</h2>
<p>From Passan’s tweet, we saw three different types of hitters. While they excely in different metrics, they all share the same wOBA. We then investigated xwOBA, which gives us a deeper understanding of their performance. Based on xwOBA, Soto is the best hitter of the three, followed by Machado, and then Suarez.</p>
<p>So in the end, the number was a mirage. A tidy .370 wOBA that made three very different men look like statistical clones. But baseball, like any market, is filled with inefficiencies for those who know where to look. And looking at xwOBA was like looking at the audited financials instead of the press release. It revealed that one of these hitters was getting lucky, another was earning his keep, and the third, Juan Soto, was the undervalued asset — despite already being a superstar. The scoreboard showed a tie, but the underlying physics of their batted balls told you who was really winning the game.</p>
<p>Peace ✌️</p>
<iframe src="https://streamable.com/m/juan-soto-homers-16-on-a-fly-ball-to-right-center-field-zkp5lh?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->

</section>

 ]]></description>
  <category>Padres</category>
  <category>Mariners</category>
  <category>Mets</category>
  <guid>https://runningonnumbers.com/posts/machado-soto-suarez-woba-xwoba/</guid>
  <pubDate>Sun, 03 Aug 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/machado-soto-suarez-woba-xwoba/composite.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Support Vector Machine</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/support-vector-machine/</link>
  <description><![CDATA[ 





<iframe src="https://streamable.com/m/cal-raleigh-strikes-out-swinging-db4nhp?partnerId=web_video-playback-page_video-share" width="720" height="415">
</iframe>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>In a previous <a href="https://runningonnumbers.com/posts/logistic-regression/">article</a>, we introduced logistic regression and applied it to a binary classification problem. In our implementation, we used a 50/50 split to determine the threshold for classification. This is a linear line, separating the two classes. However, this approach may lead to overfitting, especially if the data is not linearly separable. What if there were a way to find a hyperplane that maximizes the margin between the two classes? In this article, we turn to support vector machines (SVM).</p>
</section>
<section id="hard-margin-svm" class="level2">
<h2 class="anchored" data-anchor-id="hard-margin-svm">Hard Margin SVM</h2>
<p>Support vector machines are a set of supervised learning methods used for classification, regression, and outliers detection. The main idea behind SVM is to find a hyperplane that best separates the data into different classes. In the case of binary classification, this hyperplane is a line (in 2D) or a plane (in 3D) that divides the feature space into two halves, with each half representing a different class.</p>
<p>The optimal hyperplane is the one that maximizes the margin between the two classes. The margin is defined as the distance between the hyperplane and the nearest data point from either class. SVM aims to find the hyperplane that has the largest margin, as this is believed to lead to better generalization on unseen data.</p>
<p>Mathematically, we can represent the hyperplane or decision boundary as <img src="https://latex.codecogs.com/png.latex?%5Ctheta%5ET%20x%20+%20b%20=%200"> where <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> is the weight vector, <img src="https://latex.codecogs.com/png.latex?x"> is the input feature vector, and <img src="https://latex.codecogs.com/png.latex?b"> is the bias term. The goal of SVM is to find the optimal values for <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> and <img src="https://latex.codecogs.com/png.latex?b"> that maximize the margin. The optimization problem can be formulated as follows:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7Bmax%7D_%5Ctheta%20%5Cgamma%20%5Cquad%20%5Ctext%7Bsubject%20to%7D%20%5Cquad%20y_i(%5Ctheta%5ET%20x_i%20+%20b)%20%5Cgeq%201,%20%5Cquad%20%5Cforall%20i.%0A"> Here, <img src="https://latex.codecogs.com/png.latex?%5Cgamma"> represents the geometric margin, <img src="https://latex.codecogs.com/png.latex?y_i"> is the class label for the <img src="https://latex.codecogs.com/png.latex?i">-th data point, and <img src="https://latex.codecogs.com/png.latex?x_i"> is the feature vector for the <img src="https://latex.codecogs.com/png.latex?i">-th data point. The constraint ensures that all data points are correctly classified with a margin of at least 1. <img src="https://latex.codecogs.com/png.latex?y_i(%5Ctheta%5ET%20x_i%20+%20b)"> is the functional margin. This means every data point is correctly classified and lies on or outside the margin boundary. We set the margin to 1 for simplicity, but it can be scaled to any value. Observe the illustration below, which shows the hyperplane and the margin for a hard margin SVM.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/support-vector-machine/svm-figure.png" class="img-fluid figure-img"></p>
<figcaption>Hard margin SVM</figcaption>
</figure>
</div>
<p>The perpendicular distance from the hyperplane to a data point is <img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bdistance%7D%20=%20%7C%5Ctheta%5ET%20x%5Ei%20+%20b%7C%20/%20%7C%7C%5Ctheta%7C%7C">. Since we want all the points to be correctly classified, we can multiply the distance by the class label <img src="https://latex.codecogs.com/png.latex?y%5Ei">. Thus, <img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bdistance%7D%20=%20y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b)%20/%20%7C%7C%5Ctheta%7C%7C">. Recall that the functional margin is defined as <img src="https://latex.codecogs.com/png.latex?y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b)">. Therefore, we can rewrite the distance as <img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bdistance%7D%20=%20%5Cfrac%7By%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b)%7D%7B%7C%7C%5Ctheta%7C%7C%7D">. Note that we can scale <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> and <img src="https://latex.codecogs.com/png.latex?b"> by any positive constant; for simplicity, we set the functional margin to 1. This means that the distance from the hyperplane to the nearest data point is <img src="https://latex.codecogs.com/png.latex?1%20/%20%7C%7C%5Ctheta%7C%7C">.</p>
<p>If our goal is to maximize the margin, we can minimize the norm of <img src="https://latex.codecogs.com/png.latex?%5Ctheta">. Our optimization problem becomes <img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bmin%7D_%5Ctheta%20%5C;%20%5Cfrac%7B1%7D%7B2%7D%5Ctheta%5ET%5Ctheta%20%5C;%20s.t.%20%5C;%20y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b)%20%5Cleq%201%20%5Cforall%20i"></p>
</section>
<section id="soft-margin-svm" class="level2">
<h2 class="anchored" data-anchor-id="soft-margin-svm">Soft Margin SVM</h2>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/support-vector-machine/amongus.png" class="img-fluid figure-img"></p>
<figcaption>Among Us</figcaption>
</figure>
</div>
<p>What happens if data is not linearly separable? Take for example, the datapoints below.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/support-vector-machine/svm-figure-non-linear.png" class="img-fluid figure-img"></p>
<figcaption>Non-linearly separable data</figcaption>
</figure>
</div>
<p>Imposter acorn! No way we can draw a line to separate the two classes. We are going to need to add some flexibilty. Continuing with the formalism from above, let’s define two conditions: (1) if the margin &gt;= 1, don’t care, and (2) if the margin &lt; 1 pay a linear penalty. This leads us to the soft margin SVM, which allows for some misclassification of data points. More formally,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bmin%7D_%7B%5Ctheta,%20%5Cxi,%20b%7D%20%5Cfrac%7B1%7D%7B2%7D%5Ctheta%5ET%5Ctheta%20+%20C%5Csum_%7Bi=1%7D%5EN%20%5Cxi_i%20%5C;%20%5Ctext%7B%20s.t.%20%7D%20y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b)%20+%20%5Cxi_i%20%5Cgeq%201,%20%5Cxi%20%5Cgeq%200,%20%5Cforall%20i."></p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cxi_i"> is the “slack” variable that allows for some misclassification of data points. For <img src="https://latex.codecogs.com/png.latex?0%3C%5Cxi_i%20%5Cleq%201">, the point is between the margin and the correct side of the hyperplane. For <img src="https://latex.codecogs.com/png.latex?%5Cxi_i%20%3E%201">, the point is missclassified. <img src="https://latex.codecogs.com/png.latex?C"> is a regularization parameter. A small <img src="https://latex.codecogs.com/png.latex?C"> allows constraints to be easily ignored <img src="https://latex.codecogs.com/png.latex?%5Crightarrow"> large margin. A large <img src="https://latex.codecogs.com/png.latex?C"> forces the constraints to be satisfied <img src="https://latex.codecogs.com/png.latex?%5Crightarrow"> small margin. <img src="https://latex.codecogs.com/png.latex?C=%5Cinfty"> implies hard margin SVM.</p>
<p>So how do we solve this optimization problem? If we were to solve the above equation, we would need to use a quadratic programming solver. But this method is computationally expensive, especially as data size increases. Instead, we can re-write soft margin SVM as an uncostrained optimization problem and use gradient descent to solve it.</p>
<p>Recall that <img src="https://latex.codecogs.com/png.latex?%5Cxi"> has two contraints: <img src="https://latex.codecogs.com/png.latex?y%5Ei(%5Ctheta%5ET%20x%5Ei)%20+%20%5Cxi_i%20%5Cgeq%201"> and <img src="https://latex.codecogs.com/png.latex?%5Cxi_i%20%5Cgeq%200."> We can re-write the first constraint as <img src="https://latex.codecogs.com/png.latex?y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b)%20%5Cgeq%201%20-%20%5Cxi_i">. If the goal is the minimze the functional margin, then the optimal value for <img src="https://latex.codecogs.com/png.latex?%5Cxi_i"> is <img src="https://latex.codecogs.com/png.latex?%5Cxi_i%20=%20%5Ctext%7Bmax%7D(0,%201-y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b))."> Hence. <img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7Bmin%7D_%7B%5Ctheta,%20b%7D%20%5Cfrac%7B1%7D%7B2%7D%5Ctheta%5ET%5Ctheta%20+%20C%5Csum_%7Bi=1%7D%5EN%20%5Ctext%7Bmax%7D(0,%201-y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b)).%0A"> Based on where a data point lies if it is …</p>
<ol type="1">
<li>Outside the margin, then <img src="https://latex.codecogs.com/png.latex?%5Cxi_i%20=%200">. No contribution to the loss.</li>
<li>On the margin, then <img src="https://latex.codecogs.com/png.latex?%5Cxi_i%20=%200">. No contribution to the loss.</li>
<li>Inside the margin, then <img src="https://latex.codecogs.com/png.latex?%5Cxi_i%20=%201%20-%20y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b)">. Point violates the margin, so it contributes to the loss.</li>
</ol>
<p>This is known as the hinge loss - sometimes regarded as a rigid version of the logistic loss. We can now use gradient descent to minimize the loss function.</p>
<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>Try to think about the relationship between the hinge loss and the logistic loss. What are the similarities and differences? Read more about Logistic Regression <a href="https://runningonnumbers.com/posts/logistic-regression/">here</a>.</p>
</div>
</div>
</section>
<section id="svm-implementation" class="level2">
<h2 class="anchored" data-anchor-id="svm-implementation">SVM Implementation</h2>
<section id="gradient-descent-for-svm" class="level3">
<h3 class="anchored" data-anchor-id="gradient-descent-for-svm">Gradient Descent for SVM</h3>
<p>Suppose <img src="https://latex.codecogs.com/png.latex?COST(%5Ctheta,%20b)"> is the cost function for soft margin SVM.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Balign*%7D%0A%20%20%20%20COST(%5Ctheta,%20b)%20&amp;=%20%5Cfrac%7B1%7D%7B2%7D%5Ctheta%5ET%5Ctheta%20+%20C%5Csum_%7Bi=1%7D%5EN%20%5Ctext%7Bmax%7D(0,%201-y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b))%20%5C%5C%0A%20%20%20%20&amp;=%20%5Csum_%7Bi=1%7D%5EN%20(%5Cfrac%7B1%7D%7B2N%7D%5Ctheta%5ET%5Ctheta%20+%20C%20%5Ctext%7Bmax%7D(0,%201-y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b))).%0A%5Cend%7Balign*%7D%0A"></p>
<p>For each data point <img src="https://latex.codecogs.com/png.latex?x%5Ei"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B%5Cpartial%20COST(%5Ctheta,%20b)%7D%7B%5Cpartial%20%5Ctheta_j%7D%20=%20%5Cbegin%7Bcases%7D%0A%5Cfrac%7B1%7D%7BN%7D%5Ctheta_j%20-%20C%20y%5Ei%20x_j%5Ei%20,%20&amp;%20%5Ctext%7Bif%20%7D%201-y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b)%20%3E%200%20%5C%5C%0A%5Cfrac%7B1%7D%7BN%7D%5Ctheta_j,%20&amp;%20%5Ctext%7Botherwise%7D%0A%5Cend%7Bcases%7D%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B%5Cpartial%20COST(%5Ctheta,%20b)%7D%7B%5Cpartial%20b%7D%20=%20%5Cbegin%7Bcases%7D%0A-C%20y%5Ei%20&amp;%20%5Ctext%7Bif%20%7D%201-y%5Ei(%5Ctheta%5ET%20x%5Ei%20+%20b)%20%3E%200%20%5C%5C%0A0,%20&amp;%20%5Ctext%7Botherwise.%7D%0A%5Cend%7Bcases%7D%0A"></p>
<p>Enough math. Let’s code.</p>
</section>
<section id="svm-with-numpy" class="level3">
<h3 class="anchored" data-anchor-id="svm-with-numpy">SVM with NumPy</h3>
<p>Using the uncontrained optimization formulation, we can implement SVM with just NumPy.</p>
<div id="79802115" class="cell" data-execution_count="1">
<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="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-2"></span>
<span id="cb1-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> SVM:</span>
<span id="cb1-4">    <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>, learning_rate<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.001</span>, n_iters<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;">1000</span>):</span>
<span id="cb1-5">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> learning_rate</span>
<span id="cb1-6">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.n_iters <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> n_iters</span>
<span id="cb1-7">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.w <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="cb1-8">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.b <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="cb1-9"></span>
<span id="cb1-10">    <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, C<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-11">        n_samples, n_features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.shape</span>
<span id="cb1-12">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros(n_features)</span>
<span id="cb1-13">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.b <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-14"></span>
<span id="cb1-15">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> epoch <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.n_iters):</span>
<span id="cb1-16">            condition <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (np.dot(X, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.w) <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>.b)</span>
<span id="cb1-17">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Initialize gradients</span></span>
<span id="cb1-18">            grad_w <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>.w.copy()</span>
<span id="cb1-19">            grad_b <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-20"></span>
<span id="cb1-21">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate gradient from loss</span></span>
<span id="cb1-22">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> indx, x_i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(X):</span>
<span id="cb1-23">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> condition[indx] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>:</span>
<span id="cb1-24">                    grad_w <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-=</span> C <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> y[indx] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x_i</span>
<span id="cb1-25">                    grad_b <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-=</span> C <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> y[indx]</span>
<span id="cb1-26">            </span>
<span id="cb1-27">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Update weights and bias</span></span>
<span id="cb1-28">            <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.w <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>.lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> grad_w</span>
<span id="cb1-29">            <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.b <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>.lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> grad_b</span>
<span id="cb1-30"></span>
<span id="cb1-31">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> predict(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, X):</span>
<span id="cb1-32">        linear_output <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.dot(X, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.w) <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>.b</span>
<span id="cb1-33">        predictions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sign(linear_output)</span>
<span id="cb1-34">        predictions[predictions <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="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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb1-35">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> predictions</span></code></pre></div>
</div>
<p>Let’s validate our implementation with a simple dataset.</p>
<div id="cell-fig-simple-svm" class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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 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="cb2-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> datasets</span>
<span id="cb2-3"></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use only two classes and two features for simplicity</span></span>
<span id="cb2-5">iris <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> datasets.load_iris()</span>
<span id="cb2-6">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> iris.data[iris.target <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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]</span>
<span id="cb2-7">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> iris.target[iris.target <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="cb2-8">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(y <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="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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-9"></span>
<span id="cb2-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use more iterations to allow the model to converge</span></span>
<span id="cb2-11">svm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SVM(learning_rate<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.001</span>, n_iters<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;">1000</span>)</span>
<span id="cb2-12">svm.fit(X, y)</span>
<span id="cb2-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Weights: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>svm<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>w<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;">, Bias: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>svm<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>b<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="cb2-14"></span>
<span id="cb2-15">predictions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> svm.predict(X)</span>
<span id="cb2-16">accuracy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean(predictions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> y)</span>
<span id="cb2-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Accuracy: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>accuracy <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 class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span>
<span id="cb2-18"></span>
<span id="cb2-19"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> plot_decision_boundary(X, y, model):</span>
<span id="cb2-20">    x_min, x_max <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</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>, X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</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="cb2-21">    y_min, y_max <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</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>, X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</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="cb2-22">    xx, yy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.meshgrid(np.linspace(x_min, x_max, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>), np.linspace(y_min, y_max, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>))</span>
<span id="cb2-23">    Z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.predict(np.c_[xx.ravel(), yy.ravel()])</span>
<span id="cb2-24">    Z <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Z.reshape(xx.shape)</span>
<span id="cb2-25">    plt.contourf(xx, yy, Z, 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.3</span>, cmap<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;">'coolwarm'</span>)</span>
<span id="cb2-26">    plt.scatter(X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y, cmap<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;">'coolwarm'</span>)</span>
<span id="cb2-27">    plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SVM Decision Boundary"</span>)</span>
<span id="cb2-28">    plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Feature 1"</span>)</span>
<span id="cb2-29">    plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Feature 2"</span>)</span>
<span id="cb2-30">    plt.show()  </span>
<span id="cb2-31"></span>
<span id="cb2-32">plot_decision_boundary(X, y, svm)</span></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>Weights: [ 1.78678929 -2.79549737], Bias: -1.0460000000000018
Accuracy: 99.00%</code></pre>
</div>
<div class="cell-output cell-output-display">
<div id="fig-simple-svm" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-simple-svm-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/support-vector-machine/index_files/figure-html/fig-simple-svm-output-2.png" width="593" height="449" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-simple-svm-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Simple SVM implementation using NumPy
</figcaption>
</figure>
</div>
</div>
</div>
<p>Looking good! We have successfully implemented a simple SVM classifier using NumPy. Next, let’s see how we can use the <code>sklearn</code> library to use SVM on a real-world dataset.</p>
</section>
</section>
<section id="baseball-application" class="level2">
<h2 class="anchored" data-anchor-id="baseball-application">Baseball Application</h2>
<p>In this section, we will apply SVM to a baseball dataset. We will use the <code>svm</code> module from the <code>sklearn</code> library to implement SVM. The dataset we will use is a subset of the <a href="https://www.mlb.com/glossary/statcast">Statcast data</a> that contains information about batted balls.</p>
<p>Padres Pitcher, <a href="https://www.baseball-reference.com/players/c/ceasedy01.shtml">Dylan Cease</a>, has one of the highest wiff rates in MLB. According to <a href="https://baseballsavant.mlb.com/leaderboard/custom?year=2025&amp;type=pitcher&amp;filter=&amp;min=q&amp;selections=pa%2Ck_percent%2Cbb_percent%2Cwoba%2Cxwoba%2Csweet_spot_percent%2Cbarrel_batted_rate%2Chard_hit_percent%2Cavg_best_speed%2Cavg_hyper_speed%2Cwhiff_percent%2Cswing_percent&amp;chart=false&amp;x=pa&amp;y=pa&amp;r=no&amp;chartType=beeswarm&amp;sort=whiff_percent&amp;sortDir=desc">Baseball Savant</a>, Cease stands alone at the top with a 33.9% whiff rate; <a href="https://www.baseball-reference.com/players/s/skubata01.shtml">Tarik Skubal</a> sits close behind at 33.6%. For this case study, we are going to investigate what factors contribute to Cease’s swing-and-miss stuff. Similar to <a href="https://runningonnumbers.com/posts/fast-swings-and-barrels/">Decision Trees</a>, SVMs are non-parametric models that can capture non-linear relationships. This is ideal when there are numerous features that may interact in complex ways. For every pitch, there lies granular information about the pitch type, velocity, spin rate, and location. We will use SVM to classify whether a pitch results in a whiff or not.</p>
<p>We will use the <code>cease-whiff.csv</code> dataset, which contains information about every pitch thrown by Dylan Cease in the 2025 and 2024 season. The data was quieried from Baseball Savant. So we’ll need to tidy the data first. A couple things for data prep: categorize the <code>description</code> column into whiff or not whiff. We will also drop fouls.</p>
<div id="7b03699e" class="cell" data-execution_count="3">
<details class="code-fold">
<summary>Code</summary>
<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 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="cb4-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb4-3"><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> StandardScaler</span>
<span id="cb4-4"></span>
<span id="cb4-5">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cw2.csv"</span>)</span>
<span id="cb4-6"></span>
<span id="cb4-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># categorize description into whiff or not whiff</span></span>
<span id="cb4-8"></span>
<span id="cb4-9">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'whiff'</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;">'description'</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">apply</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> x: <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> 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;">'swinging_strike'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb4-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># let's also drop fouls</span></span>
<span id="cb4-11"></span>
<span id="cb4-12">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'description'</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;">'foul'</span>]</span>
<span id="cb4-13"></span>
<span id="cb4-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># select relevant features</span></span>
<span id="cb4-15">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;">'pitch_type'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_speed'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_pos_x'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_pos_z'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pfx_x'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pfx_z'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'plate_x'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'plate_z'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'vx0'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'vy0'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'vz0'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ax'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ay'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'az'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'effective_speed'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_spin_rate'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_extension'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_pos_y'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'n_thruorder_pitcher'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'arm_angle'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'spin_axis'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'bat_speed'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'whiff'</span>]</span>
<span id="cb4-16">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[features]</span>
<span id="cb4-17"></span>
<span id="cb4-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># drop rows with missing values</span></span>
<span id="cb4-19">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.dropna()</span>
<span id="cb4-20"></span>
<span id="cb4-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># encode categorical variables</span></span>
<span id="cb4-22">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.get_dummies(df, 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;">'pitch_type'</span>], drop_first<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>, dtype<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)</span>
<span id="cb4-23"></span>
<span id="cb4-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># scale numerical features</span></span>
<span id="cb4-25">scaler <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler()</span>
<span id="cb4-26">num_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;">'release_speed'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_pos_x'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_pos_z'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pfx_x'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pfx_z'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'plate_x'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'plate_z'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'vx0'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'vy0'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'vz0'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ax'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ay'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'az'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'effective_speed'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_spin_rate'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_extension'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_pos_y'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'n_thruorder_pitcher'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'arm_angle'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'bat_speed'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'spin_axis'</span>]</span>
<span id="cb4-27">df[num_features] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> scaler.fit_transform(df[num_features])</span>
<span id="cb4-28">df.describe()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="3">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">release_speed</th>
<th data-quarto-table-cell-role="th">release_pos_x</th>
<th data-quarto-table-cell-role="th">release_pos_z</th>
<th data-quarto-table-cell-role="th">pfx_x</th>
<th data-quarto-table-cell-role="th">pfx_z</th>
<th data-quarto-table-cell-role="th">plate_x</th>
<th data-quarto-table-cell-role="th">plate_z</th>
<th data-quarto-table-cell-role="th">vx0</th>
<th data-quarto-table-cell-role="th">vy0</th>
<th data-quarto-table-cell-role="th">vz0</th>
<th data-quarto-table-cell-role="th">...</th>
<th data-quarto-table-cell-role="th">arm_angle</th>
<th data-quarto-table-cell-role="th">spin_axis</th>
<th data-quarto-table-cell-role="th">bat_speed</th>
<th data-quarto-table-cell-role="th">whiff</th>
<th data-quarto-table-cell-role="th">pitch_type_FC</th>
<th data-quarto-table-cell-role="th">pitch_type_FF</th>
<th data-quarto-table-cell-role="th">pitch_type_KC</th>
<th data-quarto-table-cell-role="th">pitch_type_SI</th>
<th data-quarto-table-cell-role="th">pitch_type_SL</th>
<th data-quarto-table-cell-role="th">pitch_type_ST</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">count</td>
<td>1.882000e+03</td>
<td>1.882000e+03</td>
<td>1.882000e+03</td>
<td>1882.000000</td>
<td>1.882000e+03</td>
<td>1.882000e+03</td>
<td>1.882000e+03</td>
<td>1.882000e+03</td>
<td>1.882000e+03</td>
<td>1.882000e+03</td>
<td>...</td>
<td>1.882000e+03</td>
<td>1.882000e+03</td>
<td>1.882000e+03</td>
<td>1882.000000</td>
<td>1882.000000</td>
<td>1882.000000</td>
<td>1882.000000</td>
<td>1882.000000</td>
<td>1882.000000</td>
<td>1882.000000</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">mean</td>
<td>9.665193e-16</td>
<td>7.701951e-16</td>
<td>-6.614617e-15</td>
<td>0.000000</td>
<td>1.208149e-16</td>
<td>-7.550932e-17</td>
<td>1.510186e-16</td>
<td>3.020373e-17</td>
<td>2.476706e-15</td>
<td>3.020373e-16</td>
<td>...</td>
<td>6.644820e-16</td>
<td>1.812224e-16</td>
<td>1.585696e-16</td>
<td>0.460680</td>
<td>0.002125</td>
<td>0.371945</td>
<td>0.069075</td>
<td>0.009564</td>
<td>0.520191</td>
<td>0.015409</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">std</td>
<td>1.000266e+00</td>
<td>1.000266e+00</td>
<td>1.000266e+00</td>
<td>1.000266</td>
<td>1.000266e+00</td>
<td>1.000266e+00</td>
<td>1.000266e+00</td>
<td>1.000266e+00</td>
<td>1.000266e+00</td>
<td>1.000266e+00</td>
<td>...</td>
<td>1.000266e+00</td>
<td>1.000266e+00</td>
<td>1.000266e+00</td>
<td>0.498584</td>
<td>0.046065</td>
<td>0.483452</td>
<td>0.253650</td>
<td>0.097354</td>
<td>0.499725</td>
<td>0.123206</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">min</td>
<td>-4.076923e+00</td>
<td>-3.079733e+00</td>
<td>-3.168647e+00</td>
<td>-4.206431</td>
<td>-2.656910e+00</td>
<td>-2.941060e+00</td>
<td>-3.063429e+00</td>
<td>-3.098316e+00</td>
<td>-1.712382e+00</td>
<td>-2.682536e+00</td>
<td>...</td>
<td>-3.368881e+00</td>
<td>-2.140499e+00</td>
<td>-6.195404e+00</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">25%</td>
<td>-6.463924e-01</td>
<td>-6.625058e-01</td>
<td>-6.961108e-01</td>
<td>-0.669836</td>
<td>-5.489989e-01</td>
<td>-7.215194e-01</td>
<td>-7.091011e-01</td>
<td>-7.146339e-01</td>
<td>-1.024796e+00</td>
<td>-6.895903e-01</td>
<td>...</td>
<td>-6.211546e-01</td>
<td>-7.677670e-01</td>
<td>-2.094316e-01</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">50%</td>
<td>-2.775181e-01</td>
<td>-2.042987e-02</td>
<td>3.110570e-02</td>
<td>0.083327</td>
<td>-3.030760e-01</td>
<td>-3.995563e-03</td>
<td>-3.940257e-03</td>
<td>9.675244e-04</td>
<td>2.686163e-01</td>
<td>-5.441526e-02</td>
<td>...</td>
<td>7.782843e-02</td>
<td>3.871293e-02</td>
<td>1.837357e-01</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>1.000000</td>
<td>0.000000</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">75%</td>
<td>1.031986e+00</td>
<td>6.594152e-01</td>
<td>6.856005e-01</td>
<td>0.640013</td>
<td>1.043645e+00</td>
<td>6.943943e-01</td>
<td>7.125942e-01</td>
<td>6.979036e-01</td>
<td>6.396214e-01</td>
<td>5.788533e-01</td>
<td>...</td>
<td>6.743743e-01</td>
<td>9.824660e-01</td>
<td>5.670739e-01</td>
<td>1.000000</td>
<td>0.000000</td>
<td>1.000000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>1.000000</td>
<td>0.000000</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">max</td>
<td>1.714403e+00</td>
<td>3.152181e+00</td>
<td>2.649085e+00</td>
<td>4.307593</td>
<td>1.605754e+00</td>
<td>3.832365e+00</td>
<td>2.839450e+00</td>
<td>3.031471e+00</td>
<td>4.078634e+00</td>
<td>3.573972e+00</td>
<td>...</td>
<td>4.416344e+00</td>
<td>3.830884e+00</td>
<td>1.746576e+00</td>
<td>1.000000</td>
<td>1.000000</td>
<td>1.000000</td>
<td>1.000000</td>
<td>1.000000</td>
<td>1.000000</td>
<td>1.000000</td>
</tr>
</tbody>
</table>

<p>8 rows × 28 columns</p>
</div>
</div>
</div>
<p>There you have it. Twenty-six features to work with for binary classification. Let’s split the data into training and testing sets.</p>
<div id="55ec70d4" class="cell" data-execution_count="4">
<details class="code-fold">
<summary>Code</summary>
<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 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> train_test_split</span>
<span id="cb5-2"></span>
<span id="cb5-3">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.drop(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'whiff'</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="cb5-4">y <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;">'whiff'</span>]</span>
<span id="cb5-5"></span>
<span id="cb5-6">X_train, X_test, y_train, y_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X, y, 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.2</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="cb5-7"></span>
<span id="cb5-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Training set size: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X_train<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape<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;">, Testing set size: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X_test<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape<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></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>Training set size: (1505, 27), Testing set size: (377, 27)</code></pre>
</div>
</div>
<p>For this analysis, we will use the <a href="https://scikit-learn.org/stable/modules/generated/sklearn.svm.LinearSVC.html#sklearn.svm.LinearSVC">LinearSVC</a> model from <code>sklearn</code>.</p>
<div id="d23bfc4a" class="cell" data-execution_count="5">
<details class="code-fold">
<summary>Code</summary>
<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 class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.svm <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LinearSVC</span>
<span id="cb7-2"><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</span>
<span id="cb7-3"></span>
<span id="cb7-4">model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearSVC(C<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="cb7-5">model.fit(X_train, y_train)</span>
<span id="cb7-6">score <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.score(X_test, y_test)</span>
<span id="cb7-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Test set accuracy: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>score <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 class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span>
<span id="cb7-8"></span>
<span id="cb7-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># cross-validation</span></span>
<span id="cb7-10">cv_scores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cross_val_score(model, X, y, cv<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="cb7-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Cross-validation scores: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>cv_scores<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="cb7-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Mean CV accuracy: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean(cv_scores) <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 class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>Test set accuracy: 61.54%
Cross-validation scores: [0.63660477 0.59681698 0.56117021 0.55585106 0.65957447]
Mean CV accuracy: 60.20%</code></pre>
</div>
</div>
<p>61% accuracy on the test set. So-so, still better than guessing. Let’s look at the feature importance to see which features are driving the model.</p>
<div id="1b632a96" class="cell" data-execution_count="6">
<details class="code-fold">
<summary>Code</summary>
<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 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="cb9-2">feature_names <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.columns</span>
<span id="cb9-3">coefficients <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.coef_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb9-4">importance <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.Series(coefficients, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>feature_names).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="cb9-5"></span>
<span id="cb9-6">plt.figure(figsize<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb9-7">importance.plot(kind<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;">'bar'</span>)</span>
<span id="cb9-8">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Feature Importance'</span>)</span>
<span id="cb9-9">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Coefficient Value'</span>)</span>
<span id="cb9-10">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/support-vector-machine/index_files/figure-html/cell-7-output-1.png" width="810" height="624" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>Low magnitude coefficients include <code>arm_angle</code>, <code>release_speed</code>, <code>release_pos_y</code>, <code>ay</code>, <code>n_thruorder_pitcher</code>, and <code>release_extension</code>. The highest magnitude coefficient is <code>vz0</code> which describes the pitch velocity in the z-direction. This makes sense because pitches with higher vertical velocity tend to have more movement, making them harder to hit. The most influential feature that increased the likelihood of a sample being classified as NOT a whiff is <code>plate_z</code>, the vertical position of the ball as it crosses the plate.</p>
<p>It is also worth noting that there could be data imbalance for swing and miss stuff. Not every pitch results in a whiff - in fact, most pitches do not. Let’s to get a more wholistic view of the model’s performance, we can plot the precision-recall curve. This will illustrate the trade-off between precision and recall for different threshold values.</p>
<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>Wikipedia has a great article on <a href="https://en.wikipedia.org/wiki/Precision_and_recall">Precision and Recall</a> if you want to learn more. I’ll write an article on this topic in the future.</p>
</div>
</div>
<div id="74661e89" class="cell" data-execution_count="7">
<details class="code-fold">
<summary>Code</summary>
<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"><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> PrecisionRecallDisplay</span>
<span id="cb10-2">display <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PrecisionRecallDisplay.from_estimator(</span>
<span id="cb10-3">    model, X_test, y_test, 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;">"LinearSVC"</span>, plot_chance_level<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>, despine<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="cb10-4">)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/support-vector-machine/index_files/figure-html/cell-8-output-1.png" width="445" height="431" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>Observe the cavity in the precision-recall curve. This indicates that the model is struggling to balance precision and recall. Only in a select few samples where recall is low do we gain high precision. The area under the precision-recall curve (AUC-PR) is a useful metric to summarize the model’s performance. The linear SVC models has an AUC-PR of 0.64.</p>
<p>While the initial results are not flattering, there is promise in the model’s ability to distinguish between classes. Moreover, this highlights the challenge in predicting baseball outcomes - a game where randomness plays a significant role. That said, we can do better. What if we use a non-linear kernel? Let’s try the <code>SVC</code> model with an RBF kernel. Let’s also remove the least important features.</p>
<div id="d627cfa2" class="cell" data-execution_count="8">
<details class="code-fold">
<summary>Code</summary>
<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="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.svm <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> SVC</span>
<span id="cb11-2"><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</span>
<span id="cb11-3"></span>
<span id="cb11-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Remove low importance features</span></span>
<span id="cb11-5">low_importance_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;">'arm_angle'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_speed'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_pos_y'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ay'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'n_thruorder_pitcher'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'release_extension'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type_FF'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type_SL'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type_SI'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type_ST'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type_KC'</span>]</span>
<span id="cb11-6">X_reduced <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.drop(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>low_importance_features)</span>
<span id="cb11-7">X_train, X_test, y_train, y_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X_reduced, y, 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.2</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="cb11-8"></span>
<span id="cb11-9">model_rbf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SVC(kernel<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;">'rbf'</span>, C<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>, gamma<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;">'scale'</span>)</span>
<span id="cb11-10">model_rbf.fit(X_train, y_train)</span>
<span id="cb11-11">score <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_rbf.score(X_test, y_test)</span>
<span id="cb11-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Test set accuracy: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>score <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 class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span>
<span id="cb11-13"></span>
<span id="cb11-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># cross-validation</span></span>
<span id="cb11-15">cv_scores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cross_val_score(model_rbf, X, y, cv<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="cb11-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Cross-validation scores: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>cv_scores<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-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Mean CV accuracy: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean(cv_scores) <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 class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>Test set accuracy: 67.37%
Cross-validation scores: [0.59416446 0.58885942 0.57978723 0.59042553 0.58776596]
Mean CV accuracy: 58.82%</code></pre>
</div>
</div>
<p>67% accuracy on the test set. That’s progress! The non-linear kernel allows the model to capture more complex relationships between features. Below is the precision-recall curve for the RBF SVC model.</p>
<div id="8d027766" class="cell" data-execution_count="9">
<details class="code-fold">
<summary>Code</summary>
<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">display_rbf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PrecisionRecallDisplay.from_estimator(</span>
<span id="cb13-2">    model_rbf, X_test, y_test, 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;">"SVC RBF"</span>, plot_chance_level<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>, despine<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="cb13-3">)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/support-vector-machine/index_files/figure-html/cell-10-output-1.png" width="445" height="431" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>As importantly, the AUC-PR for the RBF SVC model is 0.72. This is a sizeable improvement by simply changing the kernel and removing low importance features. One interpretation of this result is that the RBF model scores a precision value shy of 0.8 when recall is around 0.5. This means that when the model correctly identifies half of all whiffs, it is correct 80% of the time. This is promising! Consider this: a starting pitcher throws thousands of pitches throughout a season. Many of those pitches are called strikes, balls, or put in play. If a pitcher can identify the pitches that are most likely to result in whiffs, they can optimize their pitch selection and location to maximize their effectiveness.</p>
<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>Pitch characteristics alone do not determine the outcome of a pitch. It takes two to tango. The batter’s skill, the game situation, and even luck play significant roles. However, understanding the factors that contribute to whiffs can help pitchers and coaches make more informed decisions. A future direction could incorporate batter data, pitch sequences, and situational context to build a more comprehensive model.</p>
</div>
</div>
<p>Finally, let’s visualize the pitch locations that resulted in whiffs vs those that did not using our new model.</p>
<div id="9f9acffc" class="cell" data-execution_count="10">
<details class="code-fold">
<summary>Code</summary>
<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"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb14-2">sns.set_theme()</span>
<span id="cb14-3"></span>
<span id="cb14-4">df_reduced <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.drop(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>low_importance_features)</span>
<span id="cb14-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># undo one-hot encoding of pitch type</span></span>
<span id="cb14-6">df_reduced[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type'</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;">'pitch_type_FF'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type_SL'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type_SI'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type_ST'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type_KC'</span>]].idxmax(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="cb14-7">df_reduced[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_reduced[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pitch_type'</span>].<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;">'pitch_type_'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span>)</span>
<span id="cb14-8">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_rbf.predict(X_reduced)</span>
<span id="cb14-9">df_reduced[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'whiff_pred'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y_pred</span>
<span id="cb14-10"></span>
<span id="cb14-11">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cw2.csv"</span>)</span>
<span id="cb14-12">df_reduced[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'effective_speed'</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;">'effective_speed'</span>]</span>
<span id="cb14-13">df_reduced[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pfx_x'</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;">'pfx_x'</span>]</span>
<span id="cb14-14">df_reduced[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pfx_z'</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;">'pfx_z'</span>]</span>
<span id="cb14-15"></span>
<span id="cb14-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># plot two side-by-side scatter plots</span></span>
<span id="cb14-17">fig, axes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(nrows<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>, ncols<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>, figsize<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;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb14-18">ax1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sns.scatterplot(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_reduced, 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;">'pfx_x'</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;">'pfx_z'</span>, hue<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;">'whiff_pred'</span>, size<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;">"effective_speed"</span>, sizes<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>), style<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;">"pitch_type"</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.5</span>, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb14-19">ax1.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Pitch Movement'</span>)</span>
<span id="cb14-20">ax1.legend_.remove()</span>
<span id="cb14-21"></span>
<span id="cb14-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># change axis based on original plate_x and plate_z</span></span>
<span id="cb14-23">df_reduced[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'plate_x'</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;">'plate_x'</span>]</span>
<span id="cb14-24">df_reduced[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'plate_z'</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;">'plate_z'</span>]</span>
<span id="cb14-25"></span>
<span id="cb14-26">ax2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sns.scatterplot(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_reduced, 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;">'plate_x'</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;">'plate_z'</span>, hue<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;">'whiff_pred'</span>, size<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;">"effective_speed"</span>, sizes<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>), style<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;">"pitch_type"</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.5</span>, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>axes[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb14-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># draw strike zone</span></span>
<span id="cb14-28">strike_zone <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.Rectangle((<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.83</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.17</span>), <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.66</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.75</span>, fill<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;">'black'</span>, linestyle<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="cb14-29">ax2.add_patch(strike_zone)</span>
<span id="cb14-30">ax2.axhline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.17</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>, linestyle<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="cb14-31">ax2.axhline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.92</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>, linestyle<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="cb14-32">ax2.axvline(<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.83</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>, linestyle<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="cb14-33">ax2.axvline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.83</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>, linestyle<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="cb14-34">ax2.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Pitch Location'</span>)</span>
<span id="cb14-35"></span>
<span id="cb14-36"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># rename whiff_pred legend</span></span>
<span id="cb14-37">handles, labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ax2.get_legend_handles_labels()</span>
<span id="cb14-38">new_labels <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 Whiff'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'No Whiff'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Whiff'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Effective Speed'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'−3'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'−2'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'−1'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'0'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'1'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Pitch Type'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'FF'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SI'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SL'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'KC'</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ST'</span>]</span>
<span id="cb14-39">ax2.legend(handles, new_labels, loc<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;">'upper left'</span>, bbox_to_anchor<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb14-40">sns.move_legend(ax2, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"upper left"</span>, bbox_to_anchor<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb14-41">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/support-vector-machine/index_files/figure-html/cell-11-output-1.png" width="839" height="381" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>These two plots work together to tell a story about what the SVM model has learned, separating the physical “stuff” of a pitch from its ultimate “strategy.” The Pitch Movement plot on the left reveals that fastballs with high vertical movement and sliders exhibit the most whiffs. However, the Pitch Location plot on the right adds more complexity in where these pitches must end up to be effective. It clearly shows the model predicting whiffs primarily in the classic “chase” zones—low below the strike zone and high above it—while correctly identifying pitches over the heart of the plate as non-whiffs (blue). Taken together, the plots demonstrate that the model has learned a two-part rule: a pitch is predicted as a whiff (red) only when it possesses both an elite movement profile and is delivered to a deceptive, difficult-to-hit location.</p>
</section>
<section id="conclusion" class="level1">
<h1>Conclusion</h1>
<p>Analyzing pitch data serves as a testament to the phrase, “the Game within the Game”. Every pitch contains a wealth of information, and understanding these nuances can provide a competitive edge. Dylan Cease possesses elite stuff. Cease’s fastball-slider combination demonstrates how challenging it is for a batter to distinguish a fastball and slider—especially when both pitches come from the same arm slot.</p>
<p>It’s a beautiful lie, sold sixty feet six inches away. For the first forty feet, two entirely different products look identical. The batter, a man paid millions to make a split-second investment decision, is being sold a false prospectus. He has a fraction of a second to decide if he’s buying a 98-mile-per-hour corporate bond or a junk-rated slider that will default into the dirt. The old way of seeing the game—the scout in the stands with a radar gun and a gut feeling—would simply say, “The kid’s got a nasty slider.” And they’d be right, but also completely, hopelessly wrong.</p>
<p>Because what this model shows is that the game has moved on. The real edge isn’t knowing that the slider is good; it’s knowing precisely which version of the slider is good. Our little Support Vector Machine, humming away on a laptop, doesn’t care about labels. It has found the inefficiency in the market: the tiny, measurable quadrant of movement and location where a Cease slider transforms from merely difficult to statistically impossible. It’s the quant in the dugout, front-running the batter’s decision. And so the man in the box is left swinging at shadows, a victim not just of a pitcher’s talent, but of an arbitrage opportunity he never even knew existed. But to truly appreciate the deception, you have to see it for yourself.</p>
<iframe src="https://streamable.com/m/eugenio-suarez-strikes-out-swinging-kqqntp?partnerId=web_video-playback-page_video-share" width="720" height="415">
</iframe>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->

</section>

 ]]></description>
  <category>Padres</category>
  <category>classification</category>
  <category>scikit-learn</category>
  <guid>https://runningonnumbers.com/posts/support-vector-machine/</guid>
  <pubDate>Sat, 26 Jul 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/support-vector-machine/svm-main.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>Swing Fast: Predicting Barrel Rate with Fast Swing Rate</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/fast-swings-and-barrels/</link>
  <description><![CDATA[ 





<iframe src="https://streamable.com/m/stats-oddities-of-2024-aaron-judge?partnerId=web_video-playback-page_video-share" width="720" height="415">
</iframe>
<section id="introduction" class="level1">
<h1>Introduction</h1>
<p>In this article, we will explore the relationship between swing speed and barrel rate in Major League Baseball (MLB) players. Barrel rate is a key metric that measures the percentage of batted balls that are classified as “barrels,” which are hits with a high probability of resulting in extra-base hits. According to MLB, batted-ball events classified as Barrels had lead to a “minium 0.500 batting average and 1.500 slugging percentage” <span class="citation" data-cites="mlb"><span>“Standard <span>Stats</span> <span></span> <span>Glossary</span>”</span> (2025)</span>. By understanding how swing speed impacts barrel rate, we can gain insights into player performance and potentially identify areas for improvement. We will use a linear regression model but with an added twist: we will apply a square root transformation to capture non-linear relationships between swing speed and barrel rate. I refer you to my previous article on <a href="https://runningonnumbers.com/posts/ops-linear-regression/">linear regressions</a> for a refresher on the topic.</p>
</section>
<section id="data-preparation-and-linear-regression" class="level1">
<h1>Data Preparation and Linear Regression</h1>
<p>As usual, most of my data comes from playing around on <a href="https://baseballsavant.mlb.com/">Baseball Savant</a>. I like making custom leaderboards and viewing relationships between different stats. For this analysis, I focus on two main features: swing speed rate and barrel rate. Swing speed rate is the percentage of swings that reached 75MPH or greater. Barrel rate is the percentage of batted balls that have an exit velocity of 98MPH or greater and an ideal launch angle of 25-31 degrees.</p>
<p>Let’s plot some data.</p>
<div id="scatter-plot" class="cell" data-execution_count="1">
<details class="code-fold">
<summary>Code</summary>
<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="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-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.express <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> px</span>
<span id="cb1-3"><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-4"></span>
<span id="cb1-5">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"stats.csv"</span>)</span>
<span id="cb1-6">p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> px.scatter(</span>
<span id="cb1-7">    df, </span>
<span id="cb1-8">    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;">"fast_swing_rate"</span>, </span>
<span id="cb1-9">    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;">"barrel_batted_rate"</span>, </span>
<span id="cb1-10">    trendline<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;">"ols"</span>, </span>
<span id="cb1-11">    trendline_color_override<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;">"red"</span>,</span>
<span id="cb1-12">    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;">"Swing Speed Rate vs Barrel Rate"</span>,</span>
<span id="cb1-13">    hover_data<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;">"last_name, first_name"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fast_swing_rate"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel_batted_rate"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"year"</span>],</span>
<span id="cb1-14">)</span>
<span id="cb1-15">p.update_xaxes(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;">"Fast Speed Rate"</span>)</span>
<span id="cb1-16">p.update_yaxes(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;">"Barrel Rate"</span>)</span></code></pre></div>
</details>
<div id="scatter-plot-1" class="cell-output cell-output-display">
        <script type="text/javascript">
        window.PlotlyConfig = {MathJaxConfig: 'local'};
        if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}
        </script>
        <script type="module">import "https://cdn.plot.ly/plotly-3.0.1.min"</script>
        
<p>Scatter Plot of Fast Swing Rate vs Barrel Rate</p>
</div>
<div id="scatter-plot-2" class="cell-output cell-output-display">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="53f365a7-c1e9-45b5-9971-979c43eb9b2b" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("53f365a7-c1e9-45b5-9971-979c43eb9b2b")) {                    Plotly.newPlot(                        "53f365a7-c1e9-45b5-9971-979c43eb9b2b",                        [{"customdata":[["Yoshida, Masataka",2023],["Vaughn, Andrew",2023],["Rooker Jr., Brent",2023],["Rosario, Eddie",2023],["Davis, J.D.",2023],["Bell, Josh",2023],["Abreu, José",2023],["Friedl Jr., TJ",2023],["Canha, Mark",2023],["Freeman, Freddie",2023],["Happ, Ian",2023],["Ramírez, José",2023],["Nootbaar, Lars",2023],["Garcia, Maikel",2023],["Arraez, Luis",2023],["Alonso, Pete",2023],["Witt Jr., Bobby",2023],["Contreras, William",2023],["Hays, Austin",2023],["Lindor, Francisco",2023],["Soler, Jorge",2023],["Cronenworth, Jake",2023],["Thomas, Lane",2023],["Volpe, Anthony",2023],["Bichette, Bo",2023],["Díaz, Yandy",2023],["Castellanos, Nick",2023],["Turner, Justin",2023],["Meneses, Joey",2023],["Rutschman, Adley",2023],["Seager, Corey",2023],["Turner, Trea",2023],["Bogaerts, Xander",2023],["Drury, Brandon",2023],["Varsho, Daulton",2023],["Walker, Christian",2023],["Candelario, Jeimer",2023],["Reynolds, Bryan",2023],["Stephenson, Tyler",2023],["Tatis Jr., Fernando",2023],["Vierling, Matt",2023],["Suwinski, Jack",2023],["Merrifield, Whit",2023],["Edman, Tommy",2023],["Benintendi, Andrew",2023],["Ohtani, Shohei",2023],["Olson, Matt",2023],["France, Ty",2023],["McMahon, Ryan",2023],["Harper, Bryce",2023],["Arcia, Orlando",2023],["Taveras, Leody",2023],["Casas, Triston",2023],["Realmuto, J.T.",2023],["Adames, Willy",2023],["Chapman, Matt",2023],["Acuña Jr., Ronald",2023],["Betts, Mookie",2023],["Swanson, Dansby",2023],["Albies, Ozzie",2023],["Burger, Jake",2023],["Ozuna, Marcell",2023],["Robert Jr., Luis",2023],["Peña, Jeremy",2023],["Torres, Gleyber",2023],["Machado, Manny",2023],["Henderson, Gunnar",2023],["Outman, James",2023],["Tucker, Kyle",2023],["Jung, Josh",2023],["Anderson, Tim",2023],["Raleigh, Cal",2023],["Hernández, Enrique",2023],["Yelich, Christian",2023],["Goldschmidt, Paul",2023],["Renfroe, Hunter",2023],["Rosario, Amed",2023],["Suárez, Eugenio",2023],["LeMahieu, DJ",2023],["Springer III, George",2023],["Lowe, Nathaniel",2023],["Devers, Rafael",2023],["Bellinger, Cody",2023],["Melendez Jr., MJ",2023],["Gurriel Jr., Lourdes",2023],["Bohm, Alec",2023],["Smith, Dominic",2023],["Paredes, Isaac",2023],["Guerrero Jr., Vladimir",2023],["McNeil, Jeff",2023],["Abrams, CJ",2023],["Arozarena, Randy",2023],["Muncy, Max",2023],["Santander, Anthony",2023],["García, Adolis",2023],["Santana, Carlos",2023],["Steer, Spencer",2023],["Straw, Myles",2023],["Nimmo, Brandon",2023],["Stott, Bryson",2023],["Hoerner, Nico",2023],["Arenado, Nolan",2023],["Soto, Juan",2023],["Hernández, Teoscar",2023],["Carroll, Corbin",2023],["Hayes, Ke'Bryan",2023],["Báez, Javier",2023],["Crawford, J.P.",2023],["Bregman, Alex",2023],["Suzuki, Seiya",2023],["Kim, Ha-Seong",2023],["McKinstry, Zach",2023],["Semien, Marcus",2023],["Schwarber, Kyle",2023],["Profar, Jurickson",2023],["Estrada, Thairo",2023],["Marte, Ketel",2023],["India, Jonathan",2023],["Wade Jr., LaMonte",2023],["Torkelson, Spencer",2023],["Tovar, Ezequiel",2023],["Giménez, Andrés",2023],["Correa, Carlos",2023],["Smith, Will",2023],["Perez, Salvador",2023],["Harris II, Michael",2023],["Ruiz, Keibert",2023],["De La Cruz, Bryan",2023],["Kwan, Steven",2023],["Verdugo, Alex",2023],["Díaz, Elias",2023],["Rodríguez, Julio",2023],["Riley, Austin",2023],["Grisham, Trent",2023],["Bleday, JJ",2024],["Kwan, Steven",2024],["Torres, Gleyber",2024],["Naylor, Josh",2024],["Cowser, Colton",2024],["Rodríguez, Julio",2024],["Smith, Josh",2024],["Tovar, Ezequiel",2024],["Garcia, Maikel",2024],["Langeliers, Shea",2024],["Reynolds, Bryan",2024],["Castellanos, Nick",2024],["Busch, Michael",2024],["Hernández, Teoscar",2024],["Soto, Juan",2024],["McCutchen, Andrew",2024],["Sánchez, Jesús",2024],["Schwarber, Kyle",2024],["Carroll, Corbin",2024],["Cruz, Oneil",2024],["García, Luis",2024],["Volpe, Anthony",2024],["Machado, Manny",2024],["Burleson, Alec",2024],["Morel, Christopher",2024],["Ohtani, Shohei",2024],["Arraez, Luis",2024],["Abrams, CJ",2024],["Turang, Brice",2024],["Neto, Zach",2024],["Langford, Wyatt",2024],["Rutschman, Adley",2024],["Smith, Will",2024],["Donovan, Brendan",2024],["Judge, Aaron",2024],["Benintendi, Andrew",2024],["Chapman, Matt",2024],["Henderson, Gunnar",2024],["Young, Jacob",2024],["Betts, Mookie",2024],["Lindor, Francisco",2024],["Meyers, Jake",2024],["Seager, Corey",2024],["Olson, Matt",2024],["Suzuki, Seiya",2024],["De La Cruz, Bryan",2024],["Varsho, Daulton",2024],["Merrill, Jackson",2024],["Alvarez, Yordan",2024],["Ozuna, Marcell",2024],["Contreras, William",2024],["De La Cruz, Elly",2024],["Rafaela, Ceddanne",2024],["Walker, Christian",2024],["Castro, Willi",2024],["Perez, Salvador",2024],["Raleigh, Cal",2024],["Santander, Anthony",2024],["Ortiz, Joey",2024],["Rooker Jr., Brent",2024],["Devers, Rafael",2024],["Diaz, Yainer",2024],["Witt Jr., Bobby",2024],["Winn, Masyn",2024],["Díaz, Yandy",2024],["Cronenworth, Jake",2024],["Vaughn, Andrew",2024],["Chisholm Jr., Jazz",2024],["Duran, Jarren",2024],["Taveras, Leody",2024],["Steer, Spencer",2024],["Gurriel Jr., Lourdes",2024],["Hoerner, Nico",2024],["Frelick, Sal",2024],["Soler, Jorge",2024],["Suárez, Eugenio",2024],["Ramírez, José",2024],["Giménez, Andrés",2024],["India, Jonathan",2024],["Bohm, Alec",2024],["Doyle, Brenton",2024],["Peña, Jeremy",2024],["Schanuel, Nolan",2024],["Lowe, Nathaniel",2024],["Ramos, Heliot",2024],["Harper, Bryce",2024],["Arenado, Nolan",2024],["Stott, Bryson",2024],["Winker, Jesse",2024],["Thomas, Lane",2024],["Pasquantino, Vinnie",2024],["Hoskins, Rhys",2024],["Chourio, Jackson",2024],["Semien, Marcus",2024],["Rodgers, Brendan",2024],["Arozarena, Randy",2024],["Profar, Jurickson",2024],["Santana, Carlos",2024],["Marte, Ketel",2024],["Arcia, Orlando",2024],["Burger, Jake",2024],["García, Adolis",2024],["Vierling, Matt",2024],["Bregman, Alex",2024],["Paredes, Isaac",2024],["Stephenson, Tyler",2024],["Guerrero Jr., Vladimir",2024],["McMahon, Ryan",2024],["Greene, Riley",2024],["Verdugo, Alex",2024],["Goldschmidt, Paul",2024],["Turner, Justin",2024],["Keith, Colt",2024],["Freeman, Freddie",2024],["France, Ty",2024],["Adames, Willy",2024],["Mountcastle, Ryan",2024],["Nimmo, Brandon",2024],["O'Hoppe, Logan",2024],["Gelof, Zack",2024],["Bell, Josh",2024],["Ward, Taylor",2024],["Happ, Ian",2024],["Springer III, George",2024],["Bellinger, Cody",2024],["Turner, Trea",2024],["Alonso, Pete",2024],["Swanson, Dansby",2024],["Altuve, Jose",2024],["Robert Jr., Luis",2025],["Schanuel, Nolan",2025],["Steer, Spencer",2025],["Rice, Ben",2025],["Donovan, Brendan",2025],["Edwards, Xavier",2025],["Walker, Christian",2025],["Wagaman, Eric",2025],["Soderstrom, Tyler",2025],["Harper, Bryce",2025],["Soler, Jorge",2025],["Bichette, Bo",2025],["Buxton, Byron",2025],["Semien, Marcus",2025],["Meyers, Jake",2025],["Wood, James",2025],["Bellinger, Cody",2025],["Stott, Bryson",2025],["India, Jonathan",2025],["Contreras, Willson",2025],["Hoerner, Nico",2025],["Diaz, Yainer",2025],["Mullins II, Cedric",2025],["Ward, Taylor",2025],["Flores, Wilmer",2025],["O'Hearn, Ryan",2025],["Toglia, Michael",2025],["Torkelson, Spencer",2025],["Rengifo, Luis",2025],["Muncy, Max",2025],["Smith, Will",2025],["Hoskins, Rhys",2025],["Stowers, Kyle",2025],["Tatis Jr., Fernando",2025],["Goodman, Hunter",2025],["Adames, Willy",2025],["Langford, Wyatt",2025],["Rodríguez, Julio",2025],["Olson, Matt",2025],["Scott II, Victor",2025],["McCutchen, Andrew",2025],["Lowe, Nathaniel",2025],["Burleson, Alec",2025],["Wilson Jr., Jacob",2025],["Bell, Josh",2025],["Ramírez, José",2025],["Butler, Lawrence",2025],["Ramírez, Agustín",2025],["Holliday, Jackson",2025],["Clement, Ernie",2025],["Jung, Josh",2025],["Perez, Salvador",2025],["Garcia, Maikel",2025],["Schwarber, Kyle",2025],["McMahon, Ryan",2025],["Smith, Cam",2025],["Cruz, Oneil",2025],["Vargas, Miguel",2025],["Paredes, Isaac",2025],["Reynolds, Bryan",2025],["Naylor, Josh",2025],["Frelick, Sal",2025],["Crow-Armstrong, Pete",2025],["Suárez, Eugenio",2025],["Torres, Gleyber",2025],["Soto, Juan",2025],["Adell, Jo",2025],["Nimmo, Brandon",2025],["Guerrero Jr., Vladimir",2025],["Judge, Aaron",2025],["Duran, Jarren",2025],["Tucker, Kyle",2025],["Chourio, Jackson",2025],["Winn, Masyn",2025],["Lux, Gavin",2025],["Lindor, Francisco",2025],["Lee, Jung Hoo",2025],["Hernández, Teoscar",2025],["Swanson, Dansby",2025],["Turner, Trea",2025],["Perdomo, Geraldo",2025],["Bogaerts, Xander",2025],["Betts, Mookie",2025],["García, Adolis",2025],["Lowe, Brandon",2025],["Rooker Jr., Brent",2025],["Freeman, Freddie",2025],["Larnach, Trevor",2025],["Goldschmidt, Paul",2025],["McLain, Matt",2025],["Ozuna, Marcell",2025],["France, Ty",2025],["Bohm, Alec",2025],["Albies, Ozzie",2025],["Chapman, Matt",2025],["Grisham, Trent",2025],["Nootbaar, Lars",2025],["Happ, Ian",2025],["Arenado, Nolan",2025],["Aranda, Jonathan",2025],["Kirk, Alejandro",2025],["Devers, Rafael",2025],["Ohtani, Shohei",2025],["Crawford, J.P.",2025],["Springer III, George",2025],["Raleigh, Cal",2025],["Doyle, Brenton",2025],["Marte, Ketel",2025],["Realmuto, J.T.",2025],["McKinstry, Zach",2025],["Henderson, Gunnar",2025],["Correa, Carlos",2025],["Arraez, Luis",2025],["Santana, Carlos",2025],["Greene, Riley",2025],["Kwan, Steven",2025],["Caminero, Junior",2025],["Díaz, Yandy",2025],["Pasquantino, Vinnie",2025],["Smith, Josh",2025],["Domínguez, Jasson",2025],["Alonso, Pete",2025],["Turang, Brice",2025],["Machado, Manny",2025],["Peña, Jeremy",2025],["Beck, Jordan",2025],["Friedl Jr., TJ",2025],["Abreu, Wilyer",2025],["Gurriel Jr., Lourdes",2025],["Volpe, Anthony",2025],["Contreras, William",2025],["Busch, Michael",2025],["Ortiz, Joey",2025],["Yelich, Christian",2025],["Conforto, Michael",2025],["Sheets, Gavin",2025],["De La Cruz, Elly",2025],["Story, Trevor",2025],["Manzardo, Kyle",2025],["Castellanos, Nick",2025],["Yastrzemski, Mike",2025],["García, Luis",2025],["Carroll, Corbin",2025],["Arozarena, Randy",2025],["Riley, Austin",2025],["Pages, Andy",2025],["Ramos, Heliot",2025],["Kepler, Max",2025],["Lopez, Otto",2025],["Altuve, Jose",2025],["Witt Jr., Bobby",2025],["Rafaela, Ceddanne",2025],["Neto, Zach",2025],["Abrams, CJ",2025],["Hayes, Ke'Bryan",2025],["Harris II, Michael",2025],["Suzuki, Seiya",2025]],"hovertemplate":"fast_swing_rate=%{x}\u003cbr\u003ebarrel_batted_rate=%{y}\u003cbr\u003elast_name, first_name=%{customdata[0]}\u003cbr\u003eyear=%{customdata[1]}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"","marker":{"color":"#636efa","symbol":"circle"},"mode":"markers","name":"","orientation":"v","showlegend":false,"x":{"dtype":"f8","bdata":"mpmZmZmZM0DNzMzMzMwkQAAAAAAAwEBAZmZmZmZmJkAzMzMzM7MyQJqZmZmZGT1AzczMzMzMREDNzMzMzMwMQAAAAAAAAAxAzczMzMzMJkDNzMzMzEwzQAAAAAAAACpAAAAAAAAAN0AAAAAAAAAUQJqZmZmZmck\u002fAAAAAAAATECamZmZmdlKQDMzMzMzc0ZAzczMzMzMK0BmZmZmZmYtQAAAAAAAwE5AzczMzMzMEECamZmZmRkxQDMzMzMzMyJAzczMzMzML0CamZmZmZlEQM3MzMzMTDxAAAAAAAAA4D8AAAAAAAAnQAAAAAAAACRAzczMzMxMMUAAAAAAAAA7QJqZmZmZmS5AMzMzMzMzMUDNzMzMzIxHQM3MzMzMDElAmpmZmZmZG0CamZmZmZklQJqZmZmZmQVAzczMzMxMPkAzMzMzMzMpQJqZmZmZ2UFAMzMzMzMz8z\u002fNzMzMzMwvQGZmZmZmZgJAMzMzMzNzUkBmZmZmZuZIQAAAAAAAgDNAmpmZmZkZN0AAAAAAAIBLQM3MzMzMTDRAZmZmZmZmLUAAAAAAAMBOQAAAAAAAwEFAMzMzMzMzOECamZmZmVlMQGZmZmZmhlFAMzMzMzOzNEAAAAAAAAAiQM3MzMzMzCVAzczMzMwsUECamZmZmVlKQM3MzMzMTE9AAAAAAAAAMEBmZmZmZmY2QDMzMzMzk1BAZmZmZmamTEDNzMzMzMxAQAAAAAAAgDZAZmZmZmZmKkDNzMzMzMwIQM3MzMzMDElAZmZmZmZmN0AAAAAAAMBDQDMzMzMzszJAMzMzMzMzSECamZmZmZkuQM3MzMzMTDZAzczMzMzMEEBmZmZmZmY4QM3MzMzMDERAmpmZmZkZQUAzMzMzMzMZQGZmZmZmZjVAZmZmZmZmEkAzMzMzMzM0QDMzMzMzMxdAmpmZmZmZEUBmZmZmZiZKQM3MzMzMzARAMzMzMzMzNEAAAAAAAABAQM3MzMzMzC1AmpmZmZmZP0AzMzMzM3NDQM3MzMzMzCtAZmZmZmZmJ0AAAAAAAADwPzMzMzMzMztAZmZmZmZm5j8AAAAAAAAEQM3MzMzMTDBAmpmZmZkZSEAAAAAAAMBFQDMzMzMzsz1AZmZmZmbmNEAAAAAAAIBGQM3MzMzMTDdAAAAAAAAAFkBmZmZmZuY+QM3MzMzMzAxAMzMzMzMzC0CamZmZmZkTQJqZmZmZmVJAzczMzMzMM0BmZmZmZmYqQAAAAAAAQEFAAAAAAAAAOUAzMzMzMzM6QDMzMzMzM0lAZmZmZmZmNUAzMzMzMzMXQDMzMzMzs0lAAAAAAAAACECamZmZmRk9QAAAAAAAwEBAZmZmZmZmAkCamZmZmZk3QJqZmZmZmck\u002fMzMzMzMzB0BmZmZmZmZAQJqZmZmZWVFAZmZmZmZGUECamZmZmZkgQAAAAAAAgDBAmpmZmZmZ2T8AAAAAAAAiQJqZmZmZWUBAzczMzMxMREAzMzMzM7NPQDMzMzMzMxtAZmZmZmbmMkCamZmZmZklQAAAAAAAAEVAmpmZmZkZMUDNzMzMzMw2QJqZmZmZmSZAMzMzMzOzP0CamZmZmZlNQM3MzMzMTDlAMzMzMzMzS0AAAAAAAIBTQDMzMzMzc0JAMzMzMzPTUkAzMzMzM7M2QJqZmZmZmQ1AzczMzMxMSkAAAAAAAAAyQM3MzMzMLFBAAAAAAAAAUECamZmZmZnJP2ZmZmZm5jdAMzMzMzMzC0BmZmZmZmYtQJqZmZmZGUhAmpmZmZmZGUDNzMzMzMwIQM3MzMzMzBxAMzMzMzOzUkAAAAAAAADwP2ZmZmZmBlBAAAAAAAAgUEBmZmZmZmb2PzMzMzMzMyNAmpmZmZmZN0CamZmZmZkfQGZmZmZm5jRAmpmZmZlZQ0AAAAAAAIBBQM3MzMzMzDNAMzMzMzMzQUCamZmZmZk1QAAAAAAAgE9AAAAAAABARUAzMzMzMzNJQDMzMzMz80pAMzMzMzMzG0BmZmZmZmZKQAAAAAAAAC9AZmZmZmamQEDNzMzMzIxGQGZmZmZm5kBAmpmZmZmZQUCamZmZmZlCQGZmZmZm5jtAmpmZmZmZN0BmZmZmZiZIQAAAAAAAACdAMzMzMzMzQUAzMzMzMzMZQAAAAAAAAChAzczMzMxMN0CamZmZmRlCQJqZmZmZmS1AMzMzMzMzK0AAAAAAAAAjQGZmZmZmZgZAAAAAAAAABEDNzMzMzExMQAAAAAAAgDVAZmZmZmbmMkCamZmZmZkbQDMzMzMzMzZAMzMzMzOzNUAzMzMzMzMgQAAAAAAAgDZAzczMzMzMBEDNzMzMzEw9QJqZmZmZmUtAAAAAAACARECamZmZmZkpQGZmZmZmZv4\u002fmpmZmZmZHUBmZmZmZuYwQM3MzMzMzDNAAAAAAAAAKkAAAAAAAABBQM3MzMzMzBBAMzMzMzMzOUAzMzMzM7NAQDMzMzMzszZAZmZmZmZmM0DNzMzMzExEQAAAAAAAACtAMzMzMzNzR0AAAAAAAAA3QJqZmZmZmSdAzczMzMzMJ0AzMzMzMzMTQM3MzMzMzCJAAAAAAADATEDNzMzMzEw6QJqZmZmZ2UZAAAAAAAAAHkDNzMzMzEw4QJqZmZmZmek\u002fmpmZmZmZLEAzMzMzMzMkQJqZmZmZmSxAmpmZmZmZQEDNzMzMzExJQGZmZmZmZkFAZmZmZmZmMUBmZmZmZmYnQAAAAAAAAC5AzczMzMzMIEAzMzMzM7M3QM3MzMzMTDZAzczMzMzMFECamZmZmRkxQGZmZmZm5klAmpmZmZmZKUAAAAAAAAAqQJqZmZmZWU1AAAAAAAAAHkDNzMzMzMwYQDMzMzMzM0RAAAAAAAAAEEDNzMzMzMz8P5qZmZmZGURAMzMzMzOzO0AzMzMzM\u002fNCQDMzMzMzc0dAmpmZmZlZREAAAAAAAAAjQAAAAAAAQEhAmpmZmZmZFUAzMzMzMzMVQJqZmZmZGVBAmpmZmZmZIkCamZmZmZkTQDMzMzMzMzZAmpmZmZnZT0DNzMzMzMwMQDMzMzMzszFAAAAAAAAAJkAzMzMzMzMbQM3MzMzMzOw\u002fMzMzMzOzMkAzMzMzMzM3QAAAAAAAADlAmpmZmZmZIkDNzMzMzMwuQJqZmZmZmRdAZmZmZmZmL0CamZmZmVlKQAAAAAAAgERAMzMzMzOzREAAAAAAAIAzQM3MzMzMjEBAMzMzMzNzTUDNzMzMzExEQAAAAAAAABZAmpmZmZmZJkBmZmZmZuY4QGZmZmZmZjxAmpmZmZmZyT+amZmZmRk+QJqZmZmZGTJAmpmZmZmZQ0BmZmZmZiZKQJqZmZmZmSNAzczMzMzMAEAzMzMzMzMVQDMzMzMzsz5AZmZmZmbmMUCamZmZmblSQGZmZmZm5kRAAAAAAABASEDNzMzMzAxTQM3MzMzMzCdAzczMzMzMI0CamZmZmRk4QM3MzMzMTDJAzczMzMzMGEAzMzMzM7M5QGZmZmZm5jhAMzMzMzMzKEDNzMzMzExDQAAAAAAAAFJAZmZmZmZmNUBmZmZmZmZQQJqZmZmZuVFAmpmZmZmZRkAAAAAAAAA4QDMzMzMzs0RAmpmZmZkZMkCamZmZmZkVQM3MzMzMzCxAZmZmZmZmEEAAAAAAAIA\u002fQM3MzMzMzBZAmpmZmZmZL0AAAAAAAAASQGZmZmZmZjhAmpmZmZmZF0AzMzMzMzM7QDMzMzMzM0BAZmZmZmZmQ0CamZmZmZkbQGZmZmZm5jZAAAAAAACAOUDNzMzMzMwQQDMzMzMzM0NAzczMzMzMKEDNzMzMzMwwQDMzMzMzMxlAMzMzMzNzSEAAAAAAAAAnQGZmZmZmJkZAAAAAAAAAM0AAAAAAAIAxQAAAAAAAAC5AAAAAAACAOkAAAAAAAIAzQDMzMzMzc09AMzMzMzMzM0AAAAAAAEBBQM3MzMzMzEpAMzMzMzMzE0AzMzMzM\u002fNGQGZmZmZmZj9AAAAAAAAA8D8zMzMzMzNLQGZmZmZm5kNAMzMzMzMz0z+amZmZmRkyQAAAAAAAAEtAmpmZmZmZ8T8zMzMzMxNTQJqZmZmZmUJAMzMzMzMzPkBmZmZmZmYQQM3MzMzMzEBAzczMzMwMT0DNzMzMzMwqQAAAAAAAgEZAMzMzMzOzMUAzMzMzMzNDQAAAAAAAAARAZmZmZmamQ0CamZmZmZkjQAAAAAAAgDlAmpmZmZkZPkDNzMzMzMwgQGZmZmZm5jpAAAAAAAAAQUAzMzMzM\u002fNCQGZmZmZmJklAzczMzMwMR0AAAAAAAAAoQJqZmZmZmSNAAAAAAAAAMUAzMzMzMzMiQAAAAAAAgDxAAAAAAABAR0DNzMzMzMw7QM3MzMzMzE1AzczMzMzMNkDNzMzMzAxFQDMzMzMzszNAMzMzMzOzNkCamZmZmZkhQDMzMzMzM0hAZmZmZmZmJ0AAAAAAAAAtQGZmZmZmZjlAAAAAAAAAJ0DNzMzMzMxAQDMzMzMz80JA"},"xaxis":"x","y":{"dtype":"f8","bdata":"ZmZmZmZmGkDNzMzMzMwgQDMzMzMzMy9AAAAAAAAAI0AzMzMzMzMjQDMzMzMzMyRAZmZmZmZmIUCamZmZmZkJQM3MzMzMzBJAMzMzMzMzJkAAAAAAAAAiQAAAAAAAABxAmpmZmZmZIUAzMzMzMzMPQAAAAAAAAAxAZmZmZmZmLUAAAAAAAAAnQM3MzMzMzCJAzczMzMzMIUDNzMzMzMwkQAAAAAAAAC5AmpmZmZmZEUAzMzMzMzMjQAAAAAAAACJAMzMzMzMzI0AAAAAAAAAjQJqZmZmZmSRAzczMzMzMFkCamZmZmZkVQAAAAAAAAB5AZmZmZmZmLkDNzMzMzMwgQGZmZmZmZhhAAAAAAAAAJkAzMzMzMzMdQM3MzMzMzCZAmpmZmZmZH0AzMzMzMzMmQGZmZmZmZh5AAAAAAAAAJkBmZmZmZmYSQGZmZmZmZi9AMzMzMzMzA0AAAAAAAAAUQDMzMzMzMwdAmpmZmZmZM0BmZmZmZmYwQDMzMzMzMxtAzczMzMzMJkBmZmZmZmYuQJqZmZmZmRtAzczMzMzMHEAzMzMzMzMqQGZmZmZmZiZAzczMzMzMKECamZmZmRkxQJqZmZmZmS5AzczMzMzMKEDNzMzMzMwlQGZmZmZmZiBAMzMzMzOzMECamZmZmZkwQM3MzMzMzC5AAAAAAAAAEECamZmZmZkfQAAAAAAAACVAzczMzMzMJkAzMzMzMzMmQDMzMzMzMyVAzczMzMzMJ0AzMzMzMzMHQDMzMzMzMylAAAAAAAAAEkBmZmZmZmYiQAAAAAAAAChAZmZmZmZmGEAzMzMzMzMLQGZmZmZmZipAmpmZmZmZF0DNzMzMzMweQAAAAAAAABpAZmZmZmZmKUBmZmZmZmYYQM3MzMzMzCZAzczMzMzMIEDNzMzMzMwWQGZmZmZmZhpAmpmZmZmZF0AzMzMzMzMmQM3MzMzMzPQ\u002fmpmZmZmZG0CamZmZmZkoQDMzMzMzMy1AZmZmZmZmJECamZmZmRkwQM3MzMzMzBpAzczMzMzMGkAAAAAAAADgPwAAAAAAACNAzczMzMzMEkDNzMzMzMz8PzMzMzMzMx1AAAAAAAAAKkCamZmZmZkrQGZmZmZmZh5AmpmZmZmZHUDNzMzMzMwUQDMzMzMzMxNAmpmZmZmZFUAAAAAAAAAlQM3MzMzMzBBAZmZmZmZmHkAAAAAAAAAaQGZmZmZmZjBAAAAAAAAAEEAzMzMzMzMTQAAAAAAAACBAzczMzMzMHkAzMzMzMzMiQDMzMzMzMyxAMzMzMzMzIEAAAAAAAAAWQDMzMzMzMyNAzczMzMzMGkCamZmZmZkhQAAAAAAAACRAMzMzMzMzF0CamZmZmZkhQJqZmZmZmfE\u002fAAAAAAAAFEDNzMzMzMwYQM3MzMzMzCdAzczMzMzMK0DNzMzMzMwnQJqZmZmZmSBAzczMzMzMBEAzMzMzMzMZQM3MzMzMzCBAMzMzMzMzK0BmZmZmZmYkQJqZmZmZmQ1AAAAAAAAAIkCamZmZmZkNQJqZmZmZmSlAMzMzMzMzI0AzMzMzMzMgQGZmZmZmZiZAzczMzMzMLUAzMzMzM7MzQAAAAAAAAChAZmZmZmZmKEAzMzMzMzMvQM3MzMzMzBxAZmZmZmZmL0AAAAAAAAAgQDMzMzMzMw9AAAAAAAAAJkAAAAAAAAAaQGZmZmZmZiRAAAAAAACANUCamZmZmZn5P5qZmZmZmRtAMzMzMzMzA0DNzMzMzMwgQJqZmZmZmSJAZmZmZmZmGECamZmZmZklQAAAAAAAABZAZmZmZmbmOkAzMzMzMzMZQDMzMzMzMylAZmZmZmZmJkCamZmZmZn5PwAAAAAAABhAMzMzMzMzK0AzMzMzMzMbQGZmZmZmZi5AzczMzMzMKEAAAAAAAAAnQJqZmZmZmSJAzczMzMzMGECamZmZmZkmQAAAAAAAAC1AAAAAAAAAL0AAAAAAAAAkQGZmZmZmZilAAAAAAAAAHkCamZmZmZkqQAAAAAAAABxAZmZmZmZmKEDNzMzMzMwuQGZmZmZmZidAZmZmZmZmEkCamZmZmZkwQAAAAAAAACpAZmZmZmZmHkCamZmZmZksQJqZmZmZmQ1AZmZmZmZmHkAzMzMzMzMfQJqZmZmZmSJAZmZmZmZmI0CamZmZmZkiQJqZmZmZmRdAmpmZmZmZGUDNzMzMzMwaQDMzMzMzM\u002fM\u002fmpmZmZmZ6T8zMzMzMzMpQJqZmZmZmSZAMzMzMzMzIUBmZmZmZmYGQM3MzMzMzB5AMzMzMzMzG0AAAAAAAAAlQJqZmZmZmRVAAAAAAAAADEAzMzMzMzMXQAAAAAAAAC1AMzMzMzMzJUCamZmZmZkJQM3MzMzMzAxAZmZmZmZmHkCamZmZmZkdQGZmZmZmZhxAZmZmZmZmKUAzMzMzMzMfQGZmZmZmZhpAZmZmZmZmFkCamZmZmZkgQM3MzMzMzBxAMzMzMzMzHUCamZmZmZkoQDMzMzMzMxVAmpmZmZmZKEAAAAAAAAApQAAAAAAAAB5AmpmZmZmZGUAAAAAAAAASQDMzMzMzMyJAZmZmZmZmK0DNzMzMzMwlQM3MzMzMzCpAZmZmZmZmFkBmZmZmZmYlQGZmZmZmZhJAZmZmZmZmFkAzMzMzMzMiQDMzMzMzMx1AAAAAAAAAKECamZmZmZkhQDMzMzMzMyJAAAAAAAAAKECamZmZmZkhQGZmZmZmZh5AAAAAAAAAKkBmZmZmZmYnQJqZmZmZmSJAMzMzMzMzGUCamZmZmZkbQGZmZmZmZipAZmZmZmZmIkAAAAAAAAAaQM3MzMzMzCZAmpmZmZmZFUAAAAAAAAAWQJqZmZmZmS9AZmZmZmZmIkBmZmZmZmbmPwAAAAAAACdAMzMzMzMzF0DNzMzMzMwoQAAAAAAAACdAmpmZmZmZJ0DNzMzMzMwjQDMzMzMzMy9AmpmZmZmZH0BmZmZmZmYUQAAAAAAAgDJAmpmZmZmZIEBmZmZmZmYUQGZmZmZmZhhAMzMzMzMzK0AAAAAAAAAEQGZmZmZmZiJAmpmZmZmZGUAzMzMzMzMqQAAAAAAAABBAAAAAAAAAIkBmZmZmZmYlQJqZmZmZmS5AMzMzMzMzEUAzMzMzMzMsQJqZmZmZmStAAAAAAAAAJUBmZmZmZmYyQGZmZmZmZidAMzMzMzMzKUDNzMzMzMwpQDMzMzMzMylAzczMzMzMHkAAAAAAAIAwQGZmZmZmZhJAZmZmZmZmI0BmZmZmZmYcQGZmZmZmZiJAZmZmZmZmAkDNzMzMzMwkQJqZmZmZmR9AMzMzMzMzIkBmZmZmZmYoQGZmZmZmZiVAzczMzMzM\u002fD+amZmZmZkgQJqZmZmZmSxAAAAAAAAAGECamZmZmRkyQDMzMzMzMyhAmpmZmZmZHUDNzMzMzEw2QM3MzMzMzCFAZmZmZmZmGEBmZmZmZmYmQJqZmZmZmRlAAAAAAAAACEAzMzMzMzMsQM3MzMzMzCtAmpmZmZmZI0AAAAAAAAAyQM3MzMzMzC9AzczMzMzMI0DNzMzMzMwqQGZmZmZmZjpAmpmZmZmZI0BmZmZmZmYpQAAAAAAAABxAzczMzMzMFkDNzMzMzMwMQJqZmZmZmSFAMzMzMzMzEUDNzMzMzMwnQAAAAAAAACZAZmZmZmZmGkBmZmZmZmYYQGZmZmZmZhRAMzMzMzMzF0DNzMzMzMwqQJqZmZmZmSpAmpmZmZmZLECamZmZmZkiQDMzMzMzMyBAMzMzMzMzIECamZmZmZkbQDMzMzMzMyZAZmZmZmZmIUAAAAAAAAAaQJqZmZmZmQ1AZmZmZmZmJEBmZmZmZmYsQM3MzMzMzCRAzczMzMzMIUDNzMzMzMwQQDMzMzMzMyhAmpmZmZmZIkAzMzMzMzMuQAAAAAAAgDVAmpmZmZmZFUDNzMzMzMwuQDMzMzMzMzRAmpmZmZmZJ0DNzMzMzMwvQDMzMzMzMx9AMzMzMzMzG0AzMzMzMzMhQJqZmZmZmRdAmpmZmZmZ6T9mZmZmZmYYQM3MzMzMTDJAzczMzMzMAEAAAAAAAAAmQGZmZmZmZiRAZmZmZmZmIUAzMzMzMzMVQDMzMzMzMyBAAAAAAACANEDNzMzMzMwWQGZmZmZmZitAmpmZmZmZH0AAAAAAAAAnQM3MzMzMzAhAzczMzMzMKECamZmZmZkbQAAAAAAAACNAZmZmZmZmEkAAAAAAAAAvQJqZmZmZmQ1AmpmZmZmZIUAAAAAAAAAjQJqZmZmZmSRAMzMzMzMzKkCamZmZmZkkQAAAAAAAACdAAAAAAAAAI0CamZmZmZkfQM3MzMzMzCFAzczMzMzMLkCamZmZmZknQAAAAAAAAC5AMzMzMzMzIEBmZmZmZmYlQM3MzMzMzCZAzczMzMzMHkBmZmZmZmYYQAAAAAAAACtAAAAAAAAAKkBmZmZmZmYtQGZmZmZmZhpAZmZmZmZmFkDNzMzMzMwYQM3MzMzMzDJA"},"yaxis":"y","type":"scatter"},{"hovertemplate":"\u003cb\u003eOLS trendline\u003c\u002fb\u003e\u003cbr\u003ebarrel_batted_rate = 0.153913 * fast_swing_rate + 5.42885\u003cbr\u003eR\u003csup\u003e2\u003c\u002fsup\u003e=0.479087\u003cbr\u003e\u003cbr\u003efast_swing_rate=%{x}\u003cbr\u003ebarrel_batted_rate=%{y} \u003cb\u003e(trend)\u003c\u002fb\u003e\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"","line":{"color":"red"},"marker":{"color":"#636efa","symbol":"circle"},"mode":"lines","name":"","showlegend":false,"x":{"dtype":"f8","bdata":"mpmZmZmZyT+amZmZmZnJP5qZmZmZmck\u002fmpmZmZmZyT8zMzMzMzPTP5qZmZmZmdk\u002fAAAAAAAA4D9mZmZmZmbmP5qZmZmZmek\u002fzczMzMzM7D8AAAAAAADwPwAAAAAAAPA\u002fAAAAAAAA8D+amZmZmZnxPzMzMzMzM\u002fM\u002fZmZmZmZm9j\u002fNzMzMzMz8P2ZmZmZmZv4\u002fzczMzMzMAEBmZmZmZmYCQGZmZmZmZgJAAAAAAAAABEAAAAAAAAAEQAAAAAAAAARAzczMzMzMBEDNzMzMzMwEQJqZmZmZmQVAZmZmZmZmBkAzMzMzMzMHQAAAAAAAAAhAzczMzMzMCEDNzMzMzMwIQDMzMzMzMwtAMzMzMzMzC0AAAAAAAAAMQM3MzMzMzAxAzczMzMzMDEDNzMzMzMwMQJqZmZmZmQ1AAAAAAAAAEEBmZmZmZmYQQGZmZmZmZhBAzczMzMzMEEDNzMzMzMwQQM3MzMzMzBBAzczMzMzMEECamZmZmZkRQAAAAAAAABJAZmZmZmZmEkAzMzMzMzMTQDMzMzMzMxNAmpmZmZmZE0CamZmZmZkTQAAAAAAAABRAzczMzMzMFEAzMzMzMzMVQDMzMzMzMxVAmpmZmZmZFUCamZmZmZkVQAAAAAAAABZAAAAAAAAAFkDNzMzMzMwWQDMzMzMzMxdAMzMzMzMzF0CamZmZmZkXQJqZmZmZmRdAzczMzMzMGEDNzMzMzMwYQDMzMzMzMxlAMzMzMzMzGUAzMzMzMzMZQJqZmZmZmRlAMzMzMzMzG0AzMzMzMzMbQDMzMzMzMxtAmpmZmZmZG0CamZmZmZkbQJqZmZmZmRtAzczMzMzMHECamZmZmZkdQAAAAAAAAB5AAAAAAAAAHkCamZmZmZkfQDMzMzMzMyBAmpmZmZmZIEDNzMzMzMwgQM3MzMzMzCBAmpmZmZmZIUAAAAAAAAAiQAAAAAAAACJAMzMzMzMzIkAzMzMzMzMiQJqZmZmZmSJAmpmZmZmZIkDNzMzMzMwiQAAAAAAAACNAAAAAAAAAI0AzMzMzMzMjQJqZmZmZmSNAmpmZmZmZI0CamZmZmZkjQM3MzMzMzCNAAAAAAAAAJEAzMzMzMzMkQM3MzMzMzCRAmpmZmZmZJUCamZmZmZklQM3MzMzMzCVAAAAAAAAAJkBmZmZmZmYmQJqZmZmZmSZAmpmZmZmZJkDNzMzMzMwmQAAAAAAAACdAAAAAAAAAJ0AAAAAAAAAnQAAAAAAAACdAZmZmZmZmJ0BmZmZmZmYnQGZmZmZmZidAmpmZmZmZJ0DNzMzMzMwnQM3MzMzMzCdAAAAAAAAAKEAAAAAAAAAoQDMzMzMzMyhAzczMzMzMKEAzMzMzMzMpQJqZmZmZmSlAmpmZmZmZKUAAAAAAAAAqQAAAAAAAACpAAAAAAAAAKkBmZmZmZmYqQGZmZmZmZipAzczMzMzMKkAAAAAAAAArQDMzMzMzMytAzczMzMzMK0DNzMzMzMwrQJqZmZmZmSxAmpmZmZmZLEDNzMzMzMwsQAAAAAAAAC1AZmZmZmZmLUBmZmZmZmYtQGZmZmZmZi1AmpmZmZmZLUDNzMzMzMwtQAAAAAAAAC5AAAAAAAAALkCamZmZmZkuQJqZmZmZmS5AzczMzMzMLkAAAAAAAAAvQGZmZmZmZi9AmpmZmZmZL0DNzMzMzMwvQM3MzMzMzC9AAAAAAAAAMEDNzMzMzEwwQAAAAAAAgDBAzczMzMzMMEBmZmZmZuYwQAAAAAAAADFAmpmZmZkZMUCamZmZmRkxQJqZmZmZGTFAMzMzMzMzMUDNzMzMzEwxQGZmZmZmZjFAAAAAAACAMUAzMzMzM7MxQDMzMzMzszFAZmZmZmbmMUAAAAAAAAAyQJqZmZmZGTJAmpmZmZkZMkCamZmZmRkyQM3MzMzMTDJAMzMzMzOzMkAzMzMzM7MyQDMzMzMzszJAZmZmZmbmMkBmZmZmZuYyQAAAAAAAADNAMzMzMzMzM0DNzMzMzEwzQGZmZmZmZjNAAAAAAACAM0AAAAAAAIAzQAAAAAAAgDNAmpmZmZmZM0AzMzMzM7MzQM3MzMzMzDNAzczMzMzMM0DNzMzMzMwzQDMzMzMzMzRAMzMzMzMzNEDNzMzMzEw0QDMzMzMzszRAZmZmZmbmNEBmZmZmZuY0QGZmZmZmZjVAZmZmZmZmNUBmZmZmZmY1QAAAAAAAgDVAmpmZmZmZNUAzMzMzM7M1QDMzMzMzMzZAMzMzMzMzNkDNzMzMzEw2QM3MzMzMTDZAZmZmZmZmNkAAAAAAAIA2QAAAAAAAgDZAMzMzMzOzNkAzMzMzM7M2QDMzMzMzszZAzczMzMzMNkDNzMzMzMw2QGZmZmZm5jZAAAAAAAAAN0AAAAAAAAA3QJqZmZmZGTdAMzMzMzMzN0DNzMzMzEw3QM3MzMzMTDdAZmZmZmZmN0CamZmZmZk3QJqZmZmZmTdAmpmZmZmZN0AzMzMzM7M3QGZmZmZm5jdAAAAAAAAAOECamZmZmRk4QDMzMzMzMzhAzczMzMxMOEBmZmZmZmY4QGZmZmZmZjhAZmZmZmbmOEBmZmZmZuY4QAAAAAAAADlAAAAAAAAAOUAzMzMzMzM5QM3MzMzMTDlAZmZmZmZmOUAAAAAAAIA5QAAAAAAAgDlAMzMzMzOzOUAzMzMzMzM6QM3MzMzMTDpAAAAAAACAOkBmZmZmZuY6QAAAAAAAADtAMzMzMzMzO0AzMzMzMzM7QDMzMzMzsztAzczMzMzMO0BmZmZmZuY7QM3MzMzMTDxAZmZmZmZmPEAAAAAAAIA8QJqZmZmZGT1AmpmZmZkZPUDNzMzMzEw9QDMzMzMzsz1AmpmZmZkZPkCamZmZmRk+QDMzMzMzMz5AzczMzMxMPkAzMzMzM7M+QGZmZmZm5j5AZmZmZmZmP0AAAAAAAIA\u002fQJqZmZmZmT9AMzMzMzOzP0AAAAAAAABAQDMzMzMzM0BAmpmZmZlZQEBmZmZmZmZAQM3MzMzMjEBAmpmZmZmZQEBmZmZmZqZAQDMzMzMzs0BAAAAAAADAQEAAAAAAAMBAQM3MzMzMzEBAzczMzMzMQEDNzMzMzMxAQGZmZmZm5kBAAAAAAAAAQUAAAAAAAABBQJqZmZmZGUFAMzMzMzMzQUAzMzMzMzNBQAAAAAAAQEFAAAAAAABAQUBmZmZmZmZBQAAAAAAAgEFAmpmZmZmZQUAAAAAAAMBBQJqZmZmZ2UFAmpmZmZkZQkAzMzMzM3NCQJqZmZmZmUJAmpmZmZmZQkAzMzMzM\u002fNCQDMzMzMz80JAMzMzMzPzQkAzMzMzMzNDQDMzMzMzM0NAzczMzMxMQ0CamZmZmVlDQGZmZmZmZkNAMzMzMzNzQ0CamZmZmZlDQGZmZmZmpkNAAAAAAADAQ0BmZmZmZuZDQM3MzMzMDERAmpmZmZkZREAzMzMzMzNEQM3MzMzMTERAzczMzMxMREDNzMzMzExEQJqZmZmZWURAAAAAAACAREAAAAAAAIBEQJqZmZmZmURAMzMzMzOzREAzMzMzM7NEQM3MzMzMzERAZmZmZmbmREAAAAAAAABFQM3MzMzMDEVAAAAAAABARUAAAAAAAMBFQGZmZmZmJkZAMzMzMzNzRkAAAAAAAIBGQAAAAAAAgEZAzczMzMyMRkCamZmZmZlGQJqZmZmZ2UZAMzMzMzPzRkDNzMzMzAxHQAAAAAAAQEdAMzMzMzNzR0AzMzMzM3NHQM3MzMzMjEdAmpmZmZkZSECamZmZmRlIQGZmZmZmJkhAMzMzMzMzSEAzMzMzMzNIQAAAAAAAQEhAAAAAAABASEAzMzMzM3NIQGZmZmZm5khAzczMzMwMSUDNzMzMzAxJQGZmZmZmJklAMzMzMzMzSUAzMzMzMzNJQM3MzMzMTElAMzMzMzOzSUBmZmZmZuZJQGZmZmZmJkpAZmZmZmYmSkDNzMzMzExKQJqZmZmZWUpAmpmZmZlZSkBmZmZmZmZKQM3MzMzMzEpAmpmZmZnZSkAzMzMzM\u002fNKQAAAAAAAAEtAMzMzMzMzS0AzMzMzMzNLQAAAAAAAgEtAmpmZmZmZS0AAAAAAAABMQM3MzMzMTExAmpmZmZlZTEBmZmZmZqZMQAAAAAAAwExAmpmZmZlZTUAzMzMzM3NNQJqZmZmZmU1AzczMzMzMTUAAAAAAAMBOQAAAAAAAwE5AzczMzMwMT0DNzMzMzExPQDMzMzMzc09AAAAAAACAT0AzMzMzM7NPQJqZmZmZ2U9AAAAAAAAAUEBmZmZmZgZQQJqZmZmZGVBAAAAAAAAgUEDNzMzMzCxQQM3MzMzMLFBAZmZmZmZGUEBmZmZmZmZQQDMzMzMzk1BAmpmZmZlZUUBmZmZmZoZRQJqZmZmZuVFAAAAAAAAAUkAzMzMzM3NSQJqZmZmZmVJAMzMzMzOzUkCamZmZmblSQDMzMzMz01JAzczMzMwMU0AzMzMzMxNTQAAAAAAAgFNA"},"xaxis":"x","y":{"dtype":"f8","bdata":"O2WgG6nWFUA7ZaAbqdYVQDtloBup1hVAO2WgG6nWFUB8pf7Ua+YVQLzlXI4u9hVA\u002fSW7R\u002fEFFkB+pne6diUWQL\u002fm1XM5NRZA\u002fyY0LfxEFkBAZ5LmvlQWQEBnkua+VBZAQGeS5r5UFkCAp\u002fCfgWQWQMHnTllEdBZAQmgLzMmTFkBEaYSx1NIWQIWp4mqX4hZABiqf3RwCF0CHqltQoiEXQIeqW1CiIRdACCsYwydBF0AIKxjDJ0EXQAgrGMMnQRdASWt2fOpQF0BJa3Z86lAXQImr1DWtYBdAyusy729wF0AKLJGoMoAXQEts72H1jxdAjKxNG7ifF0CMrE0buJ8XQE1taEcAzxdATW1oRwDPF0COrcYAw94XQM7tJLqF7hdAzu0kuoXuF0DO7SS6he4XQA8ug3NI\u002fhdA0e6dn5AtGEARL\u002fxYUz0YQBEv\u002fFhTPRhAUm9aEhZNGEBSb1oSFk0YQFJvWhIWTRhAUm9aEhZNGEDT7xaFm2wYQBQwdT5efBhAVHDT9yCMGEDV8I9qpqsYQNXwj2qmqxhAFjHuI2m7GEAWMe4jabsYQFZxTN0ryxhA2PEIULHqGEAYMmcJdPoYQBgyZwl0+hhAWXLFwjYKGUBZcsXCNgoZQJmyI3z5GRlAmbIjfPkZGUAaM+DufjkZQFtzPqhBSRlAW3M+qEFJGUCbs5xhBFkZQJuznGEEWRlAXXS3jUyIGUBddLeNTIgZQJ60FUcPmBlAnrQVRw+YGUCetBVHD5gZQN70cwDSpxlA4PXs5dzmGUDg9ezl3OYZQOD17OXc5hlAITZLn5\u002f2GUAhNkufn\u002fYZQCE2S5+f9hlA4\u002fZly+clGkBkdyI+bUUaQKS3gPcvVRpApLeA9y9VGkCnuPncOpQaQCg5tk\u002fAsxpAqblywkXTGkDq+dB7COMaQOr50HsI4xpA7PpJYRMiG0BtewbUmEEbQG17BtSYQRtArrtkjVtRG0Cuu2SNW1EbQC88IQDhcBtALzwhAOFwG0BvfH+5o4AbQLC83XJmkBtAsLzdcmaQG0Dw\u002fDssKaAbQHJ9+J6uvxtAcn34nq6\u002fG0Byffierr8bQLK9VlhxzxtA8v20ETTfG0AzPhPL9u4bQPX+Lfc+HhxA9\u002f+m3EldHED3\u002f6bcSV0cQDhABZYMbRxAeIBjT898HED5ACDCVJwcQDpBfnsXrBxAOkF+exesHEB6gdw02rscQLvBOu6cyxxAu8E67pzLHEC7wTrunMscQLvBOu6cyxxAPEL3YCLrHEA8QvdgIuscQDxC92Ai6xxAfYJVGuX6HEC9wrPTpwodQL3Cs9OnCh1A\u002fgISjWoaHUD+AhKNahodQD5DcEYtKh1AAASLcnVZHUCBhEfl+ngdQAIFBFiAmB1AAgUEWICYHUCEhcDKBbgdQISFwMoFuB1AhIXAygW4HUAEBn09i9cdQAQGfT2L1x1AhoY5sBD3HUDGxpdp0wYeQAcH9iKWFh5AyMcQT95FHkDIxxBP3kUeQMvIiTTphB5Ay8iJNOmEHkAMCejtq5QeQExJRqdupB5AzckCGvTDHkDNyQIa9MMeQM3JAhr0wx5ADgph07bTHkBOSr+MeeMeQI+KHUY88x5Aj4odRjzzHkBQSzhyhCIfQFBLOHKEIh9AkYuWK0cyH0DSy\u002fTkCUIfQFJMsVePYR9AlIwPEVJxH0DUzG3KFIEfQNTMbcoUgR9AFA3Mg9eQH0DWzeavH8AfQFhOoyKl3x9AjAdfp3YHIECtJw4EWA8gQM1HvWA5FyBA7mdsvRofIEDuZ2y9Gh8gQO5nbL0aHyBADogbGvwmIEAuqMp23S4gQE7IedO+NiBAbugoMKA+IECvKIfpYk4gQK8oh+liTiBA8GjloiVeIEAQiZT\u002fBmYgQDCpQ1zobSBAMKlDXOhtIEAwqUNc6G0gQHHpoRWrfSBA8mleiDCdIEDyaV6IMJ0gQPJpXogwnSBAMqq8QfOsIEAyqrxB86wgQFPKa57UtCBAkwrKV5fEIEC0Knm0eMwgQNRKKBFa1CBA9GrXbTvcIED0atdtO9wgQPRq12073CBAFIuGyhzkIEA1qzUn\u002fusgQFXL5IPf8yBAVcvkg9\u002fzIEBVy+SD3\u002fMgQNZLofZkEyFA1kuh9mQTIUD2a1BTRhshQHjsDMbLOiFAuCxrf45KIUC4LGt\u002fjkohQFrN1k71cSFAWs3WTvVxIUBazdZO9XEhQHrthavWeSFAmg01CLiBIUC6LeRkmYkhQFzOTzQAsSFAXM5PNACxIUB87v6Q4bghQHzu\u002fpDhuCFAnA6u7cLAIUC9Ll1KpMghQL0uXUqkyCFA\u002fW67A2fYIUD9brsDZ9ghQP1uuwNn2CFAHo9qYEjgIUAej2pgSOAhQD6vGb0p6CFAXs\u002fIGQvwIUBez8gZC\u002fAhQH7vd3bs9yFAng8n083\u002fIUC\u002fL9YvrwciQL8v1i+vByJA30+FjJAPIkAgkONFUx8iQCCQ40VTHyJAIJDjRVMfIkBAsJKiNCciQIDw8Fv3NiJAoRCguNg+IkDBME8VukYiQOJQ\u002fnGbTiJAAnGtznxWIkAikVwrXl4iQCKRXCteXiJAwzHI+sSFIkDDMcj6xIUiQORRd1emjSJA5FF3V6aNIkAkktUQaZ0iQESyhG1KpSJAZdIzyiutIkCF8uImDbUiQIXy4iYNtSJAxjJB4M\u002fEIkBn06yvNuwiQIjzWwwY9CJAyDO6xdoDI0BJtHY4YCMjQGrUJZVBKyNAqhSETgQ7I0CqFIROBDsjQEy17x1rYiNAbNWeekxqI0CM9U3XLXIjQA12CkqzkSNALZa5ppSZI0BOtmgDdqEjQBB3gy++0CNAEHeDL77QI0BQt+HogOAjQNE3nlsGACRAUrhazosfJEBSuFrOix8kQHLYCSttJyRAk\u002fi4h04vJEAUeXX6004kQFS507OWXiRA9lk\u002fg\u002f2FJEAWeu7f3o0kQDaanTzAlSRAVrpMmaGdJEC4GlqvRbUkQDibFiLL1CRAmvsjOG\u002fsJEC6G9OUUPQkQBp84Kr0CyVAO5yPB9YTJUBbvD5ktxslQHzc7cCYIyVAnPycHXorJUCc\u002fJwdeislQLwcTHpbMyVAvBxMelszJUC8HEx6WzMlQPxcqjMeQyVAPZ0I7eBSJUA9nQjt4FIlQH7dZqajYiVAvh3FX2ZyJUC+HcVfZnIlQN49dLxHeiVA3j10vEd6JUA\u002fnoHS65ElQIDe34uuoSVAwR4+RXGxJUAif0tbFcklQGK\u002fqRTY2CVABGAV5D4AJkDlQN9saDcmQEah7IIMTyZARqHsggxPJkAogrYLNoYmQCiCtgs2hiZAKIK2CzaGJkDKIiLbnK0mQMoiItucrSZACmOAlF+9JkAqgy\u002fxQMUmQEqj3k0izSZAa8ONqgPVJkDMI5vAp+wmQOxDSh2J9CZALISo1ksEJ0CO5LXs7xsnQO5EwwKUMydAD2VyX3U7J0BPpdAYOEsnQJDlLtL6WidAkOUu0vpaJ0CQ5S7S+lonQLAF3i7cYidAEWbrRIB6J0ARZutEgHonQFKmSf5CiidAkuantwWaJ0CS5qe3BZonQNMmBnHIqSdAE2dkKou5J0BUp8LjTcknQHTHcUAv0SdA9Ucus7TwJ0A4iQVSgj8oQDqKfjeNfihA\u002fEqZY9WtKEAca0jAtrUoQBxrSMC2tShAPIv3HJi9KEBdq6Z5ecUoQP5LEkng7ChAPoxwAqP8KECAzM67ZQwpQABNiy7rKylAgs1HoXBLKUCCzUehcEspQMINplozWylAJm8sVuKxKUAmbyxW4rEpQEaP27LDuSlAZq+KD6XBKUBmr4oPpcEpQIbPOWyGySlAhs85bIbJKUAHUPbeC+kpQCpxHiH4LypAi9ErN5xHKkCL0Ss3nEcqQMsRivBeVypA7DE5TUBfKkDsMTlNQF8qQCxylwYDbypALnMQ7A2uKkCw88xek80qQFGUOC769CpAUZQ4Lvr0KkCy9EVEngwrQNIU9aB\u002fFCtA0hT1oH8UK0DyNKT9YBwrQPU1HeNrWytAFVbMP01jK0BVlir5D3MrQHa22VXxeitA9zaWyHaaK0D3NpbIdporQLn3sPS+yStA+TcProHZK0D7OIiTjBgsQL35or\u002fURyxA3hlSHLZPLECf2mxI\u002fn4sQOAaywHBjixAY5wAWlHtLECj3F4TFP0sQAU9bCm4FC1Ahr0onD00LUDrHyh998ktQOsfKH33yS1AreBCqT\u002f5LUBOga54piAuQK\u002fhu45KOC5AzwFr6ytALkBQgidesV8uQLHiNHRVdy5AEkNCivmOLkAyY\u002fHm2pYuQJTD\u002fvx+ri5As+OtWWC2LkD0IwwTI8YuQPQjDBMjxi5AdaTIhajlLkAWRTRVDw0vQPgl\u002ft04RC9A8YSZi0EcMEBidf5P1jcwQOP1usJbVzBAlCZ+QLOCMEC2R6aCn8kwQBios5hD4TBAWOgRUgbxMEBoeGkA9\u002fQwQKm4x7m5BDFAOsnb2i8oMUBKWTOJICwxQF3qAx0cbzFA"},"yaxis":"y","type":"scatter"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"Fast Speed Rate"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"Barrel Rate"}},"legend":{"tracegroupgap":0},"title":{"text":"Swing Speed Rate vs Barrel Rate"}},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('53f365a7-c1e9-45b5-9971-979c43eb9b2b');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
</div>
<p>Observe that the relationship between fast swing rate and barrel rate is not a perfect linear relationship. In fact, there is a slight biphasic trend, where players with a fast swing rate less than 5% are clustered in low barrel rates, while players with a fast swing rate greater than 5% have a more linear relationship with barrel rate. This suggests that there may be a threshold effect, where players who swing fast enough can achieve higher barrel rates. An OLS regression line in red has an <img src="https://latex.codecogs.com/png.latex?R%5E2"> value of 0.48, indicating that the model explains 48% of the variance in barrel rate. The coefficient for fast swing rate is 0.153 which means for every one-unit increase in fast swing rate, barrel rate increases by 0.153 units.</p>
<section id="square-root-transformation" class="level2">
<h2 class="anchored" data-anchor-id="square-root-transformation">Square Root Transformation</h2>
<p>What if we applied a square root transformation to fast swing rate? This transformation can help capture non-linear relationships and improve the model’s performance. Let’s see how it looks.</p>
<div id="cell-scatter-plot-sqrt" class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sqrt_fast_swing_rate"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.sqrt(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fast_swing_rate"</span>])</span>
<span id="cb2-2"></span>
<span id="cb2-3">p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> px.scatter(</span>
<span id="cb2-4">    df, </span>
<span id="cb2-5">    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;">"sqrt_fast_swing_rate"</span>, </span>
<span id="cb2-6">    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;">"barrel_batted_rate"</span>, </span>
<span id="cb2-7">    trendline<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;">"ols"</span>, </span>
<span id="cb2-8">    trendline_color_override<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;">"red"</span>,</span>
<span id="cb2-9">    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;">"Swing Speed Rate vs Barrel Rate"</span>,</span>
<span id="cb2-10">    hover_data<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;">"last_name, first_name"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sqrt_fast_swing_rate"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel_batted_rate"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"year"</span>],</span>
<span id="cb2-11">)</span>
<span id="cb2-12">p.update_xaxes(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;">"Sqrt Fast Speed Rate"</span>)</span>
<span id="cb2-13">p.update_yaxes(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;">"Barrel Rate"</span>)</span></code></pre></div>
</details>
<div id="scatter-plot-sqrt" class="cell-output cell-output-display">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="794d60ff-d4e6-4302-b2ee-8bc202f57c8e" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("794d60ff-d4e6-4302-b2ee-8bc202f57c8e")) {                    Plotly.newPlot(                        "794d60ff-d4e6-4302-b2ee-8bc202f57c8e",                        [{"customdata":[["Yoshida, Masataka",2023],["Vaughn, Andrew",2023],["Rooker Jr., Brent",2023],["Rosario, Eddie",2023],["Davis, J.D.",2023],["Bell, Josh",2023],["Abreu, José",2023],["Friedl Jr., TJ",2023],["Canha, Mark",2023],["Freeman, Freddie",2023],["Happ, Ian",2023],["Ramírez, José",2023],["Nootbaar, Lars",2023],["Garcia, Maikel",2023],["Arraez, Luis",2023],["Alonso, Pete",2023],["Witt Jr., Bobby",2023],["Contreras, William",2023],["Hays, Austin",2023],["Lindor, Francisco",2023],["Soler, Jorge",2023],["Cronenworth, Jake",2023],["Thomas, Lane",2023],["Volpe, Anthony",2023],["Bichette, Bo",2023],["Díaz, Yandy",2023],["Castellanos, Nick",2023],["Turner, Justin",2023],["Meneses, Joey",2023],["Rutschman, Adley",2023],["Seager, Corey",2023],["Turner, Trea",2023],["Bogaerts, Xander",2023],["Drury, Brandon",2023],["Varsho, Daulton",2023],["Walker, Christian",2023],["Candelario, Jeimer",2023],["Reynolds, Bryan",2023],["Stephenson, Tyler",2023],["Tatis Jr., Fernando",2023],["Vierling, Matt",2023],["Suwinski, Jack",2023],["Merrifield, Whit",2023],["Edman, Tommy",2023],["Benintendi, Andrew",2023],["Ohtani, Shohei",2023],["Olson, Matt",2023],["France, Ty",2023],["McMahon, Ryan",2023],["Harper, Bryce",2023],["Arcia, Orlando",2023],["Taveras, Leody",2023],["Casas, Triston",2023],["Realmuto, J.T.",2023],["Adames, Willy",2023],["Chapman, Matt",2023],["Acuña Jr., Ronald",2023],["Betts, Mookie",2023],["Swanson, Dansby",2023],["Albies, Ozzie",2023],["Burger, Jake",2023],["Ozuna, Marcell",2023],["Robert Jr., Luis",2023],["Peña, Jeremy",2023],["Torres, Gleyber",2023],["Machado, Manny",2023],["Henderson, Gunnar",2023],["Outman, James",2023],["Tucker, Kyle",2023],["Jung, Josh",2023],["Anderson, Tim",2023],["Raleigh, Cal",2023],["Hernández, Enrique",2023],["Yelich, Christian",2023],["Goldschmidt, Paul",2023],["Renfroe, Hunter",2023],["Rosario, Amed",2023],["Suárez, Eugenio",2023],["LeMahieu, DJ",2023],["Springer III, George",2023],["Lowe, Nathaniel",2023],["Devers, Rafael",2023],["Bellinger, Cody",2023],["Melendez Jr., MJ",2023],["Gurriel Jr., Lourdes",2023],["Bohm, Alec",2023],["Smith, Dominic",2023],["Paredes, Isaac",2023],["Guerrero Jr., Vladimir",2023],["McNeil, Jeff",2023],["Abrams, CJ",2023],["Arozarena, Randy",2023],["Muncy, Max",2023],["Santander, Anthony",2023],["García, Adolis",2023],["Santana, Carlos",2023],["Steer, Spencer",2023],["Straw, Myles",2023],["Nimmo, Brandon",2023],["Stott, Bryson",2023],["Hoerner, Nico",2023],["Arenado, Nolan",2023],["Soto, Juan",2023],["Hernández, Teoscar",2023],["Carroll, Corbin",2023],["Hayes, Ke'Bryan",2023],["Báez, Javier",2023],["Crawford, J.P.",2023],["Bregman, Alex",2023],["Suzuki, Seiya",2023],["Kim, Ha-Seong",2023],["McKinstry, Zach",2023],["Semien, Marcus",2023],["Schwarber, Kyle",2023],["Profar, Jurickson",2023],["Estrada, Thairo",2023],["Marte, Ketel",2023],["India, Jonathan",2023],["Wade Jr., LaMonte",2023],["Torkelson, Spencer",2023],["Tovar, Ezequiel",2023],["Giménez, Andrés",2023],["Correa, Carlos",2023],["Smith, Will",2023],["Perez, Salvador",2023],["Harris II, Michael",2023],["Ruiz, Keibert",2023],["De La Cruz, Bryan",2023],["Kwan, Steven",2023],["Verdugo, Alex",2023],["Díaz, Elias",2023],["Rodríguez, Julio",2023],["Riley, Austin",2023],["Grisham, Trent",2023],["Bleday, JJ",2024],["Kwan, Steven",2024],["Torres, Gleyber",2024],["Naylor, Josh",2024],["Cowser, Colton",2024],["Rodríguez, Julio",2024],["Smith, Josh",2024],["Tovar, Ezequiel",2024],["Garcia, Maikel",2024],["Langeliers, Shea",2024],["Reynolds, Bryan",2024],["Castellanos, Nick",2024],["Busch, Michael",2024],["Hernández, Teoscar",2024],["Soto, Juan",2024],["McCutchen, Andrew",2024],["Sánchez, Jesús",2024],["Schwarber, Kyle",2024],["Carroll, Corbin",2024],["Cruz, Oneil",2024],["García, Luis",2024],["Volpe, Anthony",2024],["Machado, Manny",2024],["Burleson, Alec",2024],["Morel, Christopher",2024],["Ohtani, Shohei",2024],["Arraez, Luis",2024],["Abrams, CJ",2024],["Turang, Brice",2024],["Neto, Zach",2024],["Langford, Wyatt",2024],["Rutschman, Adley",2024],["Smith, Will",2024],["Donovan, Brendan",2024],["Judge, Aaron",2024],["Benintendi, Andrew",2024],["Chapman, Matt",2024],["Henderson, Gunnar",2024],["Young, Jacob",2024],["Betts, Mookie",2024],["Lindor, Francisco",2024],["Meyers, Jake",2024],["Seager, Corey",2024],["Olson, Matt",2024],["Suzuki, Seiya",2024],["De La Cruz, Bryan",2024],["Varsho, Daulton",2024],["Merrill, Jackson",2024],["Alvarez, Yordan",2024],["Ozuna, Marcell",2024],["Contreras, William",2024],["De La Cruz, Elly",2024],["Rafaela, Ceddanne",2024],["Walker, Christian",2024],["Castro, Willi",2024],["Perez, Salvador",2024],["Raleigh, Cal",2024],["Santander, Anthony",2024],["Ortiz, Joey",2024],["Rooker Jr., Brent",2024],["Devers, Rafael",2024],["Diaz, Yainer",2024],["Witt Jr., Bobby",2024],["Winn, Masyn",2024],["Díaz, Yandy",2024],["Cronenworth, Jake",2024],["Vaughn, Andrew",2024],["Chisholm Jr., Jazz",2024],["Duran, Jarren",2024],["Taveras, Leody",2024],["Steer, Spencer",2024],["Gurriel Jr., Lourdes",2024],["Hoerner, Nico",2024],["Frelick, Sal",2024],["Soler, Jorge",2024],["Suárez, Eugenio",2024],["Ramírez, José",2024],["Giménez, Andrés",2024],["India, Jonathan",2024],["Bohm, Alec",2024],["Doyle, Brenton",2024],["Peña, Jeremy",2024],["Schanuel, Nolan",2024],["Lowe, Nathaniel",2024],["Ramos, Heliot",2024],["Harper, Bryce",2024],["Arenado, Nolan",2024],["Stott, Bryson",2024],["Winker, Jesse",2024],["Thomas, Lane",2024],["Pasquantino, Vinnie",2024],["Hoskins, Rhys",2024],["Chourio, Jackson",2024],["Semien, Marcus",2024],["Rodgers, Brendan",2024],["Arozarena, Randy",2024],["Profar, Jurickson",2024],["Santana, Carlos",2024],["Marte, Ketel",2024],["Arcia, Orlando",2024],["Burger, Jake",2024],["García, Adolis",2024],["Vierling, Matt",2024],["Bregman, Alex",2024],["Paredes, Isaac",2024],["Stephenson, Tyler",2024],["Guerrero Jr., Vladimir",2024],["McMahon, Ryan",2024],["Greene, Riley",2024],["Verdugo, Alex",2024],["Goldschmidt, Paul",2024],["Turner, Justin",2024],["Keith, Colt",2024],["Freeman, Freddie",2024],["France, Ty",2024],["Adames, Willy",2024],["Mountcastle, Ryan",2024],["Nimmo, Brandon",2024],["O'Hoppe, Logan",2024],["Gelof, Zack",2024],["Bell, Josh",2024],["Ward, Taylor",2024],["Happ, Ian",2024],["Springer III, George",2024],["Bellinger, Cody",2024],["Turner, Trea",2024],["Alonso, Pete",2024],["Swanson, Dansby",2024],["Altuve, Jose",2024],["Robert Jr., Luis",2025],["Schanuel, Nolan",2025],["Steer, Spencer",2025],["Rice, Ben",2025],["Donovan, Brendan",2025],["Edwards, Xavier",2025],["Walker, Christian",2025],["Wagaman, Eric",2025],["Soderstrom, Tyler",2025],["Harper, Bryce",2025],["Soler, Jorge",2025],["Bichette, Bo",2025],["Buxton, Byron",2025],["Semien, Marcus",2025],["Meyers, Jake",2025],["Wood, James",2025],["Bellinger, Cody",2025],["Stott, Bryson",2025],["India, Jonathan",2025],["Contreras, Willson",2025],["Hoerner, Nico",2025],["Diaz, Yainer",2025],["Mullins II, Cedric",2025],["Ward, Taylor",2025],["Flores, Wilmer",2025],["O'Hearn, Ryan",2025],["Toglia, Michael",2025],["Torkelson, Spencer",2025],["Rengifo, Luis",2025],["Muncy, Max",2025],["Smith, Will",2025],["Hoskins, Rhys",2025],["Stowers, Kyle",2025],["Tatis Jr., Fernando",2025],["Goodman, Hunter",2025],["Adames, Willy",2025],["Langford, Wyatt",2025],["Rodríguez, Julio",2025],["Olson, Matt",2025],["Scott II, Victor",2025],["McCutchen, Andrew",2025],["Lowe, Nathaniel",2025],["Burleson, Alec",2025],["Wilson Jr., Jacob",2025],["Bell, Josh",2025],["Ramírez, José",2025],["Butler, Lawrence",2025],["Ramírez, Agustín",2025],["Holliday, Jackson",2025],["Clement, Ernie",2025],["Jung, Josh",2025],["Perez, Salvador",2025],["Garcia, Maikel",2025],["Schwarber, Kyle",2025],["McMahon, Ryan",2025],["Smith, Cam",2025],["Cruz, Oneil",2025],["Vargas, Miguel",2025],["Paredes, Isaac",2025],["Reynolds, Bryan",2025],["Naylor, Josh",2025],["Frelick, Sal",2025],["Crow-Armstrong, Pete",2025],["Suárez, Eugenio",2025],["Torres, Gleyber",2025],["Soto, Juan",2025],["Adell, Jo",2025],["Nimmo, Brandon",2025],["Guerrero Jr., Vladimir",2025],["Judge, Aaron",2025],["Duran, Jarren",2025],["Tucker, Kyle",2025],["Chourio, Jackson",2025],["Winn, Masyn",2025],["Lux, Gavin",2025],["Lindor, Francisco",2025],["Lee, Jung Hoo",2025],["Hernández, Teoscar",2025],["Swanson, Dansby",2025],["Turner, Trea",2025],["Perdomo, Geraldo",2025],["Bogaerts, Xander",2025],["Betts, Mookie",2025],["García, Adolis",2025],["Lowe, Brandon",2025],["Rooker Jr., Brent",2025],["Freeman, Freddie",2025],["Larnach, Trevor",2025],["Goldschmidt, Paul",2025],["McLain, Matt",2025],["Ozuna, Marcell",2025],["France, Ty",2025],["Bohm, Alec",2025],["Albies, Ozzie",2025],["Chapman, Matt",2025],["Grisham, Trent",2025],["Nootbaar, Lars",2025],["Happ, Ian",2025],["Arenado, Nolan",2025],["Aranda, Jonathan",2025],["Kirk, Alejandro",2025],["Devers, Rafael",2025],["Ohtani, Shohei",2025],["Crawford, J.P.",2025],["Springer III, George",2025],["Raleigh, Cal",2025],["Doyle, Brenton",2025],["Marte, Ketel",2025],["Realmuto, J.T.",2025],["McKinstry, Zach",2025],["Henderson, Gunnar",2025],["Correa, Carlos",2025],["Arraez, Luis",2025],["Santana, Carlos",2025],["Greene, Riley",2025],["Kwan, Steven",2025],["Caminero, Junior",2025],["Díaz, Yandy",2025],["Pasquantino, Vinnie",2025],["Smith, Josh",2025],["Domínguez, Jasson",2025],["Alonso, Pete",2025],["Turang, Brice",2025],["Machado, Manny",2025],["Peña, Jeremy",2025],["Beck, Jordan",2025],["Friedl Jr., TJ",2025],["Abreu, Wilyer",2025],["Gurriel Jr., Lourdes",2025],["Volpe, Anthony",2025],["Contreras, William",2025],["Busch, Michael",2025],["Ortiz, Joey",2025],["Yelich, Christian",2025],["Conforto, Michael",2025],["Sheets, Gavin",2025],["De La Cruz, Elly",2025],["Story, Trevor",2025],["Manzardo, Kyle",2025],["Castellanos, Nick",2025],["Yastrzemski, Mike",2025],["García, Luis",2025],["Carroll, Corbin",2025],["Arozarena, Randy",2025],["Riley, Austin",2025],["Pages, Andy",2025],["Ramos, Heliot",2025],["Kepler, Max",2025],["Lopez, Otto",2025],["Altuve, Jose",2025],["Witt Jr., Bobby",2025],["Rafaela, Ceddanne",2025],["Neto, Zach",2025],["Abrams, CJ",2025],["Hayes, Ke'Bryan",2025],["Harris II, Michael",2025],["Suzuki, Seiya",2025]],"hovertemplate":"sqrt_fast_swing_rate=%{x}\u003cbr\u003ebarrel_batted_rate=%{y}\u003cbr\u003elast_name, first_name=%{customdata[0]}\u003cbr\u003eyear=%{customdata[1]}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"","marker":{"color":"#636efa","symbol":"circle"},"mode":"markers","name":"","orientation":"v","showlegend":false,"x":{"dtype":"f8","bdata":"7T\u002f\u002f9XC1EUCBxAL\u002fmcwJQL6gMhjUJhdA+LJ6P+vFCkCWi1xRIkwRQMnFmH7okxVAgcQC\u002f5nMGUCWbWwTnVv+P0k\u002faBHq7v0\u002fG5IrB9gCC0DmMRnenJIRQPNZYUQr2AxAFgR3de4uE0Co9Jebd+MBQNntv8Uln9w\u002fST9oEeruHUCqnTms5k8dQCDEQGuQzRpAWmFMa3\u002fTDUDI57KMJqwOQETfy\u002f1nXh9AO6ElqiZlAEBbCeyzdYoQQDj9of4JIghAR2G8IFzmD0BL9fqexawZQBhD0vJyRxVAzTt\u002fZp6g5j8j0HAcGyELQFNb2jpYTAlAflYolSajEECAOUIu3MgUQMd6HsHLSg9AI1+GvNKWEEDhoNaVp3MbQPqxa7YCUBxAezkM6acDBUCsxnQvakoKQKzGdC9qSvo\u002fe2NYEqcEFkAD6UrIrWUMQJC+gbBY5hdAcoT4dPGG8T9HYbwgXOYPQLHlhT3kQ\u002fg\u002fLhr0Q28uIUCZ3X8CRzocQATxbY\u002fcqRFAXmjjiJg5E0DY4arvL6odQPdvKnWvBRJAyOeyjCasDkBE38v9Z14fQOkJSCQv1RdAhfPz92mtE0BXCWqnqB4eQDXXMQ7CviBARWwkLusyEkAAAAAAAAAIQC0n7peAaQpA+4EfzlYWIEC1ooU5tAkdQMq3ppHnpR9AAAAAAAAAEEBXm9zac+4SQBrgi0vzSCBAmJKAPFlHHkDXPH78qi8XQH7EIyxC+RJACOML5sAQDUCY+kuPwCv8P\u002fqxa7YCUBxAYBNCf3NZE0BNFiV+vSMZQJaLXFEiTBFAdGQjp\u002frTG0DHeh7By0oPQEgND1uf4xJAO6ElqiZlAECxt6LWL8ITQDfe1F1vVBlAKE2sMW5kF0A6BpxvcBQEQFstSqgJgRJAen1vfHgoAUCBlo2+TvoRQIUqLLU8RANA9lZqyevHAEDt3odZcO0cQIHEAv+ZzPk\u002fgZaNvk76EUDNO39mnqAWQDfbUdhi4Q5AZCSZEE18FkA0ZJCTrPIYQFphTGt\u002f0w1AtBY84TxdC0AAAAAAAADwP9pRFNaH3BRA+LJ6P+vF6j9TW9o6WEz5PxiXO784JhBAI1h3sj7FG0CXyf5svmEaQEbqiKyQzBVAzsCTFV9JEkD87mNpM9UaQC3PEwTbThNAp1ZUWfzCAkDK0Tj\u002fLzwWQJZtbBOdW\u002f4\u002fKuQZnKaA\u002fT\u002ftP\u002f\u002f1cLUBQHCjhztHQCFAgodmKYPMEUAI4wvmwBANQEMuY12jfhdAAAAAAAAAFEBSXuCWcHkUQAPpSsitZRxAWy1KqAmBEkCFKiy1PEQDQAXqhsZxrRxAqkxY6Hq2+z\u002fJxZh+6JMVQL6gMhjUJhdAseWFPeRD+D9U7Y0gk24TQNntv8Uln9w\u002f2il0lTw\u002f+z+SzZpalOgWQJQ13BVNqSBAGekozwwjIEAXgBQUOwwHQAy4NvaBPxBAD0lIYhM95D8AAAAAAAAIQH8Ukf2h3xZAXjZGh7x8GUCihoxzgtkfQNpRFNaH3ARAoa1ePcBjEUCsxnQvakoKQGQSJkpH7BlAWwnss3WKEEAO6KBxiBkTQIpHLeRy5ApASWiq42aFFkCpZzE10MYeQHBsF96gHhRAKuQZnKaAHUAE8W2P3KkhQCqSsm5TTBhAxHIByehaIUDdiihtzA4TQKlnMTXQxv4\u002fT1921qUCHUDZbN\u002fMdvgQQPuBH85WFiBAAAAAAAAAIEDZ7b\u002fFJZ\u002fcP\u002fXOGsoXjhNAKuQZnKaA\u002fT\u002fI57KMJqwOQCNYd7I+xRtAD0lIYhM9BECY+kuPwCv8P2PyT1RcdwVAlotcUSJMIUAAAAAAAADwP0sMWOEyAyBA6w32B\u002fgPIEBXm9zac+7yP0hyP\u002fR+yQhAVO2NIJNuE0BkJJkQTXwGQM7AkxVfSRJAtY7JGjziGEAtwpPREKoXQIKHZimDzBFA0nI8Oup1F0C2lS83H5cSQF91vH6\u002fvx9AUWaZy6kTGkAD6UrIrWUcQC4YeqDcXR1A2lEU1ofcBEAI4wvmwBAdQBJPjev7fg9Avg3lJxwVF0Cbyb871NwaQEDxq7BOQRdArbSIjFm7F0DCLXCDj2UYQPL7eGvQIBVAVO2NIJNuE0DOSbSmncwbQCPQcBwbIQtA0nI8Oup1F0A6BpxvcBQEQKpMWOh6tgtALc8TBNtOE0DwwusDCxEYQKlnMTXQxg5AKuQZnKaADUBZBvckXKgIQPiyej\u002frxfo\u002fU1vaOlhM+T8xJD012xceQDR4M7kXjBJAoa1ePcBjEUB7OQzppwMFQDn2EqLE2BJAF\u002fTqLSCiEkAxUpHOtcQGQH7EIyxC+RJAgcQC\u002f5nM+T8Syqmx26YVQJ3QQ3r7tx1AAP+fmcycGUDZ7b\u002fFJZ8MQCO3OkXyDfY\u002fJQvUjSnDBUBcu9q\u002fn3EQQIKHZimDzBFA81lhRCvYDECio7MN5VIXQDuhJaomZQBAOgacb3AUFEBdwKDS+R0XQN2KKG3MDhNAN8h9jECeEUBeNkaHvHwZQMaxDR7VZA1ATZTl0bdkG0AWBHd17i4TQFIDcWwcewtAzUFvoduYC0ByhPh08YYBQCMG0ZEMhwhAHl\u002fnTN1UHkCfTaDaboMUQDm4TPlrChtAj6U20q3oBUABlZejz7cTQNntv8Uln+w\u002fh6Wa8JRADkCJfGhUpWwJQIelmvCUQA5AF4AUFDsMF0BU8GSpFnQcQDKomG27mBdAuwMvUnGvEEC0FjzhPF0LQNpOT7He+w5A1zx+\u002fKovB0Bmp3hZGnkTQEgND1uf4xJAIw8olig+AkBbCeyzdYoQQPvLUHv0yRxA2e2\u002fxSWfDEDzWWFEK9gMQGAos4J4pR5Aj6U20q3oBUDG85KXeusDQIl8aFSlbBlAAAAAAAAAAEBj8k9UXHf1P3Q6HOyDXBlAdK5CkWQNFUC+wZ55DKAYQE2U5dG3ZBtA+P60UsSEGUBZBvckXKgIQLz9ULVV2xtAtpUvNx+XAkAXAE+e2WoCQFT6KLLHDCBAwi1wg49lCEDtP\u002f\u002f1cLUBQDn2EqLE2BJAfRrGBsfsH0CWbWwTnVv+P+Ec6aob1BBANG\u002f9k3KICkDaURTWh9wEQJZtbBOdW+4\u002flotcUSJMEUCFKiy1PEQTQAAAAAAAABRAwi1wg49lCECB7X6u7mQPQFTtjSCTbgNAWfNtKtayD0C1ooU5tAkdQAD\u002fn5nMnBlANzynurS8GUAE8W2P3KkRQJh\u002fPJNWAxdAJzuaItOyHkBeNkaHvHwZQKdWVFn8wgJAikct5HLkCkBmAu3uv\u002fUTQF4swaMQURVA2e2\u002fxSWf3D+MxdvdBPIVQOkXAuuDBBFAHvAHDUELGUDt3odZcO0cQB7wBw1BCwlA1zx+\u002fKov9z8XAE+e2WoCQHDg1Xu8KRZAG9XPGWHsEECEVP7RF08hQJsMM3513BlAvP1QtVXbG0DzVDy3YXUhQM1Bb6HbmAtAcYIfruErCUANFQfL\u002fqITQO3K+rCEHBFAxvOSl3rrA0BLCJplL0cUQGYC7e6\u002f9RNAdGQjp\u002frTC0A6F2\u002fK\u002f9kYQNls38x2+CBAWy1KqAmBEkBxYcxJ4jIgQKVjgUIm1yBAikct5HLkGkAuIQkUjpgTQDc8p7q0vBlA6RcC64MEEUC2lS83H5cCQJZtbBOdWw5AcWHMSeIyAEB3Lw6NL3MWQA7ooHGIGQNAVcv8lKPMD0DZbN\u002fMdvgAQLG3otYvwhNAVO2NIJNuA0DaURTWh9wUQDFSkc61xBZA8D1EsnXqGEB7OQzppwMFQApJCXE+JBNAehywT\u002fIyFEA7oSWqJmUAQEhyP\u002fR+yRhAmPpLj8ArDEA7oSWqJmUQQDoGnG9wFARAZN0nlq74G0Aj0HAcGyELQHRNUHaQnxpA+U1kNINvEUDbr6wHs7sQQNpOT7He+w5AiIB21VyXFEAE8W2P3KkRQF5UvXxLuR9AcoT4dPGGEUBDLmNdo34XQDTSLTPpSB1AcoT4dPGGAUAXgymCjRkbQDJCiVQOahZAAAAAAAAA8D8q5BmcpoAdQBs53SwiPBlAcoT4dPGG4T\u002fpFwLrgwQRQMaxDR7VZB1A9lZqyevH8D8zXl07UHghQMItcIOPZRhAORuO8Vf7FUBxYcxJ4jIAQNc8fvyqLxdAOFaS3XuFH0A00i0z6UgNQPzuY2kz1RpA4RzpqhvUEEBIcj\u002f0fskYQFNb2jpYTPk\u002fCnouMG0TGUAe8AcNQQsJQHocsE\u002fyMhRAjMXb3QTyFUDXPH78qi8HQKPf4Vv\u002fvhRAoqOzDeVSF0C+wZ55DKAYQCDOGJl2XhxAqAv3nKYoG0CqTFjoerYLQB7wBw1BCwlAB+2vZg9+EEA4\u002faH+CSIIQFqdKgCqWhVAietawL9GG0Di36q6HBcVQDfbUdhi4R5ADuigcYgZE0DmCHSSLPQZQEUXFs\u002f9wBFA3YoobcwOE0CttIiMWbsHQHRkI6f60xtAtBY84TxdC0BwxJ05jXYOQPQNMSbMKBRAI9BwHBshC0DXPH78qi8XQL7BnnkMoBhA"},"xaxis":"x","y":{"dtype":"f8","bdata":"ZmZmZmZmGkDNzMzMzMwgQDMzMzMzMy9AAAAAAAAAI0AzMzMzMzMjQDMzMzMzMyRAZmZmZmZmIUCamZmZmZkJQM3MzMzMzBJAMzMzMzMzJkAAAAAAAAAiQAAAAAAAABxAmpmZmZmZIUAzMzMzMzMPQAAAAAAAAAxAZmZmZmZmLUAAAAAAAAAnQM3MzMzMzCJAzczMzMzMIUDNzMzMzMwkQAAAAAAAAC5AmpmZmZmZEUAzMzMzMzMjQAAAAAAAACJAMzMzMzMzI0AAAAAAAAAjQJqZmZmZmSRAzczMzMzMFkCamZmZmZkVQAAAAAAAAB5AZmZmZmZmLkDNzMzMzMwgQGZmZmZmZhhAAAAAAAAAJkAzMzMzMzMdQM3MzMzMzCZAmpmZmZmZH0AzMzMzMzMmQGZmZmZmZh5AAAAAAAAAJkBmZmZmZmYSQGZmZmZmZi9AMzMzMzMzA0AAAAAAAAAUQDMzMzMzMwdAmpmZmZmZM0BmZmZmZmYwQDMzMzMzMxtAzczMzMzMJkBmZmZmZmYuQJqZmZmZmRtAzczMzMzMHEAzMzMzMzMqQGZmZmZmZiZAzczMzMzMKECamZmZmRkxQJqZmZmZmS5AzczMzMzMKEDNzMzMzMwlQGZmZmZmZiBAMzMzMzOzMECamZmZmZkwQM3MzMzMzC5AAAAAAAAAEECamZmZmZkfQAAAAAAAACVAzczMzMzMJkAzMzMzMzMmQDMzMzMzMyVAzczMzMzMJ0AzMzMzMzMHQDMzMzMzMylAAAAAAAAAEkBmZmZmZmYiQAAAAAAAAChAZmZmZmZmGEAzMzMzMzMLQGZmZmZmZipAmpmZmZmZF0DNzMzMzMweQAAAAAAAABpAZmZmZmZmKUBmZmZmZmYYQM3MzMzMzCZAzczMzMzMIEDNzMzMzMwWQGZmZmZmZhpAmpmZmZmZF0AzMzMzMzMmQM3MzMzMzPQ\u002fmpmZmZmZG0CamZmZmZkoQDMzMzMzMy1AZmZmZmZmJECamZmZmRkwQM3MzMzMzBpAzczMzMzMGkAAAAAAAADgPwAAAAAAACNAzczMzMzMEkDNzMzMzMz8PzMzMzMzMx1AAAAAAAAAKkCamZmZmZkrQGZmZmZmZh5AmpmZmZmZHUDNzMzMzMwUQDMzMzMzMxNAmpmZmZmZFUAAAAAAAAAlQM3MzMzMzBBAZmZmZmZmHkAAAAAAAAAaQGZmZmZmZjBAAAAAAAAAEEAzMzMzMzMTQAAAAAAAACBAzczMzMzMHkAzMzMzMzMiQDMzMzMzMyxAMzMzMzMzIEAAAAAAAAAWQDMzMzMzMyNAzczMzMzMGkCamZmZmZkhQAAAAAAAACRAMzMzMzMzF0CamZmZmZkhQJqZmZmZmfE\u002fAAAAAAAAFEDNzMzMzMwYQM3MzMzMzCdAzczMzMzMK0DNzMzMzMwnQJqZmZmZmSBAzczMzMzMBEAzMzMzMzMZQM3MzMzMzCBAMzMzMzMzK0BmZmZmZmYkQJqZmZmZmQ1AAAAAAAAAIkCamZmZmZkNQJqZmZmZmSlAMzMzMzMzI0AzMzMzMzMgQGZmZmZmZiZAzczMzMzMLUAzMzMzM7MzQAAAAAAAAChAZmZmZmZmKEAzMzMzMzMvQM3MzMzMzBxAZmZmZmZmL0AAAAAAAAAgQDMzMzMzMw9AAAAAAAAAJkAAAAAAAAAaQGZmZmZmZiRAAAAAAACANUCamZmZmZn5P5qZmZmZmRtAMzMzMzMzA0DNzMzMzMwgQJqZmZmZmSJAZmZmZmZmGECamZmZmZklQAAAAAAAABZAZmZmZmbmOkAzMzMzMzMZQDMzMzMzMylAZmZmZmZmJkCamZmZmZn5PwAAAAAAABhAMzMzMzMzK0AzMzMzMzMbQGZmZmZmZi5AzczMzMzMKEAAAAAAAAAnQJqZmZmZmSJAzczMzMzMGECamZmZmZkmQAAAAAAAAC1AAAAAAAAAL0AAAAAAAAAkQGZmZmZmZilAAAAAAAAAHkCamZmZmZkqQAAAAAAAABxAZmZmZmZmKEDNzMzMzMwuQGZmZmZmZidAZmZmZmZmEkCamZmZmZkwQAAAAAAAACpAZmZmZmZmHkCamZmZmZksQJqZmZmZmQ1AZmZmZmZmHkAzMzMzMzMfQJqZmZmZmSJAZmZmZmZmI0CamZmZmZkiQJqZmZmZmRdAmpmZmZmZGUDNzMzMzMwaQDMzMzMzM\u002fM\u002fmpmZmZmZ6T8zMzMzMzMpQJqZmZmZmSZAMzMzMzMzIUBmZmZmZmYGQM3MzMzMzB5AMzMzMzMzG0AAAAAAAAAlQJqZmZmZmRVAAAAAAAAADEAzMzMzMzMXQAAAAAAAAC1AMzMzMzMzJUCamZmZmZkJQM3MzMzMzAxAZmZmZmZmHkCamZmZmZkdQGZmZmZmZhxAZmZmZmZmKUAzMzMzMzMfQGZmZmZmZhpAZmZmZmZmFkCamZmZmZkgQM3MzMzMzBxAMzMzMzMzHUCamZmZmZkoQDMzMzMzMxVAmpmZmZmZKEAAAAAAAAApQAAAAAAAAB5AmpmZmZmZGUAAAAAAAAASQDMzMzMzMyJAZmZmZmZmK0DNzMzMzMwlQM3MzMzMzCpAZmZmZmZmFkBmZmZmZmYlQGZmZmZmZhJAZmZmZmZmFkAzMzMzMzMiQDMzMzMzMx1AAAAAAAAAKECamZmZmZkhQDMzMzMzMyJAAAAAAAAAKECamZmZmZkhQGZmZmZmZh5AAAAAAAAAKkBmZmZmZmYnQJqZmZmZmSJAMzMzMzMzGUCamZmZmZkbQGZmZmZmZipAZmZmZmZmIkAAAAAAAAAaQM3MzMzMzCZAmpmZmZmZFUAAAAAAAAAWQJqZmZmZmS9AZmZmZmZmIkBmZmZmZmbmPwAAAAAAACdAMzMzMzMzF0DNzMzMzMwoQAAAAAAAACdAmpmZmZmZJ0DNzMzMzMwjQDMzMzMzMy9AmpmZmZmZH0BmZmZmZmYUQAAAAAAAgDJAmpmZmZmZIEBmZmZmZmYUQGZmZmZmZhhAMzMzMzMzK0AAAAAAAAAEQGZmZmZmZiJAmpmZmZmZGUAzMzMzMzMqQAAAAAAAABBAAAAAAAAAIkBmZmZmZmYlQJqZmZmZmS5AMzMzMzMzEUAzMzMzMzMsQJqZmZmZmStAAAAAAAAAJUBmZmZmZmYyQGZmZmZmZidAMzMzMzMzKUDNzMzMzMwpQDMzMzMzMylAzczMzMzMHkAAAAAAAIAwQGZmZmZmZhJAZmZmZmZmI0BmZmZmZmYcQGZmZmZmZiJAZmZmZmZmAkDNzMzMzMwkQJqZmZmZmR9AMzMzMzMzIkBmZmZmZmYoQGZmZmZmZiVAzczMzMzM\u002fD+amZmZmZkgQJqZmZmZmSxAAAAAAAAAGECamZmZmRkyQDMzMzMzMyhAmpmZmZmZHUDNzMzMzEw2QM3MzMzMzCFAZmZmZmZmGEBmZmZmZmYmQJqZmZmZmRlAAAAAAAAACEAzMzMzMzMsQM3MzMzMzCtAmpmZmZmZI0AAAAAAAAAyQM3MzMzMzC9AzczMzMzMI0DNzMzMzMwqQGZmZmZmZjpAmpmZmZmZI0BmZmZmZmYpQAAAAAAAABxAzczMzMzMFkDNzMzMzMwMQJqZmZmZmSFAMzMzMzMzEUDNzMzMzMwnQAAAAAAAACZAZmZmZmZmGkBmZmZmZmYYQGZmZmZmZhRAMzMzMzMzF0DNzMzMzMwqQJqZmZmZmSpAmpmZmZmZLECamZmZmZkiQDMzMzMzMyBAMzMzMzMzIECamZmZmZkbQDMzMzMzMyZAZmZmZmZmIUAAAAAAAAAaQJqZmZmZmQ1AZmZmZmZmJEBmZmZmZmYsQM3MzMzMzCRAzczMzMzMIUDNzMzMzMwQQDMzMzMzMyhAmpmZmZmZIkAzMzMzMzMuQAAAAAAAgDVAmpmZmZmZFUDNzMzMzMwuQDMzMzMzMzRAmpmZmZmZJ0DNzMzMzMwvQDMzMzMzMx9AMzMzMzMzG0AzMzMzMzMhQJqZmZmZmRdAmpmZmZmZ6T9mZmZmZmYYQM3MzMzMTDJAzczMzMzMAEAAAAAAAAAmQGZmZmZmZiRAZmZmZmZmIUAzMzMzMzMVQDMzMzMzMyBAAAAAAACANEDNzMzMzMwWQGZmZmZmZitAmpmZmZmZH0AAAAAAAAAnQM3MzMzMzAhAzczMzMzMKECamZmZmZkbQAAAAAAAACNAZmZmZmZmEkAAAAAAAAAvQJqZmZmZmQ1AmpmZmZmZIUAAAAAAAAAjQJqZmZmZmSRAMzMzMzMzKkCamZmZmZkkQAAAAAAAACdAAAAAAAAAI0CamZmZmZkfQM3MzMzMzCFAzczMzMzMLkCamZmZmZknQAAAAAAAAC5AMzMzMzMzIEBmZmZmZmYlQM3MzMzMzCZAzczMzMzMHkBmZmZmZmYYQAAAAAAAACtAAAAAAAAAKkBmZmZmZmYtQGZmZmZmZhpAZmZmZmZmFkDNzMzMzMwYQM3MzMzMzDJA"},"yaxis":"y","type":"scatter"},{"hovertemplate":"\u003cb\u003eOLS trendline\u003c\u002fb\u003e\u003cbr\u003ebarrel_batted_rate = 1.50057 * sqrt_fast_swing_rate + 2.38301\u003cbr\u003eR\u003csup\u003e2\u003c\u002fsup\u003e=0.490152\u003cbr\u003e\u003cbr\u003esqrt_fast_swing_rate=%{x}\u003cbr\u003ebarrel_batted_rate=%{y} \u003cb\u003e(trend)\u003c\u002fb\u003e\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"","line":{"color":"red"},"marker":{"color":"#636efa","symbol":"circle"},"mode":"lines","name":"","showlegend":false,"x":{"dtype":"f8","bdata":"2e2\u002fxSWf3D\u002fZ7b\u002fFJZ\u002fcP9ntv8Uln9w\u002f2e2\u002fxSWf3D9yhPh08YbhPw9JSGITPeQ\u002fzTt\u002fZp6g5j\u002f4sno\u002f68XqP9ntv8Uln+w\u002flm1sE51b7j8AAAAAAADwPwAAAAAAAPA\u002fAAAAAAAA8D\u002f2VmrJ68fwP3KE+HTxhvE\u002fV5vc2nPu8j9j8k9UXHf1PyO3OkXyDfY\u002f1zx+\u002fKov9z+x5YU95EP4P7HlhT3kQ\u002fg\u002fU1vaOlhM+T9TW9o6WEz5P1Nb2jpYTPk\u002fgcQC\u002f5nM+T+BxAL\u002fmcz5P6zGdC9qSvo\u002f+LJ6P+vF+j\u002faKXSVPD\u002f7P6pMWOh6tvs\u002fmPpLj8Ar\u002fD+Y+kuPwCv8PyrkGZymgP0\u002fKuQZnKaA\u002fT9JP2gR6u79P5ZtbBOdW\u002f4\u002flm1sE51b\u002fj+WbWwTnVv+P6lnMTXQxv4\u002fAAAAAAAAAEBxYcxJ4jIAQHFhzEniMgBAO6ElqiZlAEA7oSWqJmUAQDuhJaomZQBAO6ElqiZlAED2VmrJ68cAQNls38x2+ABAen1vfHgoAUByhPh08YYBQHKE+HTxhgFA7T\u002f\u002f9XC1AUDtP\u002f\u002f1cLUBQKj0l5t34wFAIw8olig+AkAXAE+e2WoCQBcAT57ZagJAtpUvNx+XAkC2lS83H5cCQKdWVFn8wgJAp1ZUWfzCAkAO6KBxiBkDQIUqLLU8RANAhSostTxEA0BU7Y0gk24DQFTtjSCTbgNAxvOSl3rrA0DG85KXeusDQDoGnG9wFARAOgacb3AUBEA6BpxvcBQEQA9JSGITPQRA2lEU1ofcBEDaURTWh9wEQNpRFNaH3ARAezkM6acDBUB7OQzppwMFQHs5DOmnAwVAY\u002fJPVFx3BUAlC9SNKcMFQI+lNtKt6AVAj6U20q3oBUBkJJkQTXwGQDFSkc61xAZAF4AUFDsMB0DXPH78qi8HQNc8fvyqLwdArbSIjFm7B0AAAAAAAAAIQAAAAAAAAAhAOP2h\u002fgkiCEA4\u002faH+CSIIQMItcIOPZQhAwi1wg49lCEAjBtGRDIcIQFkG9yRcqAhAWQb3JFyoCEBIcj\u002f0fskIQB7wBw1BCwlAHvAHDUELCUAe8AcNQQsJQHGCH67hKwlAU1vaOlhMCUCJfGhUpWwJQIHEAv+ZzAlArMZ0L2pKCkCsxnQvakoKQC0n7peAaQpANG\u002f9k3KICkD4sno\u002f68UKQIpHLeRy5ApAikct5HLkCkAbkisH2AILQCPQcBwbIQtAI9BwHBshC0Aj0HAcGyELQCPQcBwbIQtAtBY84TxdC0C0FjzhPF0LQLQWPOE8XQtAUgNxbBx7C0DNQW+h25gLQM1Bb6HbmAtAqkxY6Hq2C0CqTFjoerYLQHRkI6f60wtAmPpLj8ArDEAD6UrIrWUMQNntv8UlnwxA2e2\u002fxSWfDEDzWWFEK9gMQPNZYUQr2AxA81lhRCvYDEAI4wvmwBANQAjjC+bAEA1ANNItM+lIDUDGsQ0e1WQNQCrkGZymgA1AWmFMa3\u002fTDUBaYUxrf9MNQIelmvCUQA5Ah6Wa8JRADkCWbWwTnVsOQHDEnTmNdg5AyOeyjCasDkDI57KMJqwOQMjnsowmrA5AqWcxNdDGDkA321HYYuEOQNpOT7He+w5A2k5Psd77DkDHeh7By0oPQMd6HsHLSg9Age1+ru5kD0AST43r+34PQFnzbSrWsg9AVcv8lKPMD0BHYbwgXOYPQEdhvCBc5g9AAAAAAAAAEEAYlzu\u002fOCYQQAy4NvaBPxBAO6ElqiZlEEBcu9q\u002fn3EQQAftr2YPfhBAWwnss3WKEEBbCeyzdYoQQFsJ7LN1ihBAI1+GvNKWEEB+ViiVJqMQQLsDL1JxrxBA26+sB7O7EEDhHOmqG9QQQOEc6aob1BBAG9XPGWHsEEDZbN\u002fMdvgQQOkXAuuDBBFA6RcC64MEEUDpFwLrgwQRQO3K+rCEHBFAlotcUSJMEUCWi1xRIkwRQJaLXFEiTBFAoa1ePcBjEUChrV49wGMRQPlNZDSDbxFAcoT4dPGGEUDmMRnenJIRQDfIfYxAnhFABPFtj9ypEUAE8W2P3KkRQATxbY\u002fcqRFA7T\u002f\u002f9XC1EUBFFxbP\u002fcARQIKHZimDzBFAgodmKYPMEUCCh2Ypg8wRQIGWjb5O+hFAgZaNvk76EUD3byp1rwUSQEVsJC7rMhJAzsCTFV9JEkDOwJMVX0kSQFstSqgJgRJAWy1KqAmBEkBbLUqoCYESQDR4M7kXjBJAtpUvNx+XEkAX9OotIKISQDn2EqLE2BJAOfYSosTYEkBIDQ9bn+MSQEgND1uf4xJAV5vc2nPuEkB+xCMsQvkSQH7EIyxC+RJA3YoobcwOE0DdiihtzA4TQN2KKG3MDhNADuigcYgZE0AO6KBxiBkTQApJCXE+JBNAFgR3de4uE0AWBHd17i4TQF5o44iYORNAhSostTxEE0AtzxME204TQC3PEwTbThNAYBNCf3NZE0BU7Y0gk24TQFTtjSCTbhNAVO2NIJNuE0Bmp3hZGnkTQPXOGsoXjhNALiEJFI6YE0ANFQfL\u002fqITQIXz8\u002fdprRNAAZWXo8+3E0Cxt6LWL8ITQLG3otYvwhNAZgLt7r\u002f1E0BmAu3uv\u002fUTQAAAAAAAABRAAAAAAAAAFEA6BpxvcBQUQHBsF96gHhRA9A0xJswoFEB6HLBP8jIUQHocsE\u002fyMhRASwiaZS9HFEBSXuCWcHkUQJ9NoNpugxRAiIB21VyXFECj3+Fb\u002f74UQIA5Qi7cyBRA2lEU1ofcFEDaURTWh9wUQHSuQpFkDRVA4t+quhwXFUDy+3hr0CAVQBhD0vJyRxVAXizBoxBRFUBanSoAqloVQMnFmH7okxVAycWYfuiTFUASyqmx26YVQEbqiKyQzBVAjMXb3QTyFUCMxdvdBPIVQDkbjvFX+xVAe2NYEqcEFkBw4NV7vCkWQMrROP8vPBZAMkKJVA5qFkB3Lw6NL3MWQGQkmRBNfBZASWiq42aFFkDNO39mnqAWQDFSkc61xBZAfxSR\u002faHfFkCSzZpalOgWQJh\u002fPJNWAxdAF4AUFDsMF0C+DeUnHBUXQF3AoNL5HRdAvqAyGNQmF0C+oDIY1CYXQNc8fvyqLxdA1zx+\u002fKovF0DXPH78qi8XQEDxq7BOQRdAoqOzDeVSF0Cio7MN5VIXQChNrDFuZBdA0nI8Oup1F0DScjw66nUXQEMuY12jfhdAQy5jXaN+F0AyqJhtu5gXQC3Ck9EQqhdArbSIjFm7F0DpCUgkL9UXQJC+gbBY5hdA8MLrAwsRGEAqkrJuU0wYQMItcIOPZRhAwi1wg49lGEC+wZ55DKAYQL7BnnkMoBhAvsGeeQygGEBIcj\u002f0fskYQEhyP\u002fR+yRhAOhdvyv\u002fZGEC1jskaPOIYQPA9RLJ16hhANGSQk6zyGEAe8AcNQQsZQAp6LjBtExlATRYlfr0jGUAbOd0sIjwZQDfe1F1vVBlAdDoc7INcGUCJfGhUpWwZQF42Roe8fBlAXjZGh7x8GUBeNkaHvHwZQPj+tFLEhBlAAP+fmcycGUAA\u002f5+ZzJwZQEv1+p7FrBlANzynurS8GUA3PKe6tLwZQIHEAv+ZzBlAmwwzfnXcGUBkEiZKR+wZQOYIdJIs9BlAUWaZy6kTGkCXyf5svmEaQHRNUHaQnxpAIMRAa5DNGkD87mNpM9UaQPzuY2kz1RpAm8m\u002fO9TcGkCKRy3kcuQaQDm4TPlrChtAF4Mpgo0ZG0CoC\u002fecpigbQInrWsC\u002fRhtATZTl0bdkG0BNlOXRt2QbQOGg1pWncxtAI1h3sj7FG0AjWHeyPsUbQM5JtKadzBtAdGQjp\u002frTG0B0ZCOn+tMbQLz9ULVV2xtAvP1QtVXbG0Bk3SeWrvgbQJndfwJHOhxA+rFrtgJQHED6sWu2AlAcQCDOGJl2XhxAA+lKyK1lHEAD6UrIrWUcQFTwZKkWdBxABeqGxnGtHED7y1B79MkcQO3eh1lw7RxA7d6HWXDtHEBPX3bWpQIdQLWihTm0CR1AtaKFObQJHUAI4wvmwBAdQDTSLTPpSB1Aqp05rOZPHUAuGHqg3F0dQMaxDR7VZB1AKuQZnKaAHUAq5BmcpoAdQNjhqu8vqh1AndBDevu3HUBJP2gR6u4dQDEkPTXbFx5AVwlqp6geHkCYkoA8WUceQB5f50zdVB5AYCizgnilHkAnO5oi07IeQKlnMTXQxh5AN9tR2GLhHkBE38v9Z14fQETfy\u002f1nXh9AOFaS3XuFH0DKt6aR56UfQF5UvXxLuR9AX3W8fr+\u002fH0CihoxzgtkfQH0axgbH7B9AAAAAAAAAIEBLDFjhMgMgQFT6KLLHDCBA6w32B\u002fgPIED7gR\u002fOVhYgQPuBH85WFiBAGekozwwjIEBxYcxJ4jIgQBrgi0vzSCBAlDXcFU2pIEA11zEOwr4gQKVjgUIm1yBA2WzfzHb4IEAuGvRDby4hQHCjhztHQCFAlotcUSJMIUCEVP7RF08hQMRyAcnoWiFA81Q8t2F1IUAzXl07UHghQATxbY\u002fcqSFA"},"xaxis":"x","y":{"dtype":"f8","bdata":"AyhJesNuCEADKEl6w24IQAMoSXrDbghAAyhJesNuCECLeSzzpKMJQN0levgKqApABHvNY3WNC0C4my\u002fjmBsNQLRBzBQgzQ1AozHUBN1zDkC1oshvkREPQLWiyG+REQ9AtaLIb5ERD0CaVWfZkKcPQGJySYNxGxBAmje\u002fg0+iEECyradXvpURQOS5+Q48zhFAQA3T4us6EkASMmZsi6ISQBIyZmyLohJAmCTEjsAFE0CYJMSOwAUTQJgkxI7ABRNACvH45N01E0AK8fjk3TUTQP6n\u002fIwQZRNAj5RMc2WTE0CSiXFf6MATQJ4cFBek7RNAeOPXe6IZFEB449d7ohkUQAGZQS2FmRRAAZlBLYWZFEAKaAN+4sIUQHoq8ZSp6xRAeirxlKnrFEB6KvGUqesUQHihyangExVAjJvl\u002f12JFUDsf79si68VQOx\u002fv2yLrxVAwGEAX0LVFUDAYQBfQtUVQMBhAF9C1RVAwGEAX0LVFUByToRpXR8WQDMq7jXJQxZAcLNp+c1nFkCa3a+Wr64WQJrdr5avrhZAXTAem5LRFkBdMB6bktEWQGPHKvIa9BZAal1nSiY4F0B0CnhSrlkXQHQKeFKuWRdAhTM\u002fv+V6F0CFMz+\u002f5XoXQGwtXMvOmxdAbC1cy86bF0Da2ZEsvtwXQPgSGHzI\u002fBdA+BIYfMj8F0CqBahijBwYQKoFqGKMHBhAkAqnFkN6GECQCqcWQ3oYQEJbAXX+mBhAQlsBdf6YGEBCWwF1\u002fpgYQEA2S6F7txhAWFuYlx4vGUBYW5iXHi8ZQFhbmJceLxlAU9Hnf3lMGUBT0ed\u002feUwZQFPR5395TBlAPFRsP0mjGUBI+QexKNwZQDgTY6BO+BlAOBNjoE74GUBAjdPREGcaQCM8eKdknRpANIgw0g3TGkBYE8NVpO0aQFgTw1Wk7RpAkWFHcHFWG0C95eZH84kbQL3l5kfziRtAoekMQn2jG0Ch6QxCfaMbQBcUnlEm1htAFxSeUSbWG0ATTU2NRu8bQGuzP6lECBxAa7M\u002fqUQIHECklwgvISEcQBThrYx3UhxAFOGtjHdSHEAU4a2Md1IcQBbyVGbyahxABkKlrU2DHEAAko7biZscQOzaDlqI4xxA1EgWqu1BHUDUSBaq7UEdQLl5irxAWR1ANW0He3hwHUD1IbZ2l54dQJc27Wt\u002ftR1Alzbta3+1HUBmLVl9TcwdQLbo\u002fgEC4x1Atuj+AQLjHUC26P4BAuMdQLbo\u002fgEC4x1Aioiptx8QHkCKiKm3HxAeQIqIqbcfEB5AcJuBjYkmHkD0QlUg2zweQPRCVSDbPB5AEzJFvhRTHkATMkW+FFMeQOhH0rM2aR5Ax7\u002fMhxGrHkB7mHerh9YeQOxt79mlAR9A7G3v2aUBH0AjEPAgbiwfQCMQ8CBuLB9AIxDwIG4sH0DKJRB64lYfQMolEHriVh9Ah6nRywSBH0CA1\u002f7E95UfQNkqoOrWqh9Absj1j\u002f\u002foH0BuyPWP\u002f+gfQNSQu9NrHSBA1JC702sdIEDmpv\u002fcjycgQPrFp+aqMSBAOL\u002fkWcZFIEA4v+RZxkUgQDi\u002f5FnGRSBA4x3Y8cZPIEBZbvHmvlkgQOL9aE+uYyBA4v1oT65jIEC4grkVSoEgQLiCuRVKgSBAl4+YIhiLIEBweo4M3pQgQOB77MdRqCBApBufwP+xIEDOSQHlpbsgQM5JAeWluyBA+Bf0R0TFIEDit5mg8eEgQKFHrWHq9CBAK94OpygRIUDXKRZghBohQDiBRQXZIyFAro+TpiYtIUCuj5OmJi0hQK6Pk6YmLSFAile7U202IUByaD0crT8hQJwNYQ\u002fmSCFAVHQ1PBhSIUALWBt+aGQhQAtYG35oZCFAkAgwVp52IUCepvx9r38hQDFwdzW6iCFAMXB3NbqIIUAxcHc1uoghQIBo2Im8miFAbBamOna+IUBsFqY6dr4hQGwWpjp2viFAuIxZZC7QIUC4jFlkLtAhQFbaFnkB2SFABlq+3pXqIUCyalhHV\u002fMhQIIuVeMS\u002fCFAzoErvsgEIkDOgSu+yAQiQM6BK77IBCJAyKws43gNIkASD4VdIxYiQGLHPDjIHiJAYsc8OMgeIkBixzw4yB4iQDr8pT4kQSJAOvylPiRBIkC8UOubrUkiQPNDtrKdayJAlZBCQ3Z8IkCVkEJDdnwiQKZWCUA6piJAplYJQDqmIkCmVglAOqYiQCLKAZuFriJA8K9NB8y2IkCONK+NDb8iQHb6b+AM6CJAdvpv4AzoIkBYc7i1MfAiQFhzuLUx8CJAduSp31H4IkC6L0NmbQAjQLovQ2ZtACNAPJ\u002f3qJYQI0A8n\u002feolhAjQDyf96iWECNARlagdKQYI0BGVqB0pBgjQLC7DLytICNAVozNhrIoI0BWjM2GsigjQLV9XtyyMCNAZI8mxK44I0D4WnhFpkAjQPhaeEWmQCNAZmKSZ5lII0AWgraqclgjQBaCtqpyWCNAFoK2qnJYI0Bq1NvZWGAjQDmwAnYYcCNAJLmu8PF3I0BieL48x38jQDoK2mCYhyNA1fSXY2WPI0AAaX1LLpcjQABpfUsulyNAmv7gH969I0Ca\u002fuAf3r0jQBC99OuOxSNAEL30647FI0Cu1w+95NQjQJgjDs6J3CNAxALjASvkI0Cga2ReyOsjQKBrZF7I6yNAqr17qPf6I0DDBjM3rCAkQBKafKQrKCRAHgGBlB83JEAgTelc3FQkQMQju7JCXCRAw9em3wRrJEDD16bfBGskQOyF0PutjyRAOCk80PiWJEALzuBJQJ4kQEOZUgA9uyRAXlR1+HPCJEAUKOOwp8kkQNb05Lua9CRA1vTku5r0JEAE382D0gIlQI5ak\u002f8cHyVAbrF23zY7JUBusXbfNjslQLytO9w1QiVATPCI4jFJJUB2oaOlBGUlQCRYe6DcciVA0HlhuEaVJUDmFCJNIJwlQKwJ4hn3oiVAnOEBIsupJUD4XADANr4lQI64hu9K2SVAoscnCX7tJUD8neF1NPQlQJIarRNICCZAoAQ\u002fGvQOJkAKa8uOnRUmQFiJSHREHCZAPO+mzegiJkA876bN6CImQMSP0Z2KKSZAxI\u002fRnYopJkDEj9GdiikmQBKXG67GNiZApi0QvPhDJkCmLRC8+EMmQNq\u002fQt4gUSZAtlryKj9eJkC2WvIqP14mQKAZFqjKZCZAoBkWqMpkJkC+PymbXngmQK78l+lfhSZA\u002fN1VuFeSJkC0DjjMuaUmQJiiozWasiZARsPsEKPSJkC4ODyzHf8mQIKQrJkMEidAgpCsmQwSJ0C4VrWV7j0nQLhWtZXuPSdAuFa1le49J0AQFBd3B10nQBAUF3cHXSdALu+uS2lpJ0CGQaAhl28nQObxtuzCdSdAAiL4rux7J0CAXbzUXY4nQCzimId\u002flCdAzlh88rygJ0AiN7U8CrMnQJ5d5+ZFxSdADHdk6FXLJ0BsDp0jcNcnQJBABLaC4ydAkEAEtoLjJ0CQQAS2guMnQGTLcCSJ6SdAooITGpH7J0CighMakfsnQNyCJQiNByhAAIY7hoETKEAAhjuGgRMoQFhXHaJuHyhAVmhoaVQrKEDyhZDpMjcoQFByIHMfPShA0CyUqb9UKECIO5\u002fTVI8oQEa4MNy2vShATkpCLjrgKEDsI1379OUoQOwjXfv05ShAcv55J67rKEACs\u002fuzZfEoQM44aEjjDSlARJZmiT0ZKUBGNDx3kSQpQGw2aoMmOylAKDnMv6JRKUAoOcy\u002folEpQEwUeanXXClAGHBu8Q6aKUAYcG7xDpopQA4CJ7KWnylAVMTg+xylKUBUxOD7HKUpQAoUxc+hqilAChTFz6GqKUAMvAWcpsApQH4ETbXd8SlApHfJESwCKkCkd8kRLAIqQOS\u002fewkEDSpA5hSG820SKkDmFIbzbRIqQCStPKk9HSpASGRbLUZIKkDk0fVIql0qQGSLwcVJeCpAZIvBxUl4KkBYhzdvM4gqQH5xLr1+jSpAfnEuvX6NKkA2oh7CyJIqQPIl4BPrvCpAaNcYsSnCKkBSwMsso8wqQOxTDQ3e0SpARKeuMr3mKkBEp64yveYqQJb0bjjnBStAIsfM4UAQK0BWRTLUdzkrQD6tDasvWCtAugGfP0pdK0A8\u002fbam0XsrQNxuOa\u002f1hStApJGy92\u002fCK0Cw88\u002fodMwrQDK4vit02ytAHlnxFWTvK0Ci+PEOMU0sQKL48Q4xTSxA1LL4z4JqLECMxAH01YIsQOQ6Jk5ikSxA8E0QyDmWLEBISWPgjaksQIYaWbYCuCxAWqz2127GLEC8nVuhO8ssQPTeKECc2SxAfl\u002feN2XeLEAaj9lO9OcsQBqP2U705yxAkiDIKgf7LEAadaqxyRItQHJt0GvmMy1AJA0gJ3vELUBs4me8reQtQDTlKplHCS5AqMkHREU7LkAwq9nUQYwuQHb0JGIIpy5ARKlavdK4LkA0krtsQ70uQPblPJj+zi5AlmyK2bf2LkCCeiUNHvsuQAiAZcR3RS9A"},"yaxis":"y","type":"scatter"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"Sqrt Fast Speed Rate"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"Barrel Rate"}},"legend":{"tracegroupgap":0},"title":{"text":"Swing Speed Rate vs Barrel Rate"}},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('794d60ff-d4e6-4302-b2ee-8bc202f57c8e');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
<p>Scatter Plot of Sqrt Fast Swing Rate vs Barrel Rate</p>
</div>
</div>
<p>Slightly more linear! The OLS regression as a <img src="https://latex.codecogs.com/png.latex?R%5E2"> value of 0.49, which is slightly higher than the non-transformed model. The coefficient for square root fast swing rate is 1.50 which means for every one-unit increase in square root fast swing rate, barrel rate increases by 1.50 units.</p>
</section>
</section>
<section id="decision-trees" class="level1">
<h1>Decision Trees</h1>
<p>Let’s go back to the original fast swing rate and barrel rate data. The biphasic trend suggests a simple linear regression may not be the best fit. We saw that a bunch of batters with a fast swing rate less than 5% had a low barrel rate. However, is there a threshold effect? A decision tree regression can help us identify if there is a threshold effect in the data.</p>
<p><a href="https://scikit-learn.org/stable/modules/tree.html#tree">Decision trees</a> are our first non-parametric model to make an appearance on this blog! They are a type of supervised learning algorithm that can be used for both classification and regression tasks. Decision trees work by learning simple decision rules inferred from the data features.</p>
<p>Let <img src="https://latex.codecogs.com/png.latex?T"> be a decision tree that consists of a set of nodes. Each internal (non-leaf) node <img src="https://latex.codecogs.com/png.latex?m"> represents a test on a feature <img src="https://latex.codecogs.com/png.latex?j"> with a split at point <img src="https://latex.codecogs.com/png.latex?s_m">. For a data point <img src="https://latex.codecogs.com/png.latex?x">, if its <img src="https://latex.codecogs.com/png.latex?j">-th feature <img src="https://latex.codecogs.com/png.latex?x_j%20%3C%20s_m">, it goes to the left child node; otherwise, it goes to the right child node. The terminal nodes (leaves) of the tree represent the predicted value for the target variable.</p>
<p>For a given feature space <img src="https://latex.codecogs.com/png.latex?X%20%5Cin%20%5Cmathbb%7BR%7D%5Ed">, the tree defines a partition into <img src="https://latex.codecogs.com/png.latex?M"> regions <img src="https://latex.codecogs.com/png.latex?R_1,%20R_2,%20%5Cldots,%20R_M"> such that <img src="https://latex.codecogs.com/png.latex?%5Ccup_%7Bm=1%7D%5E%7BM%7DR_m%20=%20X"> and <img src="https://latex.codecogs.com/png.latex?R_i%20%5Ccap%20R_j%20=%20%5Cemptyset"> for <img src="https://latex.codecogs.com/png.latex?i%5Cneq%20j">.</p>
<section id="classification-trees" class="level2">
<h2 class="anchored" data-anchor-id="classification-trees">Classification Trees</h2>
<p>In classification tasks, the goal is to predict a categorical label. The decision tree algorithm recursively splits the data into subsets based on feature values, aiming to create pure subsets where all samples in a subset belong to the same class. The splitting criterion is often based on measures like Gini impurity or information gain.</p>
<p>For a leaf node representing region <img src="https://latex.codecogs.com/png.latex?R_m"> let <img src="https://latex.codecogs.com/png.latex?p_%7Bmk%7D"> be the proportion of samples in <img src="https://latex.codecogs.com/png.latex?R_m"> that belong to class <img src="https://latex.codecogs.com/png.latex?k">. <img src="https://latex.codecogs.com/png.latex?p_%7Bmk%7D%20=%20%5Cfrac%7B1%7D%7BN_m%7D%5Csum_%7Bx_i%5Cin%20R_m%7D%20I(y_i=k)."> The predicted class for a sample <img src="https://latex.codecogs.com/png.latex?x"> that falls into region <img src="https://latex.codecogs.com/png.latex?R_m"> is given by the class with the highest proportion: <img src="https://latex.codecogs.com/png.latex?%5Chat%7By%7D(x)%20=%20%5Carg%5Cmax_k%20p_%7Bmk%7D."></p>
<p>Let’s implement the algorithm for finding the best decision split. The “best split” is the one that results in the highest information gain. Given a 2D array data where each row is a sample. The last column of data is the class label (0 or 1), and the preceding columns are the feature values. You are also given feature_indices, a list of column indices to consider for splitting.</p>
<section id="splitting-criterion" class="level3">
<h3 class="anchored" data-anchor-id="splitting-criterion">Splitting Criterion</h3>
<p>We can use functions like entropy or Gini impurity to measure the quality of a split. The goal is to find the feature and threshold that maximizes the information gain, which is the reduction in entropy or impurity after the split. You can think of the split as <img src="https://latex.codecogs.com/png.latex?%5Ctheta">, where <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> is a threshold value for a feature <img src="https://latex.codecogs.com/png.latex?j">. The split divides the data into two subsets: <img src="https://latex.codecogs.com/png.latex?D_L%20=%20%5C%7Bx_i%20%7C%20x_%7Bij%7D%20%3C%20%5Ctheta%5C%7D"> and <img src="https://latex.codecogs.com/png.latex?D_R%20=%20%5C%7Bx_i%20%7C%20x_%7Bij%7D%20%5Cgeq%20%5Ctheta%5C%7D">. We want to find the split that maximizes the information gain: <img src="https://latex.codecogs.com/png.latex?IG(D,%20%5Ctheta)%20=%20H(D)%20-%20%5Cleft(%20%5Cfrac%7B%7CD_L%7C%7D%7B%7CD%7C%7D%20H(D_L)%20+%20%5Cfrac%7B%7CD_R%7C%7D%7B%7CD%7C%7D%20H(D_R)%20%5Cright)"> where <img src="https://latex.codecogs.com/png.latex?H(D)"> is the entropy of the dataset <img src="https://latex.codecogs.com/png.latex?D">.</p>
<p><code>find_best_split(data, feature_indices)</code> iterates through each specified feature and each unique value within that feature as a potential split threshold. For each potential split, you will calculate the Information Gain. The function should return a tuple containing the index of the best feature to split on and the best threshold value.</p>
<div id="cell-decision-tree-split" class="cell" data-execution_count="3">
<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 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="cb3-2"></span>
<span id="cb3-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> entropy(labels):</span>
<span id="cb3-4">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Calculates the entropy for a set of labels."""</span></span>
<span id="cb3-5">    <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;">len</span>(labels) <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="cb3-6">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb3-7"></span>
<span id="cb3-8">    counts <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.bincount(labels.astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>))</span>
<span id="cb3-9">    probabilities <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> counts[counts <span class="op" 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="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(labels)</span>
<span id="cb3-10">    <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>np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(probabilities <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.log2(probabilities))</span>
<span id="cb3-11"></span>
<span id="cb3-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> find_best_split(data, feature_indices):</span>
<span id="cb3-13">    labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> data[:, <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="cb3-14">    best_info_gain <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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb3-15">    best_split <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-16">    parent_entropy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> entropy(labels)</span>
<span id="cb3-17">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> f_i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> feature_indices:</span>
<span id="cb3-18">        feature_data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> data[:, f_i]</span>
<span id="cb3-19">        unique_values <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.unique(feature_data)</span>
<span id="cb3-20">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> threshold <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> unique_values:</span>
<span id="cb3-21">            left_indices <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> feature_data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> threshold</span>
<span id="cb3-22">            right_indices <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> feature_data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> threshold</span>
<span id="cb3-23"></span>
<span id="cb3-24">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">all</span>(left_indices) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">all</span>(right_indices):</span>
<span id="cb3-25">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">continue</span></span>
<span id="cb3-26"></span>
<span id="cb3-27">            left_labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> labels[left_indices]</span>
<span id="cb3-28">            right_labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> labels[right_indices]</span>
<span id="cb3-29"></span>
<span id="cb3-30">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate the weighted average entropy</span></span>
<span id="cb3-31">            p_left <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(left_labels) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(labels)</span>
<span id="cb3-32">            p_right <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(right_labels) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(labels)</span>
<span id="cb3-33">            weighted_entropy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> p_left <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> entropy(left_labels) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> p_right <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> entropy(right_labels)</span>
<span id="cb3-34">            </span>
<span id="cb3-35">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate information gain</span></span>
<span id="cb3-36">            info_gain <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> parent_entropy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> weighted_entropy</span>
<span id="cb3-37"></span>
<span id="cb3-38">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Update the best split if the current one is better</span></span>
<span id="cb3-39">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> info_gain <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> best_info_gain:</span>
<span id="cb3-40">                best_info_gain <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> info_gain</span>
<span id="cb3-41">                best_split <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (f_i, threshold)</span>
<span id="cb3-42"></span>
<span id="cb3-43">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> best_split</span>
<span id="cb3-44"></span>
<span id="cb3-45">sample_data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(</span>
<span id="cb3-46">    [[<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>],</span>
<span id="cb3-47">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>],</span>
<span id="cb3-48">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>],</span>
<span id="cb3-49">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb3-50">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.7</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>],</span>
<span id="cb3-51">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb3-52">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb3-53">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb3-54">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5.6</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]],</span>
<span id="cb3-55">)</span>
<span id="cb3-56"></span>
<span id="cb3-57">feature_indx, threshold <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> find_best_split(sample_data, [<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;">1</span>])</span>
<span id="cb3-58"></span>
<span id="cb3-59"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Best feature index: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>feature_indx<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;">, Best threshold: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>threshold<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="cb3-60"></span>
<span id="cb3-61">plt.scatter(sample_data[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], sample_data[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>sample_data[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], cmap<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;">"coolwarm"</span>)</span>
<span id="cb3-62">plt.axvline(x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>threshold, 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;">"blue"</span>, linestyle<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>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Split at </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>threshold<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-63">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Feature 1"</span>)</span>
<span id="cb3-64">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Feature 2"</span>)</span>
<span id="cb3-65">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sample Data for Decision Tree Split"</span>)</span>
<span id="cb3-66">plt.legend()</span>
<span id="cb3-67">plt.show()</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Best feature index: 0, Best threshold: 5.5</code></pre>
</div>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/fast-swings-and-barrels/index_files/figure-html/decision-tree-split-output-2.png" id="decision-tree-split" width="589" height="449" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>The function <code>find_best_split</code> calculates the best feature and threshold to split the data based on minimizing entropy. The output shows that the best feature index is 0 (the first feature) with a threshold of 5.1. The plot visualizes the sample data and the split line.</p>
<p><code>find_best_split</code> iteratres through each feature in the dataset and each unique value within that feature as a potential split threshold. Get the left and right indicies of that unique value by calculating boolean masks. Check if one of the masks is all True, which means that the split would not be valid. Then get the labels for the left and right splits and calculate the weighted average entropy. If the current split has a lower entropy than the best split so far, update the best split. Finally, return the index of the best feature to split on and the best threshold value.</p>
</section>
</section>
<section id="regression-trees" class="level2">
<h2 class="anchored" data-anchor-id="regression-trees">Regression Trees</h2>
<p><a href="https://scikit-learn.org/stable/modules/tree.html#tree-regression">Regression trees</a> are used to predict continuous values. The decision tree algorithm recursively splits the data into subsets based on feature values, aiming to create pure subsets where all samples in a subset have similar target values. The splitting criterion is often based on measures like mean squared error (MSE) or mean absolute error (MAE). The prediction for a new input <img src="https://latex.codecogs.com/png.latex?x"> is given by <img src="https://latex.codecogs.com/png.latex?f(x)%20=%20%5Csum_%7Bm=1%7D%5EM%20c_mI(x%5Cin%20R_m)."> The value <img src="https://latex.codecogs.com/png.latex?c_m"> is chosen to minimize the sum of squared errors within the region. <img src="https://latex.codecogs.com/png.latex?c_m%20=%20%5Ctext%7Bargmin%7D_c%5Csum_%7Bx_i%20%5Cin%20R_m%7D(y_i%20-%20c)%5E2%20=%20%5Cfrac%7B1%7D%7BN_m%7D%5Csum%20y_i."></p>
</section>
<section id="splitting-criterion-1" class="level2">
<h2 class="anchored" data-anchor-id="splitting-criterion-1">Splitting Criterion</h2>
<p>For regression tasks, the splitting criterion is based on minimizing the variance of the target variable in the resulting subsets. A given node <img src="https://latex.codecogs.com/png.latex?n"> and a split candidate by feature <img src="https://latex.codecogs.com/png.latex?j"> and point <img src="https://latex.codecogs.com/png.latex?s">, partitions the data into two sets: <img src="https://latex.codecogs.com/png.latex?R_%7B%5Ctext%7Bleft%7D%7D(%5Ctheta)=%5C%7B(x,y)%20%7C%20x_j%5Cleq%20s%5C%7D%20%5Ctext%7Band%20%7D%20R_%7B%5Ctext%7Bright%7D%7D(%5Ctheta)=%5C%7B(x,y)%20%7C%20x_j%20%3E%20s%5C%7D">.</p>
<p>The goal is the find the optimal split <img src="https://latex.codecogs.com/png.latex?%5Ctheta=(j,s)"> that minimizes the weighted sum of squared errors of the two subsets. The objective function is: <img src="https://latex.codecogs.com/png.latex?%5Csum_%7Bx_i%20%5Cin%20R_%7B%5Ctext%7Bleft%7D%7D(%5Ctheta)%7D(y_i%20-%20%5Cbar%7By%7D_%7B%5Ctext%7Bleft%7D%7D)%5E2%20+%20%5Csum_%7Bx_i%20%5Cin%20R_%7B%5Ctext%7Bright%7D%7D(%5Ctheta)%7D(y_i%20-%20%5Cbar%7By%7D_%7B%5Ctext%7Bright%7D%7D)%5E2."></p>
</section>
<section id="grouping-players-with-decision-trees" class="level2">
<h2 class="anchored" data-anchor-id="grouping-players-with-decision-trees">Grouping Players with Decision Trees</h2>
<p>We can use a decision tree regression model to group players based on their fast swing rate and barrel rate. The decision tree will help us identify the optimal threshold for fast swing rate that separates players into different performance groups. Below I apply a decision tree regression model to the fast swing rate and barrel rate data. The goal is to find the optimal threshold for fast swing rate that separates players into different performance groups. Since we are interested in finding a threshold, we will set the maximum depth of the tree to 1. This means that the tree will only have one split, which will be the optimal threshold for fast swing rate.</p>
<div id="decision-tree-regression" class="cell" data-execution_count="4">
<details class="code-fold">
<summary>Code</summary>
<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 class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.tree <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> DecisionTreeRegressor</span>
<span id="cb5-2"><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> train_test_split</span>
<span id="cb5-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy.stats <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> ttest_ind</span>
<span id="cb5-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sys</span>
<span id="cb5-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> sklearn</span>
<span id="cb5-6"></span>
<span id="cb5-7">X_feature_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;">"fast_swing_rate"</span></span>
<span id="cb5-8">y_feature_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;">"barrel_batted_rate"</span></span>
<span id="cb5-9"></span>
<span id="cb5-10">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[[X_feature_name]]</span>
<span id="cb5-11">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[y_feature_name]</span>
<span id="cb5-12"></span>
<span id="cb5-13">model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DecisionTreeRegressor(max_depth<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>, 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="cb5-14">model.fit(X, y)</span>
<span id="cb5-15"></span>
<span id="cb5-16">threshold_X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.tree_.threshold[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb5-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"The optimal threshold 'X' found by the Decision Tree is: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>threshold_X<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>The optimal threshold 'X' found by the Decision Tree is: 35.35%</code></pre>
</div>
</div>
<p>Our decision tree found that the threshold for fast swing rate is approximately 35.35%. What does the average barrel rate look like for players below and above this threshold? Let’s calculate the average barrel rate for players below and above the threshold.</p>
<div id="a564d1db" class="cell" data-execution_count="5">
<details class="code-fold">
<summary>Code</summary>
<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">below_threshold <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fast_swing_rate"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> threshold_X]</span>
<span id="cb7-2">at_or_above_threshold <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fast_swing_rate"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> threshold_X]</span>
<span id="cb7-3"></span>
<span id="cb7-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate the average barrel rate for each group</span></span>
<span id="cb7-5">avg_barrel_rate_below <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> below_threshold[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel_batted_rate"</span>].mean()</span>
<span id="cb7-6">avg_barrel_rate_above <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> at_or_above_threshold[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel_batted_rate"</span>].mean()</span>
<span id="cb7-7"></span>
<span id="cb7-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Average barrel rate for players below </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>threshold_X<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>avg_barrel_rate_below<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span>
<span id="cb7-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Average barrel rate for players at or above </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>threshold_X<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>avg_barrel_rate_above<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span>
<span id="cb7-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"The drop in average barrel rate is: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>(avg_barrel_rate_above <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> avg_barrel_rate_below)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.1f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>)</span>
<span id="cb7-11"></span>
<span id="cb7-12">stat, pvalue <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ttest_ind(below_threshold[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel_batted_rate"</span>], at_or_above_threshold[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel_batted_rate"</span>], equal_var<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>, nan_policy<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;">'omit'</span>)</span>
<span id="cb7-13"></span>
<span id="cb7-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">T-test p-value: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>pvalue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2e}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb7-15"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> pvalue <span class="op" 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>
<span id="cb7-16">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The difference between the two groups is statistically significant."</span>)</span>
<span id="cb7-17"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb7-18">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"The difference between the two groups is not statistically significant."</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>Average barrel rate for players below 35.35%: 7.9%
Average barrel rate for players at or above 35.35%: 13.3%
The drop in average barrel rate is: 5.4%

T-test p-value: 2.08e-28
The difference between the two groups is statistically significant.</code></pre>
</div>
</div>
<p>A different of 5.4% barrel rate is pretty stark! In taking a t-test as well, we find that the difference between the two groups is statistically significant with a p-value of 2.08e-28. This suggests that there is a significant difference in barrel rate between players below and above the threshold of 35.35% fast swing rate.</p>
<p>Let’s plot the cutoff threshold and the average barrel rates for each group.</p>
<div id="cell-decision-tree-regression-plot" class="cell" data-execution_count="6">
<details class="code-fold">
<summary>Code</summary>
<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 class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.graph_objects <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> go</span>
<span id="cb9-2"></span>
<span id="cb9-3">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> px.scatter(</span>
<span id="cb9-4">    df, </span>
<span id="cb9-5">    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;">"fast_swing_rate"</span>, </span>
<span id="cb9-6">    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;">"barrel_batted_rate"</span>, </span>
<span id="cb9-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;">"Decision Tree Regression of Fast Swing Rate vs Barrel Rate"</span>,</span>
<span id="cb9-8">    hover_data<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;">"last_name, first_name"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fast_swing_rate"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"barrel_batted_rate"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"year"</span>],</span>
<span id="cb9-9">)</span>
<span id="cb9-10">fig.update_xaxes(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;">"Fast Speed Rate"</span>)</span>
<span id="cb9-11">fig.update_yaxes(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;">"Barrel Rate"</span>)</span>
<span id="cb9-12">fig.add_shape(</span>
<span id="cb9-13">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">type</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;">"line"</span>,</span>
<span id="cb9-14">    x0<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>threshold_X,</span>
<span id="cb9-15">    y0<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="cb9-16">    x1<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>threshold_X,</span>
<span id="cb9-17">    y1<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;">"barrel_batted_rate"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(),</span>
<span id="cb9-18">    line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</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;">"blue"</span>, 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;">2</span>, dash<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;">"dash"</span>),</span>
<span id="cb9-19">    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;">"Decision Tree Threshold"</span></span>
<span id="cb9-20">)</span>
<span id="cb9-21">fig.add_annotation(</span>
<span id="cb9-22">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>threshold_X,</span>
<span id="cb9-23">    y<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;">"barrel_batted_rate"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(),</span>
<span id="cb9-24">    text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Threshold: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>threshold_X<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%"</span>,</span>
<span id="cb9-25">    showarrow<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="cb9-26">    arrowhead<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-27">    ax<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="cb9-28">    ay<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;">40</span>,</span>
<span id="cb9-29">    font<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</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;">"green"</span>),        </span>
<span id="cb9-30">)</span>
<span id="cb9-31">fig.show()</span></code></pre></div>
</details>
<div id="decision-tree-regression-plot" class="cell-output cell-output-display">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="ccc7b6e4-919f-4ac6-b0c7-545d0562d980" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("ccc7b6e4-919f-4ac6-b0c7-545d0562d980")) {                    Plotly.newPlot(                        "ccc7b6e4-919f-4ac6-b0c7-545d0562d980",                        [{"customdata":[["Yoshida, Masataka",2023],["Vaughn, Andrew",2023],["Rooker Jr., Brent",2023],["Rosario, Eddie",2023],["Davis, J.D.",2023],["Bell, Josh",2023],["Abreu, José",2023],["Friedl Jr., TJ",2023],["Canha, Mark",2023],["Freeman, Freddie",2023],["Happ, Ian",2023],["Ramírez, José",2023],["Nootbaar, Lars",2023],["Garcia, Maikel",2023],["Arraez, Luis",2023],["Alonso, Pete",2023],["Witt Jr., Bobby",2023],["Contreras, William",2023],["Hays, Austin",2023],["Lindor, Francisco",2023],["Soler, Jorge",2023],["Cronenworth, Jake",2023],["Thomas, Lane",2023],["Volpe, Anthony",2023],["Bichette, Bo",2023],["Díaz, Yandy",2023],["Castellanos, Nick",2023],["Turner, Justin",2023],["Meneses, Joey",2023],["Rutschman, Adley",2023],["Seager, Corey",2023],["Turner, Trea",2023],["Bogaerts, Xander",2023],["Drury, Brandon",2023],["Varsho, Daulton",2023],["Walker, Christian",2023],["Candelario, Jeimer",2023],["Reynolds, Bryan",2023],["Stephenson, Tyler",2023],["Tatis Jr., Fernando",2023],["Vierling, Matt",2023],["Suwinski, Jack",2023],["Merrifield, Whit",2023],["Edman, Tommy",2023],["Benintendi, Andrew",2023],["Ohtani, Shohei",2023],["Olson, Matt",2023],["France, Ty",2023],["McMahon, Ryan",2023],["Harper, Bryce",2023],["Arcia, Orlando",2023],["Taveras, Leody",2023],["Casas, Triston",2023],["Realmuto, J.T.",2023],["Adames, Willy",2023],["Chapman, Matt",2023],["Acuña Jr., Ronald",2023],["Betts, Mookie",2023],["Swanson, Dansby",2023],["Albies, Ozzie",2023],["Burger, Jake",2023],["Ozuna, Marcell",2023],["Robert Jr., Luis",2023],["Peña, Jeremy",2023],["Torres, Gleyber",2023],["Machado, Manny",2023],["Henderson, Gunnar",2023],["Outman, James",2023],["Tucker, Kyle",2023],["Jung, Josh",2023],["Anderson, Tim",2023],["Raleigh, Cal",2023],["Hernández, Enrique",2023],["Yelich, Christian",2023],["Goldschmidt, Paul",2023],["Renfroe, Hunter",2023],["Rosario, Amed",2023],["Suárez, Eugenio",2023],["LeMahieu, DJ",2023],["Springer III, George",2023],["Lowe, Nathaniel",2023],["Devers, Rafael",2023],["Bellinger, Cody",2023],["Melendez Jr., MJ",2023],["Gurriel Jr., Lourdes",2023],["Bohm, Alec",2023],["Smith, Dominic",2023],["Paredes, Isaac",2023],["Guerrero Jr., Vladimir",2023],["McNeil, Jeff",2023],["Abrams, CJ",2023],["Arozarena, Randy",2023],["Muncy, Max",2023],["Santander, Anthony",2023],["García, Adolis",2023],["Santana, Carlos",2023],["Steer, Spencer",2023],["Straw, Myles",2023],["Nimmo, Brandon",2023],["Stott, Bryson",2023],["Hoerner, Nico",2023],["Arenado, Nolan",2023],["Soto, Juan",2023],["Hernández, Teoscar",2023],["Carroll, Corbin",2023],["Hayes, Ke'Bryan",2023],["Báez, Javier",2023],["Crawford, J.P.",2023],["Bregman, Alex",2023],["Suzuki, Seiya",2023],["Kim, Ha-Seong",2023],["McKinstry, Zach",2023],["Semien, Marcus",2023],["Schwarber, Kyle",2023],["Profar, Jurickson",2023],["Estrada, Thairo",2023],["Marte, Ketel",2023],["India, Jonathan",2023],["Wade Jr., LaMonte",2023],["Torkelson, Spencer",2023],["Tovar, Ezequiel",2023],["Giménez, Andrés",2023],["Correa, Carlos",2023],["Smith, Will",2023],["Perez, Salvador",2023],["Harris II, Michael",2023],["Ruiz, Keibert",2023],["De La Cruz, Bryan",2023],["Kwan, Steven",2023],["Verdugo, Alex",2023],["Díaz, Elias",2023],["Rodríguez, Julio",2023],["Riley, Austin",2023],["Grisham, Trent",2023],["Bleday, JJ",2024],["Kwan, Steven",2024],["Torres, Gleyber",2024],["Naylor, Josh",2024],["Cowser, Colton",2024],["Rodríguez, Julio",2024],["Smith, Josh",2024],["Tovar, Ezequiel",2024],["Garcia, Maikel",2024],["Langeliers, Shea",2024],["Reynolds, Bryan",2024],["Castellanos, Nick",2024],["Busch, Michael",2024],["Hernández, Teoscar",2024],["Soto, Juan",2024],["McCutchen, Andrew",2024],["Sánchez, Jesús",2024],["Schwarber, Kyle",2024],["Carroll, Corbin",2024],["Cruz, Oneil",2024],["García, Luis",2024],["Volpe, Anthony",2024],["Machado, Manny",2024],["Burleson, Alec",2024],["Morel, Christopher",2024],["Ohtani, Shohei",2024],["Arraez, Luis",2024],["Abrams, CJ",2024],["Turang, Brice",2024],["Neto, Zach",2024],["Langford, Wyatt",2024],["Rutschman, Adley",2024],["Smith, Will",2024],["Donovan, Brendan",2024],["Judge, Aaron",2024],["Benintendi, Andrew",2024],["Chapman, Matt",2024],["Henderson, Gunnar",2024],["Young, Jacob",2024],["Betts, Mookie",2024],["Lindor, Francisco",2024],["Meyers, Jake",2024],["Seager, Corey",2024],["Olson, Matt",2024],["Suzuki, Seiya",2024],["De La Cruz, Bryan",2024],["Varsho, Daulton",2024],["Merrill, Jackson",2024],["Alvarez, Yordan",2024],["Ozuna, Marcell",2024],["Contreras, William",2024],["De La Cruz, Elly",2024],["Rafaela, Ceddanne",2024],["Walker, Christian",2024],["Castro, Willi",2024],["Perez, Salvador",2024],["Raleigh, Cal",2024],["Santander, Anthony",2024],["Ortiz, Joey",2024],["Rooker Jr., Brent",2024],["Devers, Rafael",2024],["Diaz, Yainer",2024],["Witt Jr., Bobby",2024],["Winn, Masyn",2024],["Díaz, Yandy",2024],["Cronenworth, Jake",2024],["Vaughn, Andrew",2024],["Chisholm Jr., Jazz",2024],["Duran, Jarren",2024],["Taveras, Leody",2024],["Steer, Spencer",2024],["Gurriel Jr., Lourdes",2024],["Hoerner, Nico",2024],["Frelick, Sal",2024],["Soler, Jorge",2024],["Suárez, Eugenio",2024],["Ramírez, José",2024],["Giménez, Andrés",2024],["India, Jonathan",2024],["Bohm, Alec",2024],["Doyle, Brenton",2024],["Peña, Jeremy",2024],["Schanuel, Nolan",2024],["Lowe, Nathaniel",2024],["Ramos, Heliot",2024],["Harper, Bryce",2024],["Arenado, Nolan",2024],["Stott, Bryson",2024],["Winker, Jesse",2024],["Thomas, Lane",2024],["Pasquantino, Vinnie",2024],["Hoskins, Rhys",2024],["Chourio, Jackson",2024],["Semien, Marcus",2024],["Rodgers, Brendan",2024],["Arozarena, Randy",2024],["Profar, Jurickson",2024],["Santana, Carlos",2024],["Marte, Ketel",2024],["Arcia, Orlando",2024],["Burger, Jake",2024],["García, Adolis",2024],["Vierling, Matt",2024],["Bregman, Alex",2024],["Paredes, Isaac",2024],["Stephenson, Tyler",2024],["Guerrero Jr., Vladimir",2024],["McMahon, Ryan",2024],["Greene, Riley",2024],["Verdugo, Alex",2024],["Goldschmidt, Paul",2024],["Turner, Justin",2024],["Keith, Colt",2024],["Freeman, Freddie",2024],["France, Ty",2024],["Adames, Willy",2024],["Mountcastle, Ryan",2024],["Nimmo, Brandon",2024],["O'Hoppe, Logan",2024],["Gelof, Zack",2024],["Bell, Josh",2024],["Ward, Taylor",2024],["Happ, Ian",2024],["Springer III, George",2024],["Bellinger, Cody",2024],["Turner, Trea",2024],["Alonso, Pete",2024],["Swanson, Dansby",2024],["Altuve, Jose",2024],["Robert Jr., Luis",2025],["Schanuel, Nolan",2025],["Steer, Spencer",2025],["Rice, Ben",2025],["Donovan, Brendan",2025],["Edwards, Xavier",2025],["Walker, Christian",2025],["Wagaman, Eric",2025],["Soderstrom, Tyler",2025],["Harper, Bryce",2025],["Soler, Jorge",2025],["Bichette, Bo",2025],["Buxton, Byron",2025],["Semien, Marcus",2025],["Meyers, Jake",2025],["Wood, James",2025],["Bellinger, Cody",2025],["Stott, Bryson",2025],["India, Jonathan",2025],["Contreras, Willson",2025],["Hoerner, Nico",2025],["Diaz, Yainer",2025],["Mullins II, Cedric",2025],["Ward, Taylor",2025],["Flores, Wilmer",2025],["O'Hearn, Ryan",2025],["Toglia, Michael",2025],["Torkelson, Spencer",2025],["Rengifo, Luis",2025],["Muncy, Max",2025],["Smith, Will",2025],["Hoskins, Rhys",2025],["Stowers, Kyle",2025],["Tatis Jr., Fernando",2025],["Goodman, Hunter",2025],["Adames, Willy",2025],["Langford, Wyatt",2025],["Rodríguez, Julio",2025],["Olson, Matt",2025],["Scott II, Victor",2025],["McCutchen, Andrew",2025],["Lowe, Nathaniel",2025],["Burleson, Alec",2025],["Wilson Jr., Jacob",2025],["Bell, Josh",2025],["Ramírez, José",2025],["Butler, Lawrence",2025],["Ramírez, Agustín",2025],["Holliday, Jackson",2025],["Clement, Ernie",2025],["Jung, Josh",2025],["Perez, Salvador",2025],["Garcia, Maikel",2025],["Schwarber, Kyle",2025],["McMahon, Ryan",2025],["Smith, Cam",2025],["Cruz, Oneil",2025],["Vargas, Miguel",2025],["Paredes, Isaac",2025],["Reynolds, Bryan",2025],["Naylor, Josh",2025],["Frelick, Sal",2025],["Crow-Armstrong, Pete",2025],["Suárez, Eugenio",2025],["Torres, Gleyber",2025],["Soto, Juan",2025],["Adell, Jo",2025],["Nimmo, Brandon",2025],["Guerrero Jr., Vladimir",2025],["Judge, Aaron",2025],["Duran, Jarren",2025],["Tucker, Kyle",2025],["Chourio, Jackson",2025],["Winn, Masyn",2025],["Lux, Gavin",2025],["Lindor, Francisco",2025],["Lee, Jung Hoo",2025],["Hernández, Teoscar",2025],["Swanson, Dansby",2025],["Turner, Trea",2025],["Perdomo, Geraldo",2025],["Bogaerts, Xander",2025],["Betts, Mookie",2025],["García, Adolis",2025],["Lowe, Brandon",2025],["Rooker Jr., Brent",2025],["Freeman, Freddie",2025],["Larnach, Trevor",2025],["Goldschmidt, Paul",2025],["McLain, Matt",2025],["Ozuna, Marcell",2025],["France, Ty",2025],["Bohm, Alec",2025],["Albies, Ozzie",2025],["Chapman, Matt",2025],["Grisham, Trent",2025],["Nootbaar, Lars",2025],["Happ, Ian",2025],["Arenado, Nolan",2025],["Aranda, Jonathan",2025],["Kirk, Alejandro",2025],["Devers, Rafael",2025],["Ohtani, Shohei",2025],["Crawford, J.P.",2025],["Springer III, George",2025],["Raleigh, Cal",2025],["Doyle, Brenton",2025],["Marte, Ketel",2025],["Realmuto, J.T.",2025],["McKinstry, Zach",2025],["Henderson, Gunnar",2025],["Correa, Carlos",2025],["Arraez, Luis",2025],["Santana, Carlos",2025],["Greene, Riley",2025],["Kwan, Steven",2025],["Caminero, Junior",2025],["Díaz, Yandy",2025],["Pasquantino, Vinnie",2025],["Smith, Josh",2025],["Domínguez, Jasson",2025],["Alonso, Pete",2025],["Turang, Brice",2025],["Machado, Manny",2025],["Peña, Jeremy",2025],["Beck, Jordan",2025],["Friedl Jr., TJ",2025],["Abreu, Wilyer",2025],["Gurriel Jr., Lourdes",2025],["Volpe, Anthony",2025],["Contreras, William",2025],["Busch, Michael",2025],["Ortiz, Joey",2025],["Yelich, Christian",2025],["Conforto, Michael",2025],["Sheets, Gavin",2025],["De La Cruz, Elly",2025],["Story, Trevor",2025],["Manzardo, Kyle",2025],["Castellanos, Nick",2025],["Yastrzemski, Mike",2025],["García, Luis",2025],["Carroll, Corbin",2025],["Arozarena, Randy",2025],["Riley, Austin",2025],["Pages, Andy",2025],["Ramos, Heliot",2025],["Kepler, Max",2025],["Lopez, Otto",2025],["Altuve, Jose",2025],["Witt Jr., Bobby",2025],["Rafaela, Ceddanne",2025],["Neto, Zach",2025],["Abrams, CJ",2025],["Hayes, Ke'Bryan",2025],["Harris II, Michael",2025],["Suzuki, Seiya",2025]],"hovertemplate":"fast_swing_rate=%{x}\u003cbr\u003ebarrel_batted_rate=%{y}\u003cbr\u003elast_name, first_name=%{customdata[0]}\u003cbr\u003eyear=%{customdata[1]}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"","marker":{"color":"#636efa","symbol":"circle"},"mode":"markers","name":"","orientation":"v","showlegend":false,"x":{"dtype":"f8","bdata":"mpmZmZmZM0DNzMzMzMwkQAAAAAAAwEBAZmZmZmZmJkAzMzMzM7MyQJqZmZmZGT1AzczMzMzMREDNzMzMzMwMQAAAAAAAAAxAzczMzMzMJkDNzMzMzEwzQAAAAAAAACpAAAAAAAAAN0AAAAAAAAAUQJqZmZmZmck\u002fAAAAAAAATECamZmZmdlKQDMzMzMzc0ZAzczMzMzMK0BmZmZmZmYtQAAAAAAAwE5AzczMzMzMEECamZmZmRkxQDMzMzMzMyJAzczMzMzML0CamZmZmZlEQM3MzMzMTDxAAAAAAAAA4D8AAAAAAAAnQAAAAAAAACRAzczMzMxMMUAAAAAAAAA7QJqZmZmZmS5AMzMzMzMzMUDNzMzMzIxHQM3MzMzMDElAmpmZmZmZG0CamZmZmZklQJqZmZmZmQVAzczMzMxMPkAzMzMzMzMpQJqZmZmZ2UFAMzMzMzMz8z\u002fNzMzMzMwvQGZmZmZmZgJAMzMzMzNzUkBmZmZmZuZIQAAAAAAAgDNAmpmZmZkZN0AAAAAAAIBLQM3MzMzMTDRAZmZmZmZmLUAAAAAAAMBOQAAAAAAAwEFAMzMzMzMzOECamZmZmVlMQGZmZmZmhlFAMzMzMzOzNEAAAAAAAAAiQM3MzMzMzCVAzczMzMwsUECamZmZmVlKQM3MzMzMTE9AAAAAAAAAMEBmZmZmZmY2QDMzMzMzk1BAZmZmZmamTEDNzMzMzMxAQAAAAAAAgDZAZmZmZmZmKkDNzMzMzMwIQM3MzMzMDElAZmZmZmZmN0AAAAAAAMBDQDMzMzMzszJAMzMzMzMzSECamZmZmZkuQM3MzMzMTDZAzczMzMzMEEBmZmZmZmY4QM3MzMzMDERAmpmZmZkZQUAzMzMzMzMZQGZmZmZmZjVAZmZmZmZmEkAzMzMzMzM0QDMzMzMzMxdAmpmZmZmZEUBmZmZmZiZKQM3MzMzMzARAMzMzMzMzNEAAAAAAAABAQM3MzMzMzC1AmpmZmZmZP0AzMzMzM3NDQM3MzMzMzCtAZmZmZmZmJ0AAAAAAAADwPzMzMzMzMztAZmZmZmZm5j8AAAAAAAAEQM3MzMzMTDBAmpmZmZkZSEAAAAAAAMBFQDMzMzMzsz1AZmZmZmbmNEAAAAAAAIBGQM3MzMzMTDdAAAAAAAAAFkBmZmZmZuY+QM3MzMzMzAxAMzMzMzMzC0CamZmZmZkTQJqZmZmZmVJAzczMzMzMM0BmZmZmZmYqQAAAAAAAQEFAAAAAAAAAOUAzMzMzMzM6QDMzMzMzM0lAZmZmZmZmNUAzMzMzMzMXQDMzMzMzs0lAAAAAAAAACECamZmZmRk9QAAAAAAAwEBAZmZmZmZmAkCamZmZmZk3QJqZmZmZmck\u002fMzMzMzMzB0BmZmZmZmZAQJqZmZmZWVFAZmZmZmZGUECamZmZmZkgQAAAAAAAgDBAmpmZmZmZ2T8AAAAAAAAiQJqZmZmZWUBAzczMzMxMREAzMzMzM7NPQDMzMzMzMxtAZmZmZmbmMkCamZmZmZklQAAAAAAAAEVAmpmZmZkZMUDNzMzMzMw2QJqZmZmZmSZAMzMzMzOzP0CamZmZmZlNQM3MzMzMTDlAMzMzMzMzS0AAAAAAAIBTQDMzMzMzc0JAMzMzMzPTUkAzMzMzM7M2QJqZmZmZmQ1AzczMzMxMSkAAAAAAAAAyQM3MzMzMLFBAAAAAAAAAUECamZmZmZnJP2ZmZmZm5jdAMzMzMzMzC0BmZmZmZmYtQJqZmZmZGUhAmpmZmZmZGUDNzMzMzMwIQM3MzMzMzBxAMzMzMzOzUkAAAAAAAADwP2ZmZmZmBlBAAAAAAAAgUEBmZmZmZmb2PzMzMzMzMyNAmpmZmZmZN0CamZmZmZkfQGZmZmZm5jRAmpmZmZlZQ0AAAAAAAIBBQM3MzMzMzDNAMzMzMzMzQUCamZmZmZk1QAAAAAAAgE9AAAAAAABARUAzMzMzMzNJQDMzMzMz80pAMzMzMzMzG0BmZmZmZmZKQAAAAAAAAC9AZmZmZmamQEDNzMzMzIxGQGZmZmZm5kBAmpmZmZmZQUCamZmZmZlCQGZmZmZm5jtAmpmZmZmZN0BmZmZmZiZIQAAAAAAAACdAMzMzMzMzQUAzMzMzMzMZQAAAAAAAAChAzczMzMxMN0CamZmZmRlCQJqZmZmZmS1AMzMzMzMzK0AAAAAAAAAjQGZmZmZmZgZAAAAAAAAABEDNzMzMzExMQAAAAAAAgDVAZmZmZmbmMkCamZmZmZkbQDMzMzMzMzZAMzMzMzOzNUAzMzMzMzMgQAAAAAAAgDZAzczMzMzMBEDNzMzMzEw9QJqZmZmZmUtAAAAAAACARECamZmZmZkpQGZmZmZmZv4\u002fmpmZmZmZHUBmZmZmZuYwQM3MzMzMzDNAAAAAAAAAKkAAAAAAAABBQM3MzMzMzBBAMzMzMzMzOUAzMzMzM7NAQDMzMzMzszZAZmZmZmZmM0DNzMzMzExEQAAAAAAAACtAMzMzMzNzR0AAAAAAAAA3QJqZmZmZmSdAzczMzMzMJ0AzMzMzMzMTQM3MzMzMzCJAAAAAAADATEDNzMzMzEw6QJqZmZmZ2UZAAAAAAAAAHkDNzMzMzEw4QJqZmZmZmek\u002fmpmZmZmZLEAzMzMzMzMkQJqZmZmZmSxAmpmZmZmZQEDNzMzMzExJQGZmZmZmZkFAZmZmZmZmMUBmZmZmZmYnQAAAAAAAAC5AzczMzMzMIEAzMzMzM7M3QM3MzMzMTDZAzczMzMzMFECamZmZmRkxQGZmZmZm5klAmpmZmZmZKUAAAAAAAAAqQJqZmZmZWU1AAAAAAAAAHkDNzMzMzMwYQDMzMzMzM0RAAAAAAAAAEEDNzMzMzMz8P5qZmZmZGURAMzMzMzOzO0AzMzMzM\u002fNCQDMzMzMzc0dAmpmZmZlZREAAAAAAAAAjQAAAAAAAQEhAmpmZmZmZFUAzMzMzMzMVQJqZmZmZGVBAmpmZmZmZIkCamZmZmZkTQDMzMzMzMzZAmpmZmZnZT0DNzMzMzMwMQDMzMzMzszFAAAAAAAAAJkAzMzMzMzMbQM3MzMzMzOw\u002fMzMzMzOzMkAzMzMzMzM3QAAAAAAAADlAmpmZmZmZIkDNzMzMzMwuQJqZmZmZmRdAZmZmZmZmL0CamZmZmVlKQAAAAAAAgERAMzMzMzOzREAAAAAAAIAzQM3MzMzMjEBAMzMzMzNzTUDNzMzMzExEQAAAAAAAABZAmpmZmZmZJkBmZmZmZuY4QGZmZmZmZjxAmpmZmZmZyT+amZmZmRk+QJqZmZmZGTJAmpmZmZmZQ0BmZmZmZiZKQJqZmZmZmSNAzczMzMzMAEAzMzMzMzMVQDMzMzMzsz5AZmZmZmbmMUCamZmZmblSQGZmZmZm5kRAAAAAAABASEDNzMzMzAxTQM3MzMzMzCdAzczMzMzMI0CamZmZmRk4QM3MzMzMTDJAzczMzMzMGEAzMzMzM7M5QGZmZmZm5jhAMzMzMzMzKEDNzMzMzExDQAAAAAAAAFJAZmZmZmZmNUBmZmZmZmZQQJqZmZmZuVFAmpmZmZmZRkAAAAAAAAA4QDMzMzMzs0RAmpmZmZkZMkCamZmZmZkVQM3MzMzMzCxAZmZmZmZmEEAAAAAAAIA\u002fQM3MzMzMzBZAmpmZmZmZL0AAAAAAAAASQGZmZmZmZjhAmpmZmZmZF0AzMzMzMzM7QDMzMzMzM0BAZmZmZmZmQ0CamZmZmZkbQGZmZmZm5jZAAAAAAACAOUDNzMzMzMwQQDMzMzMzM0NAzczMzMzMKEDNzMzMzMwwQDMzMzMzMxlAMzMzMzNzSEAAAAAAAAAnQGZmZmZmJkZAAAAAAAAAM0AAAAAAAIAxQAAAAAAAAC5AAAAAAACAOkAAAAAAAIAzQDMzMzMzc09AMzMzMzMzM0AAAAAAAEBBQM3MzMzMzEpAMzMzMzMzE0AzMzMzM\u002fNGQGZmZmZmZj9AAAAAAAAA8D8zMzMzMzNLQGZmZmZm5kNAMzMzMzMz0z+amZmZmRkyQAAAAAAAAEtAmpmZmZmZ8T8zMzMzMxNTQJqZmZmZmUJAMzMzMzMzPkBmZmZmZmYQQM3MzMzMzEBAzczMzMwMT0DNzMzMzMwqQAAAAAAAgEZAMzMzMzOzMUAzMzMzMzNDQAAAAAAAAARAZmZmZmamQ0CamZmZmZkjQAAAAAAAgDlAmpmZmZkZPkDNzMzMzMwgQGZmZmZm5jpAAAAAAAAAQUAzMzMzM\u002fNCQGZmZmZmJklAzczMzMwMR0AAAAAAAAAoQJqZmZmZmSNAAAAAAAAAMUAzMzMzMzMiQAAAAAAAgDxAAAAAAABAR0DNzMzMzMw7QM3MzMzMzE1AzczMzMzMNkDNzMzMzAxFQDMzMzMzszNAMzMzMzOzNkCamZmZmZkhQDMzMzMzM0hAZmZmZmZmJ0AAAAAAAAAtQGZmZmZmZjlAAAAAAAAAJ0DNzMzMzMxAQDMzMzMz80JA"},"xaxis":"x","y":{"dtype":"f8","bdata":"ZmZmZmZmGkDNzMzMzMwgQDMzMzMzMy9AAAAAAAAAI0AzMzMzMzMjQDMzMzMzMyRAZmZmZmZmIUCamZmZmZkJQM3MzMzMzBJAMzMzMzMzJkAAAAAAAAAiQAAAAAAAABxAmpmZmZmZIUAzMzMzMzMPQAAAAAAAAAxAZmZmZmZmLUAAAAAAAAAnQM3MzMzMzCJAzczMzMzMIUDNzMzMzMwkQAAAAAAAAC5AmpmZmZmZEUAzMzMzMzMjQAAAAAAAACJAMzMzMzMzI0AAAAAAAAAjQJqZmZmZmSRAzczMzMzMFkCamZmZmZkVQAAAAAAAAB5AZmZmZmZmLkDNzMzMzMwgQGZmZmZmZhhAAAAAAAAAJkAzMzMzMzMdQM3MzMzMzCZAmpmZmZmZH0AzMzMzMzMmQGZmZmZmZh5AAAAAAAAAJkBmZmZmZmYSQGZmZmZmZi9AMzMzMzMzA0AAAAAAAAAUQDMzMzMzMwdAmpmZmZmZM0BmZmZmZmYwQDMzMzMzMxtAzczMzMzMJkBmZmZmZmYuQJqZmZmZmRtAzczMzMzMHEAzMzMzMzMqQGZmZmZmZiZAzczMzMzMKECamZmZmRkxQJqZmZmZmS5AzczMzMzMKEDNzMzMzMwlQGZmZmZmZiBAMzMzMzOzMECamZmZmZkwQM3MzMzMzC5AAAAAAAAAEECamZmZmZkfQAAAAAAAACVAzczMzMzMJkAzMzMzMzMmQDMzMzMzMyVAzczMzMzMJ0AzMzMzMzMHQDMzMzMzMylAAAAAAAAAEkBmZmZmZmYiQAAAAAAAAChAZmZmZmZmGEAzMzMzMzMLQGZmZmZmZipAmpmZmZmZF0DNzMzMzMweQAAAAAAAABpAZmZmZmZmKUBmZmZmZmYYQM3MzMzMzCZAzczMzMzMIEDNzMzMzMwWQGZmZmZmZhpAmpmZmZmZF0AzMzMzMzMmQM3MzMzMzPQ\u002fmpmZmZmZG0CamZmZmZkoQDMzMzMzMy1AZmZmZmZmJECamZmZmRkwQM3MzMzMzBpAzczMzMzMGkAAAAAAAADgPwAAAAAAACNAzczMzMzMEkDNzMzMzMz8PzMzMzMzMx1AAAAAAAAAKkCamZmZmZkrQGZmZmZmZh5AmpmZmZmZHUDNzMzMzMwUQDMzMzMzMxNAmpmZmZmZFUAAAAAAAAAlQM3MzMzMzBBAZmZmZmZmHkAAAAAAAAAaQGZmZmZmZjBAAAAAAAAAEEAzMzMzMzMTQAAAAAAAACBAzczMzMzMHkAzMzMzMzMiQDMzMzMzMyxAMzMzMzMzIEAAAAAAAAAWQDMzMzMzMyNAzczMzMzMGkCamZmZmZkhQAAAAAAAACRAMzMzMzMzF0CamZmZmZkhQJqZmZmZmfE\u002fAAAAAAAAFEDNzMzMzMwYQM3MzMzMzCdAzczMzMzMK0DNzMzMzMwnQJqZmZmZmSBAzczMzMzMBEAzMzMzMzMZQM3MzMzMzCBAMzMzMzMzK0BmZmZmZmYkQJqZmZmZmQ1AAAAAAAAAIkCamZmZmZkNQJqZmZmZmSlAMzMzMzMzI0AzMzMzMzMgQGZmZmZmZiZAzczMzMzMLUAzMzMzM7MzQAAAAAAAAChAZmZmZmZmKEAzMzMzMzMvQM3MzMzMzBxAZmZmZmZmL0AAAAAAAAAgQDMzMzMzMw9AAAAAAAAAJkAAAAAAAAAaQGZmZmZmZiRAAAAAAACANUCamZmZmZn5P5qZmZmZmRtAMzMzMzMzA0DNzMzMzMwgQJqZmZmZmSJAZmZmZmZmGECamZmZmZklQAAAAAAAABZAZmZmZmbmOkAzMzMzMzMZQDMzMzMzMylAZmZmZmZmJkCamZmZmZn5PwAAAAAAABhAMzMzMzMzK0AzMzMzMzMbQGZmZmZmZi5AzczMzMzMKEAAAAAAAAAnQJqZmZmZmSJAzczMzMzMGECamZmZmZkmQAAAAAAAAC1AAAAAAAAAL0AAAAAAAAAkQGZmZmZmZilAAAAAAAAAHkCamZmZmZkqQAAAAAAAABxAZmZmZmZmKEDNzMzMzMwuQGZmZmZmZidAZmZmZmZmEkCamZmZmZkwQAAAAAAAACpAZmZmZmZmHkCamZmZmZksQJqZmZmZmQ1AZmZmZmZmHkAzMzMzMzMfQJqZmZmZmSJAZmZmZmZmI0CamZmZmZkiQJqZmZmZmRdAmpmZmZmZGUDNzMzMzMwaQDMzMzMzM\u002fM\u002fmpmZmZmZ6T8zMzMzMzMpQJqZmZmZmSZAMzMzMzMzIUBmZmZmZmYGQM3MzMzMzB5AMzMzMzMzG0AAAAAAAAAlQJqZmZmZmRVAAAAAAAAADEAzMzMzMzMXQAAAAAAAAC1AMzMzMzMzJUCamZmZmZkJQM3MzMzMzAxAZmZmZmZmHkCamZmZmZkdQGZmZmZmZhxAZmZmZmZmKUAzMzMzMzMfQGZmZmZmZhpAZmZmZmZmFkCamZmZmZkgQM3MzMzMzBxAMzMzMzMzHUCamZmZmZkoQDMzMzMzMxVAmpmZmZmZKEAAAAAAAAApQAAAAAAAAB5AmpmZmZmZGUAAAAAAAAASQDMzMzMzMyJAZmZmZmZmK0DNzMzMzMwlQM3MzMzMzCpAZmZmZmZmFkBmZmZmZmYlQGZmZmZmZhJAZmZmZmZmFkAzMzMzMzMiQDMzMzMzMx1AAAAAAAAAKECamZmZmZkhQDMzMzMzMyJAAAAAAAAAKECamZmZmZkhQGZmZmZmZh5AAAAAAAAAKkBmZmZmZmYnQJqZmZmZmSJAMzMzMzMzGUCamZmZmZkbQGZmZmZmZipAZmZmZmZmIkAAAAAAAAAaQM3MzMzMzCZAmpmZmZmZFUAAAAAAAAAWQJqZmZmZmS9AZmZmZmZmIkBmZmZmZmbmPwAAAAAAACdAMzMzMzMzF0DNzMzMzMwoQAAAAAAAACdAmpmZmZmZJ0DNzMzMzMwjQDMzMzMzMy9AmpmZmZmZH0BmZmZmZmYUQAAAAAAAgDJAmpmZmZmZIEBmZmZmZmYUQGZmZmZmZhhAMzMzMzMzK0AAAAAAAAAEQGZmZmZmZiJAmpmZmZmZGUAzMzMzMzMqQAAAAAAAABBAAAAAAAAAIkBmZmZmZmYlQJqZmZmZmS5AMzMzMzMzEUAzMzMzMzMsQJqZmZmZmStAAAAAAAAAJUBmZmZmZmYyQGZmZmZmZidAMzMzMzMzKUDNzMzMzMwpQDMzMzMzMylAzczMzMzMHkAAAAAAAIAwQGZmZmZmZhJAZmZmZmZmI0BmZmZmZmYcQGZmZmZmZiJAZmZmZmZmAkDNzMzMzMwkQJqZmZmZmR9AMzMzMzMzIkBmZmZmZmYoQGZmZmZmZiVAzczMzMzM\u002fD+amZmZmZkgQJqZmZmZmSxAAAAAAAAAGECamZmZmRkyQDMzMzMzMyhAmpmZmZmZHUDNzMzMzEw2QM3MzMzMzCFAZmZmZmZmGEBmZmZmZmYmQJqZmZmZmRlAAAAAAAAACEAzMzMzMzMsQM3MzMzMzCtAmpmZmZmZI0AAAAAAAAAyQM3MzMzMzC9AzczMzMzMI0DNzMzMzMwqQGZmZmZmZjpAmpmZmZmZI0BmZmZmZmYpQAAAAAAAABxAzczMzMzMFkDNzMzMzMwMQJqZmZmZmSFAMzMzMzMzEUDNzMzMzMwnQAAAAAAAACZAZmZmZmZmGkBmZmZmZmYYQGZmZmZmZhRAMzMzMzMzF0DNzMzMzMwqQJqZmZmZmSpAmpmZmZmZLECamZmZmZkiQDMzMzMzMyBAMzMzMzMzIECamZmZmZkbQDMzMzMzMyZAZmZmZmZmIUAAAAAAAAAaQJqZmZmZmQ1AZmZmZmZmJEBmZmZmZmYsQM3MzMzMzCRAzczMzMzMIUDNzMzMzMwQQDMzMzMzMyhAmpmZmZmZIkAzMzMzMzMuQAAAAAAAgDVAmpmZmZmZFUDNzMzMzMwuQDMzMzMzMzRAmpmZmZmZJ0DNzMzMzMwvQDMzMzMzMx9AMzMzMzMzG0AzMzMzMzMhQJqZmZmZmRdAmpmZmZmZ6T9mZmZmZmYYQM3MzMzMTDJAzczMzMzMAEAAAAAAAAAmQGZmZmZmZiRAZmZmZmZmIUAzMzMzMzMVQDMzMzMzMyBAAAAAAACANEDNzMzMzMwWQGZmZmZmZitAmpmZmZmZH0AAAAAAAAAnQM3MzMzMzAhAzczMzMzMKECamZmZmZkbQAAAAAAAACNAZmZmZmZmEkAAAAAAAAAvQJqZmZmZmQ1AmpmZmZmZIUAAAAAAAAAjQJqZmZmZmSRAMzMzMzMzKkCamZmZmZkkQAAAAAAAACdAAAAAAAAAI0CamZmZmZkfQM3MzMzMzCFAzczMzMzMLkCamZmZmZknQAAAAAAAAC5AMzMzMzMzIEBmZmZmZmYlQM3MzMzMzCZAzczMzMzMHkBmZmZmZmYYQAAAAAAAACtAAAAAAAAAKkBmZmZmZmYtQGZmZmZmZhpAZmZmZmZmFkDNzMzMzMwYQM3MzMzMzDJA"},"yaxis":"y","type":"scatter"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"Fast Speed Rate"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"Barrel Rate"}},"legend":{"tracegroupgap":0},"title":{"text":"Decision Tree Regression of Fast Swing Rate vs Barrel Rate"},"shapes":[{"line":{"color":"blue","dash":"dash","width":2},"name":"Decision Tree Threshold","type":"line","x0":35.35000038146973,"x1":35.35000038146973,"y0":0,"y1":26.9}],"annotations":[{"arrowhead":2,"ax":0,"ay":-40,"font":{"color":"green"},"showarrow":true,"text":"Threshold: 35.35%","x":35.35000038146973,"y":26.9}]},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('ccc7b6e4-919f-4ac6-b0c7-545d0562d980');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
<p>Decision Tree Regression Plot of Fast Swing Rate vs Barrel Rate</p>
</div>
</div>
<p>A single split might not be enough to capture the complexity of the data. Let’s try a deeper decision tree with a maximum depth of 2. This will allow us to create more groups based on fast swing rate and barrel rate.</p>
<div id="decision-tree-regression-plot-2" class="cell" data-execution_count="7">
<details class="code-fold">
<summary>Code</summary>
<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"><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="cb10-2"></span>
<span id="cb10-3">X_feature_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;">'fast_swing_rate'</span></span>
<span id="cb10-4">y_feature_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;">'barrel_batted_rate'</span></span>
<span id="cb10-5"></span>
<span id="cb10-6">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[[X_feature_name]]</span>
<span id="cb10-7">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[y_feature_name]</span>
<span id="cb10-8"></span>
<span id="cb10-9">tree_model_d2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DecisionTreeRegressor(max_depth<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>, 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-10">tree_model_d2.fit(X, y)</span>
<span id="cb10-11">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'group'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tree_model_d2.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">apply</span>(X)</span>
<span id="cb10-12"></span>
<span id="cb10-13">group_analysis <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'group'</span>).agg(</span>
<span id="cb10-14">    min_swing_rate<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(X_feature_name, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'min'</span>),</span>
<span id="cb10-15">    max_swing_rate<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(X_feature_name, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'max'</span>),</span>
<span id="cb10-16">    avg_barrel_rate<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(y_feature_name, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean'</span>),</span>
<span id="cb10-17">    player_count<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;">'player_id'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'count'</span>)</span>
<span id="cb10-18">).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;">'min_swing_rate'</span>).reset_index()</span>
<span id="cb10-19"></span>
<span id="cb10-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--- Analysis of Player Groups (from depth-2 tree) ---"</span>)</span>
<span id="cb10-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(group_analysis)</span></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>--- Analysis of Player Groups (from depth-2 tree) ---
   group  min_swing_rate  max_swing_rate  avg_barrel_rate  player_count
0      2             0.2             7.9         5.116867            83
1      3             8.1            35.2         8.957798           218
2      5            35.5            52.6        11.811429            70
3      6            52.7            78.0        15.351020            49</code></pre>
</div>
</div>
<p>In the first pile were the monks, the 83 players who swung fast at less than 8% of pitches. Their reward for this monastic patience? A barrel rate of 5%. Then you had the great mass of players, the 218 guys who followed the rules and swung fast at a “normal” rate. They did a little better, barreling the ball about 9% of the time. This is where it should have ended. But the machine kept splitting.</p>
<p>The model found a group of 70 hitters who were…antsy. They swung at over a third of the pitches they saw. The old scout would have benched them for their lack of discipline. The machine, however, noticed their barrel rate had jumped to nearly 12%. Interesting.</p>
<p>Then it found the last group. A tiny cohort of 49 players who were, by any traditional measure, completely out of their minds. These guys swung at everything. More than half the pitches thrown to them, they were hacking at. They were the hitters your pitching coach warned you about, the ones who would chase a ball if you rolled it to the plate. And what was their reward for this utter lack of discipline? A barrel rate of over 15%. An elite, All-Star-level number. Although some outliers were present. Take for example, 2025 Julio Rodriguez, who has a fast swing rate of 60% but a barrel rate of 7.7%.</p>
<p>Below is a bar chart that visualizes the average barrel rate for each group. The x-axis shows the fast swing rate ranges, and the y-axis shows the average barrel rate for each group. The groups are color-coded based on their fast swing rate ranges.</p>
<div id="cell-decision-tree-regression-plot-3" class="cell" data-execution_count="8">
<details class="code-fold">
<summary>Code</summary>
<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">plt.style.use(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seaborn-v0_8-whitegrid'</span>)</span>
<span id="cb12-2">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<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>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb12-3"></span>
<span id="cb12-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create labels for the x-axis based on the swing rate ranges</span></span>
<span id="cb12-5">group_labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb12-6">    <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>row<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>min_swing_rate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">% - </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>row<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>max_swing_rate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">(n=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>row<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>player_count<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="cb12-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> index, row <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> group_analysis.iterrows()</span>
<span id="cb12-8">]</span>
<span id="cb12-9"></span>
<span id="cb12-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create the bar chart</span></span>
<span id="cb12-11">bars <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ax.bar(</span>
<span id="cb12-12">    group_labels,</span>
<span id="cb12-13">    group_analysis[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'avg_barrel_rate'</span>],</span>
<span id="cb12-14">    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;">'#0a7ff5'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#e6f0fa'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#fae6e6'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#fa5f5f'</span>],</span>
<span id="cb12-15">    edgecolor<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></span>
<span id="cb12-16">)</span>
<span id="cb12-17"></span>
<span id="cb12-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add labels and titles</span></span>
<span id="cb12-19">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Fast Swing Rate'</span>, fontsize<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;">12</span>)</span>
<span id="cb12-20">ax.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Average Barrel Rate (%)'</span>, fontsize<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;">12</span>)</span>
<span id="cb12-21">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Player Barrel Rate Groups by Fast Swing Rate'</span>, fontsize<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;">16</span>, pad<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="cb12-22">ax.tick_params(axis<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;">'x'</span>, labelsize<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="cb12-23"></span>
<span id="cb12-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add text labels on top of the bars</span></span>
<span id="cb12-25"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> bar <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> bars:</span>
<span id="cb12-26">    yval <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> bar.get_height()</span>
<span id="cb12-27">    ax.text(bar.get_x() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> bar.get_width()<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;">2.0</span>, yval <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 class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>yval<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">%'</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;">'center'</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;">'bottom'</span>, fontsize<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;">12</span>)</span>
<span id="cb12-28"></span>
<span id="cb12-29">plt.tight_layout()</span>
<span id="cb12-30">plt.savefig(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'decision_tree_3_groups.png'</span>)</span>
<span id="cb12-31">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="decision-tree-regression-plot-3" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/fast-swings-and-barrels/index_files/figure-html/decision-tree-regression-plot-3-output-1.png" width="854" height="375" class="figure-img"></p>
<figcaption>Decision Tree Regression Plot of Fast Swing Rate vs Barrel Rate with Average Barrel Rates</figcaption>
</figure>
</div>
</div>
</div>
<div id="1f40ecb1" class="cell" data-execution_count="9">
<details class="code-fold">
<summary>Code</summary>
<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"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># t-test for the four groups</span></span>
<span id="cb13-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Extract barrel rates for each group</span></span>
<span id="cb13-3">group_0 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'group'</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;">2</span>][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'barrel_batted_rate'</span>]</span>
<span id="cb13-4">group_1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'group'</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;">3</span>][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'barrel_batted_rate'</span>]</span>
<span id="cb13-5">group_2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'group'</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;">5</span>][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'barrel_batted_rate'</span>]</span>
<span id="cb13-6">group_3 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'group'</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;">6</span>][<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'barrel_batted_rate'</span>]</span>
<span id="cb13-7"></span>
<span id="cb13-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Perform t-tests</span></span>
<span id="cb13-9">ttest_01 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ttest_ind(group_0, group_1, equal_var<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="cb13-10">ttest_12 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ttest_ind(group_1, group_2, equal_var<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="cb13-11">ttest_23 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ttest_ind(group_2, group_3, equal_var<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="cb13-12"></span>
<span id="cb13-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Display results</span></span>
<span id="cb13-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"--- T-Test Results ---"</span>)</span>
<span id="cb13-15"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Group 0 vs Group 1: t-statistic = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>ttest_01<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>statistic<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, p-value = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>ttest_01<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>pvalue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb13-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Group 1 vs Group 2: t-statistic = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>ttest_12<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>statistic<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, p-value = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>ttest_12<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>pvalue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb13-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Group 2 vs Group 3: t-statistic = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>ttest_23<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>statistic<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, p-value = </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>ttest_23<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>pvalue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>--- T-Test Results ---
Group 0 vs Group 1: t-statistic = -10.56, p-value = 0.0000
Group 1 vs Group 2: t-statistic = -6.97, p-value = 0.0000
Group 2 vs Group 3: t-statistic = -5.07, p-value = 0.0000</code></pre>
</div>
</div>
</section>
</section>
<section id="conclusion" class="level1">
<h1>Conclusion</h1>
<p>Of course, a walk was as good as a hit. The quants had proven that a decade ago, and it was the one piece of common knowledge that was actually, you know, true. Getting on base for free was a foundational good.</p>
<p>But that truth had created a dangerous piece of collateral wisdom: that patience, in all its forms, was a virtue. That the same mindset that let you take ball four was the one you should use when a pitcher threw you something hittable.</p>
<p>The data, however, saw a clean line in the sand. It wasn’t about patience versus aggression; it was about knowing when to be which. The analysis didn’t argue against the value of a walk—it argued against the crippling passivity that had been mistaken for discipline.</p>
<p>The most valuable players weren’t just patient or just aggressive; they were both. They had the discipline of a monk until the moment they decided to swing. And at that moment, they had the fury of a barbarian. The rest of the league, stuck in the middle, was playing the wrong game entirely.</p>
<p>Of course barrels are not the only thing that matters in baseball. There are many other factors that contribute to a player’s success, such as plate discipline, contact rate, and defensive skills. However, understanding the relationship between swing speed and barrel rate can provide valuable insights into player performance and help teams make better decisions. I leave you with a clip of Julio Rodriguez: a fast swinger who hasn’t quite found his stride in 2025. However, he is still a young player with a lot of potential. With the right adjustments, he could become one of the best hitters in the league.</p>
<iframe src="https://streamable.com/m/bailey-ober-in-play-run-s-to-julio-rodriguez?partnerId=web_video-playback-page_video-share" width="720" height="415">
</iframe>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->


</section>

<div id="quarto-appendix" class="default"><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" data-entry-spacing="0">
<div id="ref-mlb" class="csl-entry">
<span>“Standard <span>Stats</span> <span></span> <span>Glossary</span>.”</span> 2025. <em>MLB.com</em>. <a href="https://www.mlb.com/glossary/statcast/barrel">https://www.mlb.com/glossary/statcast/barrel</a>.
</div>
</div></section></div> ]]></description>
  <category>scikit-learn</category>
  <category>regression</category>
  <category>MLB</category>
  <guid>https://runningonnumbers.com/posts/fast-swings-and-barrels/</guid>
  <pubDate>Thu, 17 Jul 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/fast-swings-and-barrels/flamebat.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>Logistic Regression</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/logistic-regression/</link>
  <description><![CDATA[ 





<iframe src="https://streamable.com/m/dat-viz-juan-soto-s-two-run-home-run?partnerId=web_video-playback-page_video-share" width="720" height="415">
</iframe>
<section id="introduction" class="level1">
<h1>Introduction</h1>
<p>Last <a href="https://runningonnumbers.com/posts/ops-linear-regression/">article</a>, we introduced linear regression and applied it to predict MLB teams’ runs scored given OPS. Linear regression is great at predicting numerical values. For example, it can predict runs scored given OPS. However, what happens if we want to move away from predicting continuous values and do binary classification? How can we predict whether a batter’s swing mechanics will result in a <a href="https://www.mlb.com/glossary/statcast/hard-hit-rate">“hard-hit”</a> batted ball? We are going to have to turn to logistic regression!</p>
<p>Contrary to its name, logistic regression is a classification technique (you will see where the regression part comes from). Logistic regression involves a probabilistic view of classification. This binary classification method maps a data point to a probabilistic value in the range 0 to 1. Let’s dig into some mathematical formalities.</p>
</section>
<section id="logistic-regression" class="level1">
<h1>Logistic Regression</h1>
<section id="preliminaries" class="level2">
<h2 class="anchored" data-anchor-id="preliminaries">Preliminaries</h2>
<p>“Never tell me the odds” - Han Solo.</p>
<p>The average movie watcher could hear this quote with a slight alteration, where the word “odds” is replaced by “probability,” and they would not bat an eye. However, a statistician would have an issue with substituting the word “odds” with “probability.” While in layman terms they both share similar meaning, in mathematics they are defined distinctly.</p>
<p><img src="https://runningonnumbers.com/posts/logistic-regression/han.jpeg" class="img-fluid"></p>
<p>Odds are a transformation of probabilities - they are another way to think about probabilities. More formally, <img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bodds%7D%20=%20%5Cfrac%7Bp%7D%7B1-p%7D"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?p"> denotes some probability value between 0 and 1, and <img src="https://latex.codecogs.com/png.latex?1-p"> denotes the complement. Think of it as the probability of something happening divided by the probability of it not happening. If given some event, <img src="https://latex.codecogs.com/png.latex?E">, where the odds are <img src="https://latex.codecogs.com/png.latex?x"> to <img src="https://latex.codecogs.com/png.latex?y">, then that means <img src="https://latex.codecogs.com/png.latex?Odds(E)=%5Cfrac%7Bx%7D%7By%7D">. Subsequently, <img src="https://latex.codecogs.com/png.latex?P(E)=%5Cfrac%7Bx%7D%7Bx+y%7D">. The range of possible values for odds becomes 0 to <img src="https://latex.codecogs.com/png.latex?%5Cinfty">. When using probability values between 0 and 1, the range of odds becomes (0,1). Observe that this is an open interval. If <img src="https://latex.codecogs.com/png.latex?p=1">, then the denominator becomes <img src="https://latex.codecogs.com/png.latex?1-1%20=%200">. We cannot divide by zero, so the upper bound is undefined at 1. When <img src="https://latex.codecogs.com/png.latex?p=0">, we get <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B0%7D%7B1%7D=0">. If we are going to do any regressions of this sort, we will need to expand our real number bounds.</p>
<p>To get an unbounded range, we introduce the logit function. The logit function takes in a value between 0 and 1 and maps it to a value between <img src="https://latex.codecogs.com/png.latex?-%5Cinfty"> and <img src="https://latex.codecogs.com/png.latex?%5Cinfty">.</p>
<p><img src="https://latex.codecogs.com/png.latex?z%20=%20%5Clog_e%7B%5Cfrac%7Bp%7D%7B1-p%7D%7D."></p>
<p>Below is a plot for what the logit function looks like.</p>
<div id="cell-fig-logit" class="cell" data-execution_count="1">
<details class="code-fold">
<summary>Code</summary>
<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="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-2"><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-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</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>
<span id="cb1-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># x values</span></span>
<span id="cb1-7">p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.001</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.999</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)</span>
<span id="cb1-8"></span>
<span id="cb1-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># calculate the logit function. np uses base e by default.</span></span>
<span id="cb1-10">logit_p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.log(p <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 class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p))</span>
<span id="cb1-11">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Probability (p)'</span>: p, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Logit(p)'</span>: logit_p})</span>
<span id="cb1-12"></span>
<span id="cb1-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># plotting</span></span>
<span id="cb1-14">plt.figure(figsize<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;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb1-15">sns.lineplot(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;">'Probability (p)'</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;">'Logit(p)'</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, 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;">'blue'</span>)</span>
<span id="cb1-16">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Logit Function'</span>, fontsize<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;">16</span>)</span>
<span id="cb1-17">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Probability (p)'</span>, fontsize<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;">14</span>)</span>
<span id="cb1-18">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Logit(p) = ln(p / (1 - p))'</span>, fontsize<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;">14</span>)</span>
<span id="cb1-19">plt.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, linestyle<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>, 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.7</span>)</span>
<span id="cb1-20"></span>
<span id="cb1-21">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-logit" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-logit-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/logistic-regression/index_files/figure-html/fig-logit-output-1.png" width="667" height="386" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-logit-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Logit function
</figcaption>
</figure>
</div>
</div>
</div>
<p>Awesome. We have ourselves a function that maps values from (0,1) to <img src="https://latex.codecogs.com/png.latex?(-%5Cinfty,%5Cinfty)">. But what if we want the inverse? Map values from <img src="https://latex.codecogs.com/png.latex?(-%5Cinfty,%5Cinfty)"> to <img src="https://latex.codecogs.com/png.latex?(0,1)."> We simply take the inverse of the logit function. This yields the <strong>Logistic Function.</strong></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Balign*%7D%0A%20%20%20%20z%20&amp;=%20%5Clog_e%7B%5Cfrac%7Bp%7D%7B1=p%7D%7D%20%5C%5C%0A%20%20%20%20e%5Ez%20&amp;=%20%5Cfrac%7Bp%7D%7B1-p%7D%20%5C%5C%0A%20%20%20%20e%5Ez%20(1-p)%20&amp;=%20p%20%5C%5C%0A%20%20%20%20e%5Ez%20-%20e%5Ez%20p%20&amp;=%20p%20%5C%5C%0A%20%20%20%20e%5Ez%20&amp;=%20p%20+%20e%5Ez%20p%20%5C%5C%0A%20%20%20%20e%5Ez%20&amp;=%20p(1+e%5Ez)%20%5C%5C%0A%20%20%20%20%5Cfrac%7Be%5Ez%7D%7B(1+e%5Ez)%7D%20&amp;=%20p%20%5C%5C%0A%20%20%20%20p%20&amp;=%20%5Cfrac%7Be%5Ez%7D%7B(1+e%5Ez)%7D%20%5C%5C%0A%20%20%20%20p%20&amp;=%20%5Cfrac%7B1%7D%7B(1/e%5Ez+1)%7D%20%5C%5C%0A%20%20%20%20p%20&amp;=%20%5Cfrac%7B1%7D%7B(e%5E%7B-z%7D+1)%7D%0A%5Cend%7Balign*%7D%0A"></p>
<p>This below is a plot of the logistic function. This is also known as the sigmoid curve.</p>
<div id="cell-fig-logistic" class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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 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="cb2-2"><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="cb2-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb2-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="cb2-5"></span>
<span id="cb2-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># x values</span></span>
<span id="cb2-7">p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.001</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.999</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)</span>
<span id="cb2-8"></span>
<span id="cb2-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># calculate the logit function. np uses base e by default.</span></span>
<span id="cb2-10">logit_p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.log(p <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 class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> p))</span>
<span id="cb2-11">logistic_p <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 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 class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>logit_p))</span>
<span id="cb2-12">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'logits (z)'</span>: logit_p, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'p'</span>: logistic_p})</span>
<span id="cb2-13"></span>
<span id="cb2-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># plotting</span></span>
<span id="cb2-15">plt.figure(figsize<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;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb2-16">sns.lineplot(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;">'logits (z)'</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;">'p'</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>data, 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;">'blue'</span>)</span>
<span id="cb2-17">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Logistic Function'</span>, fontsize<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;">16</span>)</span>
<span id="cb2-18">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Logits (z)'</span>, fontsize<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;">14</span>)</span>
<span id="cb2-19">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Probability (p)'</span>, fontsize<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;">14</span>)</span>
<span id="cb2-20">plt.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, linestyle<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>, 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.7</span>)</span>
<span id="cb2-21"></span>
<span id="cb2-22">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-logistic" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-logistic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/logistic-regression/index_files/figure-html/fig-logistic-output-1.png" width="669" height="386" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-logistic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Logistic function
</figcaption>
</figure>
</div>
</div>
</div>
<p>So why go through all of this work of mapping values from one range to another? The main reason is so that we can enable linear modeling. Recall from <a href="https://runningonnumbers.com/posts/ops-linear-regression/">linear regression</a>, any value can be mapped to an output – linear regressions are unbounded. However, probabilities pose a challenge in that they are bounded between 0 and 1. The logit function solves this issue by transforming the probability space into log-odds. We can now predict log-odd values, which implicitly means we can predict probabilities.</p>
</section>
<section id="using-a-logistic-regression-model" class="level2">
<h2 class="anchored" data-anchor-id="using-a-logistic-regression-model">Using a Logistic Regression Model</h2>
<p>Consider a vector <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> in (d+1)-dimensional feature space. For any given point (<img src="https://latex.codecogs.com/png.latex?x">) in the feature space, we project it onto <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> to convert it into a real number <img src="https://latex.codecogs.com/png.latex?z"> in the range (<img src="https://latex.codecogs.com/png.latex?-%5Cinfty,%20%5Cinfty">). <img src="https://latex.codecogs.com/png.latex?z=%5Ctheta_0%20+%20%5Ctheta_1%20x_1%20+%20%5Cdots%20+%20%5Ctheta_d%20x_d."> <img src="https://latex.codecogs.com/png.latex?z=%5Ctheta%20%5Ccdot%20x%20=%5Ctheta%5ET%20x."> Now that we have <img src="https://latex.codecogs.com/png.latex?z">, we can map it to 0 to 1 using the logistic (sigmoid) function. <img src="https://latex.codecogs.com/png.latex?p=y(x)=%5Csigma(z)%20=%20%5Cfrac%7B1%7D%7B1+e%5E%7B-z%7D%7D."></p>
<p>For example, let’s condier a first-order model.</p>
<p><img src="https://latex.codecogs.com/png.latex?z=%5Ctheta_0%20+%20%5Ctheta_1%20x_1."></p>
<p><img src="https://latex.codecogs.com/png.latex?p%20=%20%5Csigma(z)%20=%20%5Cfrac%7B1%7D%7B1+e%5E%7B-(%5Ctheta_0%20+%20%5Ctheta_1%20x_1)%7D%7D."> Oh look! A linear regression tucked away in our logistic function.</p>
<p>So with <img src="https://latex.codecogs.com/png.latex?p"> being a value between 0 and 1, we can model class probability. More formally,</p>
<p><img src="https://latex.codecogs.com/png.latex?p(C=1%20%7C%20x)%20=%20%5Csigma(%5Ctheta%5ETx)%20=%20%5Cfrac%7B1%7D%7B1+e%5E%7B-%5Ctheta%5ETx%7D%7D"> with <img src="https://latex.codecogs.com/png.latex?%5Csigma(z)=%5Cfrac%7B1%7D%7B1+e%5E%7B-z%7D%7D."></p>
<p>In a binary classification case, <img src="https://latex.codecogs.com/png.latex?p(C=0%7Cx)"> can be modeled as the complement of <img src="https://latex.codecogs.com/png.latex?p(C=1%7Cx)">. So, <img src="https://latex.codecogs.com/png.latex?p(C=0%7Cx)%20=%201-p(C=1%7Cx)%20=%201-%5Cfrac%7B1%7D%7B1+e%5E%7B-%5Ctheta%5ETx%7D%7D%20=%20%5Cfrac%7Be%5E%7B-%5Ctheta%5ETx%7D%7D%7B1+e%5E%7B-%5Ctheta%5ETx%7D%7D."></p>
<section id="finding-the-best-parameters-with-mle" class="level3">
<h3 class="anchored" data-anchor-id="finding-the-best-parameters-with-mle">Finding the Best Parameters with MLE 🧐</h3>
<p>We have the model but how do we find the optimal parameters, <img src="https://latex.codecogs.com/png.latex?%5Ctheta%5C;">? We use maximum likelihood estimation (MLE).</p>
<p>MLE: <img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bmax%7D_%5Ctheta%20%5C;%20%5Cell%5Cell(w)=%5Ctext%7Bmax%7D_%5Ctheta%20%5Csum_i%20%5Clog%7BP(y%5E%7B(i)%7D%20%7C%20x%5E%7B(i)%7D;%20%5Ctheta)%7D."></p>
<p>If the actual label <img src="https://latex.codecogs.com/png.latex?y%5E%7B(i)%7D"> is true, the equation becomes <img src="https://latex.codecogs.com/png.latex?P(y%5E%7B(i)%20=%20+1%20%7C%20x%5E%7B(i)%7D;%5Ctheta%7D)%20=%20%5Cfrac%7B1%7D%7B1+e%5E%7B-%5Ctheta%5ET%20x%7D%7D."></p>
<p>Otherwise, the equation becomes <img src="https://latex.codecogs.com/png.latex?P(y%5E%7B(i)%20=%20-1%20%7C%20x%5E%7B(i)%7D;%5Ctheta%7D)%20=%201-%5Cfrac%7B1%7D%7B1+e%5E%7B-%5Ctheta%5ET%20x%7D%7D">. Note that the in the binary case, we can set the decision boundary to 0.5. This is when <img src="https://latex.codecogs.com/png.latex?%5Ctheta%5ETx=0."> Thus for the binary case, <img src="https://latex.codecogs.com/png.latex?p(y%5E%7B(i)%7D%7Cx%5E%7B(i);%5Ctheta%7D)%20=%20(p_i)%5E%7By%5E%7B(i)%7D%7D(1-p_i)%5E%7B1-y%5E%7B(i)%7D%7D."></p>
<p>Plugging in the marginal probability property, we get <img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Balign*%7D%0A%5Ctext%7Bmax%7D_%5Ctheta%20%5C;%20%5Cell%5Cell(w)%20&amp;=%20%5Ctext%7Bmax%7D_%5Ctheta%20%5Csum_i%20%5Clog%7BP(y%5E%7B(i)%7D%20%7C%20x%5E%7B(i)%7D;%20%5Ctheta)%7D%20%5C%5C%0A&amp;=%20%5Ctext%7Bmax%7D_%5Ctheta%20%5Csum_i%20%5Clog%7B((p_i)%5E%7By%5E%7B(i)%7D%7D(1-p_i)%5E%7B1-y%5E%7B(i)%7D%7D)%7D%20%5C%5C%0A&amp;=%20%5Ctext%7Bmax%7D_%5Ctheta%20%5Csum_i%20y%5E%7B(i)%7D%5Clog%7Bp_i%7D%20+%20(1-y%5E%7B(i)%7D)%5Clog%7B(1-p_i)%7D%0A%5Cend%7Balign*%7D%0A"> and that’s the final expression for log-likelihood! We can use Gradient Descent (GD) to find the parameters. The derived formula says <code>max</code>, but GD makes the loss as small as possible. To address GD finding the minimum optimum, we negate the loss function.</p>
<p>The gradients themselves are derived by applying the chain rule to the log-loss function. The log-loss function (<img src="https://latex.codecogs.com/png.latex?L">) itself contains the sigmoid function (<img src="https://latex.codecogs.com/png.latex?p=%5Csigma(z)">); inside the sigmoid function is the linear function (<img src="https://latex.codecogs.com/png.latex?z">). Going from out to in, we take the partial derivative using the chain rule. <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B%5Cpartial%20L%7D%7B%5Cpartial%20w_j%7D%20=%20%5Cfrac%7B%5Cpartial%20L%7D%7B%5Cpartial%20p%7D%5Ccdot%20%5Cfrac%7B%5Cpartial%20p%7D%7B%5Cpartial%20z%7D%5Ccdot%20%5Cfrac%7B%5Cpartial%20z%7D%7B%5Cpartial%20w_j%7D."></p>
<p>I’ll leave the derivation as an exercise to the audience. However, I highly encourage it! This is one of the most elegant derivations in machine learning - setting the stage for more advanced techniques. Any computer science student taking a machine learning course should at least do the full derivative once throughout their academic journey.</p>
<p>Hence, binary cross entropy loss (often averaged over all samples) becomes <img src="https://latex.codecogs.com/png.latex?Loss%20=%20-%5Cfrac%7B1%7D%7BN%7D%5Csum_%7Bi=1%7D%5EN%5By%5E%7B(i)%7D%5Clog%7B(p_i)%7D%20+%20(1-y%5E%7B(i)%7D)%5Clog%7B1-p_i%7D%5D."></p>
</section>
</section>
</section>
<section id="baseball-application" class="level1">
<h1>Baseball Application</h1>
<p>Earlier this season, Statcast published their swing path data on <a href="https://baseballsavant.mlb.com/leaderboard/bat-tracking/swing-path-attack-angle">baseballsavant</a>. Three new metrics were introduced: attack angle, attack direction, and swing path tilt. What is special about these new statistics is their level of granularity in measuring a bat swing. It is similar to how indoor golf studios are equipped with all sorts of sensors to track your golf swing (minus the ridiculous upcharge for a 30-min golf lesson).</p>
<p>In messing around with the eye-catching visuals on Baseball Savant, I noticed a dichotomous pattern among batters and their <em>ideal attack angle rate</em> and <em>hard-hit</em> outcome. Take a look at the distribution of batted balls grouped by if they were hard hit. We see a distinct distribution depending on the ideal attack angle rate.</p>
<div id="cell-fig-kde-ideal-attack-angle-rate" class="cell" data-execution_count="3">
<details class="code-fold">
<summary>Code</summary>
<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 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="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb3-3">sns.set_theme()</span>
<span id="cb3-4"></span>
<span id="cb3-5">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bat-tracking-swing-path-year.csv"</span>)</span>
<span id="cb3-6">s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sns.kdeplot(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df, 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;">"ideal_attack_angle_rate"</span>, hue<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;">"is_hit_into_play_hardhit"</span>, fill<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="cb3-7">s.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ideal Attack Angle Rate"</span>)</span>
<span id="cb3-8">s.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Distribution of Hard Hit Outcomes Given Ideal Attack Angle Rate"</span>)</span>
<span id="cb3-9">plt.legend(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;">'Hard Hit'</span>, loc<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;">'upper right'</span>, labels<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 class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'No'</span>])</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-kde-ideal-attack-angle-rate" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-kde-ideal-attack-angle-rate-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/logistic-regression/index_files/figure-html/fig-kde-ideal-attack-angle-rate-output-1.png" width="593" height="455" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-kde-ideal-attack-angle-rate-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: KDE plots of batted ball with ideal attack angle rate and hard hit outcome.
</figcaption>
</figure>
</div>
</div>
</div>
<p>Observe the plot below. The x-axis measures the ideal attack angle rate: a metric indicating how consistently a batter achieves their optimal launch angle. The y-axis is binary: 1 if the ball was hard-hit (typically defined as 95+ mph exit velocity), 0 otherwise. Let’s apply a logistic regression to measure how strongly ideal attack angle rate predicts hard-hit probability, estimate the rate at which the probability transitions, and make probabilistic predictions on new data.</p>
<div id="cell-fig-empirical-log" class="cell" data-execution_count="4">
<details class="code-fold">
<summary>Code</summary>
<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">s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sns.scatterplot(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df, 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;">"ideal_attack_angle_rate"</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;">"is_hit_into_play_hardhit"</span>)</span>
<span id="cb4-2">s.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Is Hard Hit?"</span>)</span>
<span id="cb4-3">s.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ideal Attack Angle Rate"</span>)</span>
<span id="cb4-4">s.set_yticks([<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;">1</span>])</span>
<span id="cb4-5">s.set_yticklabels([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"No"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Yes"</span>])</span>
<span id="cb4-6">s.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Relationship Between Binary Outcome of Hard Hit and Ideal Attack Angle Rate"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-empirical-log" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-empirical-log-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/logistic-regression/index_files/figure-html/fig-empirical-log-output-1.png" width="614" height="455" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-empirical-log-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4: Scatter plots of batted ball with ideal attack angle rate and hard hit outcome.
</figcaption>
</figure>
</div>
</div>
</div>
<p>We build a logistic regression model from scratch.</p>
<div id="a39f478c" class="cell" data-execution_count="5">
<details class="code-fold">
<summary>Code</summary>
<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 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="cb5-2"><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> StandardScaler</span>
<span id="cb5-3"><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="cb5-4"></span>
<span id="cb5-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> LogisticRegressionScratch:</span>
<span id="cb5-6">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Make class for logistic regression model built from scratch using NumPy."""</span></span>
<span id="cb5-7">    <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>, lr<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>, n_iters<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;">1000</span>):</span>
<span id="cb5-8">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lr</span>
<span id="cb5-9">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.n_iters <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> n_iters</span>
<span id="cb5-10">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.weights <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="cb5-11">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.bias <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="cb5-12"></span>
<span id="cb5-13">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> _sigmoid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, z):</span>
<span id="cb5-14">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Call sigmoid activation function."""</span></span>
<span id="cb5-15">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</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 class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.exp(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>z))</span>
<span id="cb5-16"></span>
<span id="cb5-17">    <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>
<span id="cb5-18">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">""" Train the model using gradient descent."""</span></span>
<span id="cb5-19">        n_samples, n_features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.shape</span>
<span id="cb5-20">        </span>
<span id="cb5-21">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 1. Initialize parameters</span></span>
<span id="cb5-22">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.weights <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.zeros(n_features)</span>
<span id="cb5-23">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.bias <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="cb5-24">        </span>
<span id="cb5-25">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 2. Gradient Descent</span></span>
<span id="cb5-26">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.n_iters):</span>
<span id="cb5-27">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate the linear model output</span></span>
<span id="cb5-28">            linear_model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.dot(X, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.weights) <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>.bias</span>
<span id="cb5-29">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Apply the sigmoid function to get probabilities</span></span>
<span id="cb5-30">            y_predicted <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>._sigmoid(linear_model)</span>
<span id="cb5-31">            </span>
<span id="cb5-32">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate the gradients</span></span>
<span id="cb5-33">            dw <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 class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n_samples) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.dot(X.T, (y_predicted <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y))</span>
<span id="cb5-34">            db <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 class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n_samples) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(y_predicted <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y)</span>
<span id="cb5-35">            </span>
<span id="cb5-36">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Update the parameters</span></span>
<span id="cb5-37">            <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.weights <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>.lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> dw</span>
<span id="cb5-38">            <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.bias <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>.lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> db</span>
<span id="cb5-39">            </span>
<span id="cb5-40">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> predict(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, X):</span>
<span id="cb5-41">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""Make predictions on new data."""</span></span>
<span id="cb5-42">        linear_model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.dot(X, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.weights) <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>.bias</span>
<span id="cb5-43">        y_predicted <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>._sigmoid(linear_model)</span>
<span id="cb5-44">        y_predicted_cls <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 class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> y_predicted]</span>
<span id="cb5-45">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> np.array(y_predicted_cls)</span>
<span id="cb5-46"></span>
<span id="cb5-47">X <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;">"ideal_attack_angle_rate"</span>]].values</span>
<span id="cb5-48">y <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;">"is_hit_into_play_hardhit"</span>].values</span>
<span id="cb5-49"></span>
<span id="cb5-50">scaler <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler()</span>
<span id="cb5-51">X_scaled <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> scaler.fit_transform(X)</span>
<span id="cb5-52"></span>
<span id="cb5-53"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># init model</span></span>
<span id="cb5-54">model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LogisticRegressionScratch(lr<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>, n_iters<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;">10000</span>)</span>
<span id="cb5-55">model.fit(X_scaled, y)</span>
<span id="cb5-56"></span>
<span id="cb5-57"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Learned Weights: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>model<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>weights[<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;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb5-58"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Learned Bias: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>model<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>bias<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>Learned Weights: 2.1455
Learned Bias: 0.1103</code></pre>
</div>
</div>
<p>Using the weights, let’s plot the sigmoid curve.</p>
<div id="ce0e7b7b" class="cell" data-execution_count="6">
<details class="code-fold">
<summary>Code</summary>
<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">s <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sns.scatterplot(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df, 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;">"ideal_attack_angle_rate"</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;">"is_hit_into_play_hardhit"</span>)</span>
<span id="cb7-2">s.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Is Hard Hit?"</span>)</span>
<span id="cb7-3">s.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ideal Attack Angle Rate"</span>)</span>
<span id="cb7-4">s.set_yticks([<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;">1</span>])</span>
<span id="cb7-5">s.set_yticklabels([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"No"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Yes"</span>])</span>
<span id="cb7-6"></span>
<span id="cb7-7">x_curve <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ideal_attack_angle_rate"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ideal_attack_angle_rate"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span>).reshape(<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb7-8"></span>
<span id="cb7-9">x_curve_scaled <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> scaler.transform(x_curve)</span>
<span id="cb7-10">z_curve <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.dot(x_curve_scaled, model.weights) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> model.bias</span>
<span id="cb7-11">y_curve <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model._sigmoid(z_curve)</span>
<span id="cb7-12"></span>
<span id="cb7-13">plt.plot(x_curve, y_curve, 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;">'red'</span>, linestyle<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>, linewidth<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>, label<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;">'Logistic Regression Curve'</span>)</span>
<span id="cb7-14">plt.legend()</span>
<span id="cb7-15">plt.grid(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, which<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;">'both'</span>, linestyle<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>, linewidth<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>)</span>
<span id="cb7-16">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div>
<figure class="figure">
<p><img src="https://runningonnumbers.com/posts/logistic-regression/index_files/figure-html/cell-7-output-1.png" width="597" height="435" class="figure-img"></p>
</figure>
</div>
</div>
</div>
<p>The red S-shaped curve on the plot is the model’s prediction. For any given “Ideal Attack Angle Rate” on the x-axis, the curve’s height on the y-axis represents the predicted probability of that swing resulting in a hard-hit ball.</p>
<ul>
<li><p>Where the curve is low, the model predicts a low probability of a hard hit.</p></li>
<li><p>Where the curve is high, the model predicts a high probability of a hard hit.</p></li>
</ul>
<p>The most important point on this curve is the decision boundary, where the probability is exactly 0.5. This is the threshold where the model’s prediction flips from “No” (less than 50% chance) to “Yes” (greater than 50% chance). We can calculate this exact point: it occurs where the linear function z=w⋅x+b is zero. For our model trained on scaled data, this gives us the crossover point for a player’s ideal attack angle rate.</p>
<p>To get a more precise understanding, we need to look at the math. A logistic regression model is a linear model for the log-odds of an event. <img src="https://latex.codecogs.com/png.latex?%5Clog%7B(%5Cfrac%7Bp%7D%7B1-p%7D)=w%5Ccdot%20x%20+%20b%7D"> This equation tells us how the learned weight and bias directly impact those odds. To make the weight intuitive, we convert it from log-odds to an odds ratio by calculating <img src="https://latex.codecogs.com/png.latex?e%5Ew">.</p>
<p>Let’s use the weight our model learned on the scaled data (e.g., a weight of 2.1455). <img src="https://latex.codecogs.com/png.latex?%5Ctext%7BOdds%20ratio%7D%20=%20e%5E%7B2.1455%7D%20%5Capprox%208.57">. For every one standard deviation increase in a player’s ideal_attack_angle_rate, the odds of them getting a hard hit multiply by approximately 8.57.</p>
<p>The bias is 0.1103. This means the odds of a player with an average ideal attack angle rate hitting the ball hard is <img src="https://latex.codecogs.com/png.latex?e%5E%7B0.1103%7D%20%5Capprox%201.116">. This means that for a player with an average ideal attack angle rate, the odds of them hitting the ball hard is about 1.116 to 1, or a 53% chance.</p>
<section id="scikit-learn-example" class="level2">
<h2 class="anchored" data-anchor-id="scikit-learn-example">Scikit-Learn Example</h2>
<p>Last but not least, let’s run <code>sklearn</code> to validate our findings. When given a raw dataset you are going to train a model on, you should always split the data into training and testing sets. This ensures that your model is not overfitting to the training data and can generalize well to unseen data.</p>
<div id="e4605cfd" class="cell" data-execution_count="7">
<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 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="cb8-2"><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> train_test_split</span>
<span id="cb8-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> datasets</span>
<span id="cb8-4"></span>
<span id="cb8-5">X <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;">'ideal_attack_angle_rate'</span>]]</span>
<span id="cb8-6">y <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;">'is_hit_into_play_hardhit'</span>]</span>
<span id="cb8-7"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Raw data shapes: features </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>shape<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;">, labels </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape<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="cb8-8"></span>
<span id="cb8-9">X_train, X_test, y_train, y_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X, y, 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.2</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;">47</span>)</span>
<span id="cb8-10">test_indices <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_test.index <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># to recall later</span></span>
<span id="cb8-11"></span>
<span id="cb8-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Train data shapes: features </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X_train<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape<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;">, labels </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y_train<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape<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="cb8-13"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Test data shapes: features </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X_test<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape<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;">, labels </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>y_test<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape<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></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Raw data shapes: features (1134, 1), labels (1134,)
Train data shapes: features (907, 1), labels (907,)
Test data shapes: features (227, 1), labels (227,)</code></pre>
</div>
</div>
<p>Next, we should clean the data. We will scale the ideal attack angle rate features; this makes our data more normalized.</p>
<div id="24b521ec" class="cell" data-execution_count="8">
<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"><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> StandardScaler</span>
<span id="cb10-2"><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="cb10-3"><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> LogisticRegression</span>
<span id="cb10-4"><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> KFold, cross_val_score</span>
<span id="cb10-5"><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> accuracy_score</span>
<span id="cb10-6"></span>
<span id="cb10-7">pipeline <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Pipeline([</span>
<span id="cb10-8">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'scaler'</span>, StandardScaler()),</span>
<span id="cb10-9">    (<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'model'</span>, LogisticRegression(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;">47</span>)),</span>
<span id="cb10-10">])</span></code></pre></div>
</div>
<p>Now we can fit the model. However, what happens if we overfit on the training data? We can use cross-validation to ensure that our model is robust and generalizes well.</p>
<div id="2276d129" class="cell" data-execution_count="9">
<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">cv <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;">47</span>)</span>
<span id="cb11-2">cv_scores <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cross_val_score(pipeline, X_train, y_train, cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>cv, scoring<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;">'accuracy'</span>)</span>
<span id="cb11-3"></span>
<span id="cb11-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"K-Fold Cross-Validation Scores: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(cv_scores, <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 class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb11-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Average CV Score: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>cv_scores<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> (+/- </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>cv_scores<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>std()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">)"</span>)</span>
<span id="cb11-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>)</span>
<span id="cb11-7"></span>
<span id="cb11-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Now, train the final model on the ENTIRE training set.</span></span>
<span id="cb11-9">pipeline.fit(X_train, y_train)</span>
<span id="cb11-10"></span>
<span id="cb11-11">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipeline.predict(X_test)</span>
<span id="cb11-12">final_accuracy <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> accuracy_score(y_test, y_pred)</span>
<span id="cb11-13"></span>
<span id="cb11-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Final Test Set Accuracy: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>final_accuracy<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>K-Fold Cross-Validation Scores: [0.797 0.841 0.818 0.79  0.807]
Average CV Score: 0.810 (+/- 0.018)
----------------------------------------
Final Test Set Accuracy: 0.802</code></pre>
</div>
</div>
<p>80% accuracy is an ok result for a model trained on a single feature. Now let’s look at the coefficients to see how significant the ideal attack angle rate is.</p>
<div id="52b3680b" class="cell" data-execution_count="10">
<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">model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipeline.named_steps[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'model'</span>]</span>
<span id="cb13-2">coef <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.coef_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb13-3">intercept <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.intercept_[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb13-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Coefficient for Ideal Attack Angle Rate: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>coef[<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;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb13-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Intercept: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>intercept<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb13-6"></span>
<span id="cb13-7">odds_ratios <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.exp(coef)</span>
<span id="cb13-8"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> name, odds <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ideal Attack Angle Rate"</span>], odds_ratios):</span>
<span id="cb13-9">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Odds Ratio for </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>name<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="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>odds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb13-10"></span>
<span id="cb13-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Coefficient for Ideal Attack Angle Rate: 2.1094
Intercept: 0.0900
Odds Ratio for Ideal Attack Angle Rate: 8.244
----------------------------------------</code></pre>
</div>
</div>
<p>An odds ratio of 8.244, which we get by computing <img src="https://latex.codecogs.com/png.latex?(e%5E%7B2.1094%7D)">, means that for every one standard deviation increase in a player’s ideal attack angle rate, the odds of them hitting the ball hard multiply by approximately 8.244. This is a significant relationship, indicating that this feature is a strong predictor of hard-hit outcomes. The intercept of 0.0900 suggests that for a player with an average ideal attack angle rate, the odds of hitting the ball hard are about 1.094 to 1, or a 52.2% chance.</p>
<p>Finally, let’s visualize the model’s predictions on the test set.</p>
<div id="cell-fig-logistic-regression-plot" class="cell" data-execution_count="11">
<details class="code-fold">
<summary>Code</summary>
<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"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb15-2"><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="cb15-3"><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="cb15-4"><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="cb15-5"></span>
<span id="cb15-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># test</span></span>
<span id="cb15-7">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">47</span>)</span>
<span id="cb15-8">y_pred_proba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pipeline.predict_proba(X_test)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb15-9">y_pred_proba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (y_pred_proba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)</span>
<span id="cb15-10"></span>
<span id="cb15-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Create DataFrame and Plot with Seaborn ---</span></span>
<span id="cb15-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Combine the actual outcomes and the feature into a DataFrame</span></span>
<span id="cb15-13">df_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({</span>
<span id="cb15-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Ideal Attack Angle Rate'</span>: X_test.values.flatten(),</span>
<span id="cb15-15">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Hard Hit Actual'</span>: y_test,</span>
<span id="cb15-16">})</span>
<span id="cb15-17">df_test[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Result'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(df_test[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Hard Hit Actual'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> y_pred_proba, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Correct'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Incorrect'</span>)</span>
<span id="cb15-18"></span>
<span id="cb15-19">plt.figure(figsize<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>))</span>
<span id="cb15-20"></span>
<span id="cb15-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use regplot to show the data points and the fitted logistic curve</span></span>
<span id="cb15-22">sns.regplot(</span>
<span id="cb15-23">    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;">'Ideal Attack Angle Rate'</span>,</span>
<span id="cb15-24">    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;">'Hard Hit Actual'</span>,   </span>
<span id="cb15-25">    data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_test,</span>
<span id="cb15-26">    logistic<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="cb15-27">    ci<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Turn off confidence interval for this plot</span></span>
<span id="cb15-28">    y_jitter<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;">.03</span>,</span>
<span id="cb15-29">    scatter_kws<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;">'alpha'</span>: <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'color'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'blue'</span>},</span>
<span id="cb15-30">    line_kws<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;">'color'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'red'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'label'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Fitted Logistic Curve'</span>},</span>
<span id="cb15-31">    scatter<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-32">)</span>
<span id="cb15-33"></span>
<span id="cb15-34"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> jitter(values,j):</span>
<span id="cb15-35">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> values <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.normal(j,<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>,values.shape)</span>
<span id="cb15-36"><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb15-37">df_test[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Hard Hit Actual'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> jitter(df_test[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Hard Hit Actual'</span>], <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.001</span>)</span>
<span id="cb15-38"></span>
<span id="cb15-39">sns.scatterplot(</span>
<span id="cb15-40">    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;">'Ideal Attack Angle Rate'</span>,</span>
<span id="cb15-41">    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;">'Hard Hit Actual'</span>,</span>
<span id="cb15-42">    hue<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;">'Result'</span>,</span>
<span id="cb15-43">    style<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;">'Result'</span>, <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use different markers for correctness</span></span>
<span id="cb15-44">    palette<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;">'Correct'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'blue'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Incorrect'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'red'</span>},</span>
<span id="cb15-45">    data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df_test,</span>
<span id="cb15-46">    s<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="cb15-47">    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></span>
<span id="cb15-48">)</span>
<span id="cb15-49"></span>
<span id="cb15-50">plt.axhline(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</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;">'green'</span>, linestyle<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>, label<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;">'Decision Boundary (0.5)'</span>)</span>
<span id="cb15-51">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Logistic Regression Fit'</span>)</span>
<span id="cb15-52">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Hard Hit (1) or Not (0)'</span>)</span>
<span id="cb15-53">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Ideal Attack Angle Rate Normalized'</span>)</span>
<span id="cb15-54">plt.legend()</span>
<span id="cb15-55">plt.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-logistic-regression-plot" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-logistic-regression-plot-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/logistic-regression/index_files/figure-html/fig-logistic-regression-plot-output-1.png" width="816" height="529" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-logistic-regression-plot-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;5: Logistic Regression Predictions on Test Set
</figcaption>
</figure>
</div>
</div>
</div>
<p>Pretty cool stuff. The red points represent the model’s predictions, while the blue points are the actual labels. The green dashed line indicates the decision boundary at 0.5, where the model predicts a hard hit.</p>
<p>Of course, we can’t win them all. Some players will have swings that don’t translate to hard hits, even if they have a high ideal attack angle rate. Those players are shown in the table below. These are the model misclassifications.</p>
<div id="2d99698d" class="cell" data-execution_count="12">
<details class="code-fold">
<summary>Code</summary>
<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">misclassified <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_test[df_test[<span class="st" style="color: #20794D;
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;">'Incorrect'</span>].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;">'Ideal Attack Angle Rate'</span>)</span>
<span id="cb16-2">df_joined <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> misclassified.join(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;">'inner'</span>, rsuffix<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;">'_misclassified'</span>)</span>
<span id="cb16-3">final_tbl <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_joined[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Ideal Attack Angle Rate'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'is_hit_into_play_hardhit'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'name'</span>]]</span>
<span id="cb16-4">final_tbl.head(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="12">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">Ideal Attack Angle Rate</th>
<th data-quarto-table-cell-role="th">is_hit_into_play_hardhit</th>
<th data-quarto-table-cell-role="th">name</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">551</td>
<td>0.333333</td>
<td>1</td>
<td>Rodgers, Brendan</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">435</td>
<td>0.365854</td>
<td>1</td>
<td>Taveras, Leody</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">43</td>
<td>0.373016</td>
<td>1</td>
<td>Guerrero Jr., Vladimir</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">673</td>
<td>0.380282</td>
<td>1</td>
<td>Vierling, Matt</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">978</td>
<td>0.398438</td>
<td>1</td>
<td>Hoerner, Nico</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>And here are the last 5 misclassifications.</p>
<div id="5e99f975" class="cell" data-execution_count="13">
<details class="code-fold">
<summary>Code</summary>
<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">final_tbl.tail(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="13">
<div>


<table class="dataframe caption-top table table-sm table-striped small" data-quarto-postprocess="true" data-border="1">
<thead>
<tr class="header">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">Ideal Attack Angle Rate</th>
<th data-quarto-table-cell-role="th">is_hit_into_play_hardhit</th>
<th data-quarto-table-cell-role="th">name</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td data-quarto-table-cell-role="th">929</td>
<td>0.617747</td>
<td>0</td>
<td>Garver, Mitch</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">878</td>
<td>0.633071</td>
<td>0</td>
<td>Yastrzemski, Mike</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">559</td>
<td>0.638743</td>
<td>0</td>
<td>Thomas, Lane</td>
</tr>
<tr class="even">
<td data-quarto-table-cell-role="th">828</td>
<td>0.660640</td>
<td>0</td>
<td>Bregman, Alex</td>
</tr>
<tr class="odd">
<td data-quarto-table-cell-role="th">238</td>
<td>0.682573</td>
<td>0</td>
<td>Carroll, Corbin</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
</section>
<section id="conclusion-from-theory-to-insight" class="level1">
<h1>Conclusion: From Theory to Insight</h1>
<p>It all starts with the black box.</p>
<p>Everyone in the game, from the front-office Ivy Leaguers to the Silicon Valley startups trying to sell them something, loves to type .fit() and watch the magic happen. They get an answer, they nod, and they move on. But they have no earthly idea what’s going on inside the box. They’re flying a 747 on autopilot without ever having seen the cockpit.</p>
<p>So we decided to pry the thing open. We went back to the beginning, to the raw, messy mathematics of a logistic regression. Inside, we found this relentless engine called Maximum Likelihood Estimation, a fancy term for a machine built to find the single most plausible story for what the hell is going on in the data. We watched it work, watched the gradients crawl their way down the mountain, each step a tiny, agonizing calculation on the path to the best possible answer. It wasn’t elegant, but it was honest.</p>
<p>Once you’ve built the engine, you want to see what it can do. You want to point it at something. We pointed it at baseball. We fed it a mountain of swing data, and the machine started to hum.</p>
<p>And then it spit out a signal, a signal so loud it was impossible to ignore. Forget what the scouts told you about a “pretty swing.” One number mattered more than the others: ideal_attack_angle_rate. It was right there in the data, a clear, blinking light showing that the players who got their bat on the perfect plane to meet the ball weren’t just making better contact—they were hitting the ball hard.</p>
<p>But here’s the beautiful part. The model didn’t just tell us the two things were connected. It told us the price. It handed us a number that said for every standard deviation a player improved in this one metric—a totally learnable skill—the odds that he’d lace a ball into the gap went up by a multiplier that could change the course of a franchise.</p>
<p>This is the point where you realize logistic regression isn’t just some sorting hat for data. It’s a pair of X-ray specs. It lets you look past the noise and see the hidden architecture of a problem. It gives you an edge that is not only predictive, but that you can actually understand and explain.</p>
<p>Don’t believe me? Go pull up a video of Corbin Carroll hitting a triple. He’s third in the league in ideal attack angle. The machine saw him coming.</p>
<iframe src="https://streamable.com/m/trevor-williams-in-play-no-out-to-corbin-carroll-tdxvup?partnerId=web_video-playback-page_video-share" width="720" height="415">
</iframe>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->

</section>

 ]]></description>
  <category>numpy</category>
  <category>classification</category>
  <category>MLB</category>
  <guid>https://runningonnumbers.com/posts/logistic-regression/</guid>
  <pubDate>Fri, 11 Jul 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/logistic-regression/attack-angle.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>Linear Regression</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/ops-linear-regression/</link>
  <description><![CDATA[ 





<p><img src="https://runningonnumbers.com/posts/ops-linear-regression/ops-main.png" class="img-fluid"></p>
<section id="introduction" class="level1">
<h1>Introduction</h1>
<p>Linear Regression—long before transformers and LLMs, it served as one of the first tools in the machine learning toolbox. Despite the rise of complex models, its role in modern statistical analysis remains essential and unshaken.</p>
<p>Rregression models measure the statistical relationship of an dependent variable (<img src="https://latex.codecogs.com/png.latex?y">), and a series of other variables (<img src="https://latex.codecogs.com/png.latex?x_i">). They are widely used for prediction, estimation, hypothesis testing, and modeling causal relationships. Independate variables serve as inputs into a system and take on different values freely. Dependent variables are those values that change as a consequence of change in other values in the system. <img src="https://latex.codecogs.com/png.latex?X"> can refers to <em>predictor</em> or <em>explanatory variable</em>. <img src="https://latex.codecogs.com/png.latex?Y"> denotes the response variable.</p>
</section>
<section id="first-order-linear-model" class="level1">
<h1>First Order Linear Model</h1>
<p><img src="https://latex.codecogs.com/png.latex?Y=%5Ctheta_0%20+%20%5Ctheta_1%20X"></p>
<p>where Y is the dependent variable, <img src="https://latex.codecogs.com/png.latex?%5Ctheta_0"> is the y-incercept, <img src="https://latex.codecogs.com/png.latex?%5Ctheta_1"> is the slop of the line, and <img src="https://latex.codecogs.com/png.latex?X"> is the independent variable.</p>
<p>This is the standard <img src="https://latex.codecogs.com/png.latex?y=mx%20+%20b"> model taught in middle school.</p>
<p>From this, we can create a hypothesis function (model):</p>
<p><img src="https://latex.codecogs.com/png.latex?h_%5Ctheta(x)%20=%20%5Ctheta_0%20+%20%5Ctheta_1%20x."></p>
<p>Note that we use a lowercase <img src="https://latex.codecogs.com/png.latex?x"> to denote an individual data point. How do we find the optimal <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> coefficients? Sure we can plot the data and eye-ball a drawn line where half of the data points lie above and the other half below the line. But consider an application like baseball data. A historic game like baseball has decades of seasons. If we were to model batting average <img src="https://latex.codecogs.com/png.latex?(%5Cfrac%7B%5Ctext%7Bhits%7D%7D%7B%5Ctext%7Bat-bats%7D%7D)">, it would be impossible to guess the best-fitted line by hand. We need a cleverer method.</p>
<p>We turn to least-squares linear regression. Cost function: <img src="https://latex.codecogs.com/png.latex?Cost(%5Ctheta)%20=%20%5Cfrac%7B1%7D%7B2%5Ctimes%20n%7D%5Csum_%7Bi=0%7D%5E%7Bn%7D(h_%5Ctheta(x%5E%7B(i)%7D)%20-%20y%5E%7B(i)%7D)%5E2."></p>
<p>The cost function is takes the average of square-error differences among all data points. We fit by solving <img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bmin%7D_%5Ctheta%20Cost(%5Ctheta)"> or in other words, the parameters <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> that minimze the mean squared-error (MSE).</p>
<p>Gradient descent is the method we use to find the optimal <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> values. More formally,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Ctheta_j%20=%20%5Ctheta_j%20-%20%5Calpha%20%5Cfrac%7B%5Cpartial%20Cost(%5Ctheta)%7D%7B%5Cpartial%20%5Ctheta_j%7D."></p>
<p><img src="https://latex.codecogs.com/png.latex?%5Calpha"> is the learning rate. Calculus is inescapable. One of its most powerful contributions to humanity is the ability to systematically find optimal values—a cornerstone of decision-making in science, economics, engineering, and machine learning. Let’s solve for <img src="https://latex.codecogs.com/png.latex?%5Ctheta_0"> and <img src="https://latex.codecogs.com/png.latex?%5Ctheta_1"> for first-order linear regression.</p>
<p>We first take the partial derivative with respect to <img src="https://latex.codecogs.com/png.latex?%5Ctheta_j">, <img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Balign*%7D%0A%20%20%20%20%5Cfrac%7B%5Cpartial%20Cost(%5Ctheta)%7D%7B%5Cpartial%20%5Ctheta_j%7D%20&amp;=%20%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20%5Ctheta_j%7D%20%5Cfrac%7B1%7D%7B2n%7D%5Csum_%7Bi=0%7D%5E%7Bn%7D(h_%5Ctheta(x%5E%7B(i)%7D)%20-%20y)%5E2%20%5C%5C%0A%20%20%20%20&amp;=%20%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20%5Ctheta_j%7D%20%5Cfrac%7B1%7D%7B2n%7D%5Csum_%7Bi=0%7D%5E%7Bn%7D((%5Ctheta_0%20+%20%5Ctheta_1%20x)%20-%20y)%5E2%20%5C%5C%0A%20%20%20%20&amp;=%20%5Cfrac%7B1%7D%7B2n%7D%20%5Csum_%7Bi=0%7D%5E%7Bn%7D%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20%5Ctheta_j%7D((%5Ctheta_0%20+%20%5Ctheta_1%20x)%20-%20y)%5E2%20%5C%5C%0A%20%20%20%20&amp;=%20%5Cfrac%7B1%7D%7B2n%7D%5Csum_%7Bi=0%7D%5E%7Bn%7D2((%5Ctheta_0%20+%20%5Ctheta_1%20x)%20-%20y)%20%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20%5Ctheta_j%7D((%5Ctheta_0%20+%20%5Ctheta_1%20x)%20-%20y)%20%5C%5C%0A%20%20%20%20&amp;=%20%5Cfrac%7B1%7D%7B2n%7D%5Csum_%7Bi=0%7D%5E%7Bn%7D2((%5Ctheta_0%20+%20%5Ctheta_1%20x)%20-%20y)%20(%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20%5Ctheta_0%7D%5Ctheta_0%20+%20%20%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20%5Ctheta_1%7D%20%5Ctheta_1%20x)%20%5C%5C%0A%20%20%20%20&amp;=%20%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi=0%7D%5E%7Bn%7D((%5Ctheta_0%20+%20%5Ctheta_1%20x)%20-%20y)%20(%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20%5Ctheta_0%7D%5Ctheta_0%20+%20%20%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20%5Ctheta_1%7D%20%5Ctheta_1%20x)%0A%5Cend%7Balign*%7D%0A"> Hence,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B%5Cpartial%20Cost(%5Ctheta)%7D%7B%5Cpartial%5Ctheta_0%7D%20=%20%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi=0%7D%5E%7Bn%7D((%5Ctheta_0%20+%20%5Ctheta_1%20x)%20-%20y)%20(1)%0A"> and <img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B%5Cpartial%20Cost(%5Ctheta)%7D%7B%5Cpartial%5Ctheta_1%7D%20=%20%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi=0%7D%5E%7Bn%7D((%5Ctheta_0%20+%20%5Ctheta_1%20x)%20-%20y)%20(x%5E%7B(i)%7D).%0A"> Now solve for <img src="https://latex.codecogs.com/png.latex?%5Ctheta_0"> and <img src="https://latex.codecogs.com/png.latex?%5Ctheta_1">. <img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Balign*%7D%0A%20%20%20%20%5Cfrac%7B%5Cpartial%20Cost(%5Ctheta)%7D%7B%5Cpartial%20%5Ctheta_0%7D%20&amp;=%200%20%5C%5C%0A%20%20%20%20%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi=0%7D%5E%7Bn%7D((%5Ctheta_0%20+%20%5Ctheta_1%20x)%20-%20y)%20&amp;%20=0%5C%5C%0A%20%20%20%20%5Csum_%7Bi=0%7D%5E%7Bn%7D%5Ctheta_0%20+%20%5Csum_%7Bi=0%7D%5E%7Bn%7D%5Ctheta_1x%5E%7B(i)%7D%20+%20%5Csum_%7Bi=0%7D%5E%7Bn%7Dy%20&amp;=%200%20%5C%5C%0A%20%20%20%20%5Csum_%7Bi=0%7D%5E%7Bn%7D%5Ctheta_1x%5E%7B(i)%7D%20+%20%5Csum_%7Bi=0%7D%5E%7Bn%7Dy%20&amp;=%20-%5Csum_%7Bi=0%7D%5E%7Bn%7D%5Ctheta_0%20%5C%5C%0A%20%20%20%20%5Csum_%7Bi=0%7D%5E%7Bn%7D%5Ctheta_1x%5E%7B(i)%7D%20+%20%5Csum_%7Bi=0%7D%5E%7Bn%7Dy%20&amp;=%20-n%5Ctheta_0%20%5C%5C%0A%20%20%20%20%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi=0%7D%5E%7Bn%7D%5Ctheta_1x%5E%7B(i)%7D%20+%20%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi=0%7D%5E%7Bn%7Dy%20&amp;=%20%5Ctheta_0%20%5C%5C%0A%20%20%20%20%5Ctheta_1%5Cbar%7Bx%7D%20+%20%5Cbar%7By%7D%20&amp;=%20-%5Ctheta_0%20%5C%5C%0A%20%20%20%20-%20%5Ctheta_1%5Cbar%7Bx%7D%20-%20%5Cbar%7By%7D%20&amp;=%20%5Ctheta_0%20%5C%5C%0A%20%20%20%20%5Ctheta_0%20&amp;=%20%5Cbar%7By%7D%20-%20%5Ctheta_1%5Cbar%7Bx%7D%0A%5Cend%7Balign*%7D%0A"></p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Balign*%7D%0A%20%20%20%20%5Cfrac%7B%5Cpartial%20Cost(%5Ctheta)%7D%7B%5Cpartial%20%5Ctheta_1%7D%20&amp;=%200%20%5C%5C%0A%20%20%20%20%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi=0%7D%5E%7Bn%7D((%5Ctheta_0%20+%20%5Ctheta_1%20x%5E%7B(i)%7D)%20-%20y)%20x%5E%7B(i)%7D%20&amp;%20=0%5C%5C%0A%20%20%20%20%5Csum_%7Bi=1%7D%5E%7Bn%7D%20%5Cleft(%20%5Cbar%7By%7D%20-%20%5Ctheta_1%20%5Cbar%7Bx%7D%20+%20%5Ctheta_1%20x%5E%7B(i)%7D%20-%20y%5E%7B(i)%7D%20%5Cright)%20x%5E%7B(i)%7D%20&amp;%20=0%5C%5C%0A%20%20%20%20%5Csum_%7Bi=1%7D%5E%7Bn%7D%20%5Cleft%5B%20%5Ctheta_1%20(x%5E%7B(i)%7D%20-%20%5Cbar%7Bx%7D)%20+%20(%5Cbar%7By%7D%20-%20y%5E%7B(i)%7D)%20%5Cright%5D%20x%5E%7B(i)%7D%20&amp;%20=0%5C%5C%0A%20%20%20%20%5Ctheta_1%20%5Csum_%7Bi=1%7D%5E%7Bn%7D%20(x%5E%7B(i)%7D%20-%20%5Cbar%7Bx%7D)%20x%5E%7B(i)%7D%20&amp;=%20%5Csum_%7Bi=1%7D%5E%7Bn%7D%20(y%5E%7B(i)%7D%20-%20%5Cbar%7By%7D)%20x%5E%7B(i)%7D%20%5C%5C%0A%20%20%20%20%5Ctheta_1%20&amp;=%20%5Cfrac%7B%5Csum_%7Bi=1%7D%5E%7Bn%7D%20(x%5E%7B(i)%7D%20-%20%5Cbar%7Bx%7D)(y%5E%7B(i)%7D%20-%20%5Cbar%7By%7D)%7D%7B%5Csum_%7Bi=1%7D%5E%7Bn%7D%20(x%5E%7B(i)%7D%20-%20%5Cbar%7Bx%7D)%5E2%7D%0A%5Cend%7Balign*%7D%0A"></p>
<p>Enough math. Let’s code.</p>
</section>
<section id="linear-regression-application-to-baseball-data" class="level1">
<h1>Linear Regression Application to Baseball Data</h1>
<p>Baseball is a game of numbers. There exist several statistics to measure a hitter’s offensive contribution. The simplest and well-known metric is batting average (BA or AVG); <img src="https://latex.codecogs.com/png.latex?BA=%5Cfrac%7B%5Ctext%7BHits%7D%7D%7B%5Ctext%7BAt-bats%7D%7D">. Whlie batting average only considers hits, slugging percentage weights different types of hits, giving more value to extra base hits; <img src="https://latex.codecogs.com/png.latex?SLG=%5Cfrac%7B(1B%20%5Ccdot%201%20+%202B%20%5Ccdot%202%20+%203B%5Ccdot%203%20+%20HR%5Ccdot%204)%7D%7BAB%7D">. On-base percentage (<img src="https://latex.codecogs.com/png.latex?OBP">) “refers to how frequently a batter reachers base per plate appearance.” <span class="citation" data-cites="mlb">(<span>“Standard <span>Stats</span> <span></span> <span>Glossary</span>”</span> 2025)</span>. <img src="https://latex.codecogs.com/png.latex?OPS"> (on-base plus slugging) is an amalgamation of <img src="https://latex.codecogs.com/png.latex?OBP"> and <img src="https://latex.codecogs.com/png.latex?SLG">. That is, <img src="https://latex.codecogs.com/png.latex?OPS=OBP%20+%20SLG">. <img src="https://latex.codecogs.com/png.latex?OPS"> encapsulates a batter’s power and on-base rate. Lastly, there’s weighted on-base average (<img src="https://latex.codecogs.com/png.latex?wOBA">). <img src="https://latex.codecogs.com/png.latex?wOBA"> is an all-empcompasing offensive measurement. Similar to <img src="https://latex.codecogs.com/png.latex?SLG">, <img src="https://latex.codecogs.com/png.latex?wOBA"> weighs batted-events, however, it does so with a different formula. Each batted event (walks, singles, home run, etc.), is weighted by the adjusted run expectancy in the context of a season.</p>
<p>Figure&nbsp;1 illustrates the relationships between various baseball statistics and runs. Observe that the strength of the relationship between the independent variables (<img src="https://latex.codecogs.com/png.latex?AVG,%20OBP,%20SLG,%20OPS,%20wOBA">) and the dependent variable <img src="https://latex.codecogs.com/png.latex?R"> (runs) are not the same.</p>
<div id="cell-fig-scatter-stats" class="cell" data-execution_count="1">
<details class="code-fold">
<summary>Code</summary>
<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="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-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> pybaseball <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> team_batting</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb1-4"></span>
<span id="cb1-5">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> team_batting(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2025</span>)</span>
<span id="cb1-6"></span>
<span id="cb1-7">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> data[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Team"</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;">"R"</span>, <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;">"OBP"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SLG"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OPS"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wOBA"</span>]]</span>
<span id="cb1-8">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> data[(data[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Season"</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;">2020</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> (data[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Season"</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;">2025</span>)]</span>
<span id="cb1-9"></span>
<span id="cb1-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># melt to facetgrid by metrics</span></span>
<span id="cb1-11">long_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> data.melt(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;">"Team"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Season"</span>], value_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;">"AVG"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OBP"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OPS"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SLG"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wOBA"</span>], 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;">"Metric"</span>, 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="cb1-12"></span>
<span id="cb1-13">g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sns.FacetGrid(long_df, 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;">"Metric"</span>, col_wrap<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>, height<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;">4</span>, sharex<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>, sharey<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="cb1-14">g.map_dataframe(sns.scatterplot, 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;">"R"</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-scatter-stats" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-scatter-stats-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/ops-linear-regression/index_files/figure-html/fig-scatter-stats-output-1.png" width="1142" height="758" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-scatter-stats-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Scatter plots of baseball metrics and runs.
</figcaption>
</figure>
</div>
</div>
</div>
<p>We will need to compute the linear model’s weights if we want to accurate prediction of team runs given a statistic. To hold true to our mathematical derivation, we’ll implement our own linear regression model. Of course, ready-made solutions exist in libraries such as <a href="https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html">Scikit-Learn</a>.</p>
<div id="cell-fig-linear-reg" class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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 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="cb2-2"></span>
<span id="cb2-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> LinearRegression:</span>
<span id="cb2-4">    <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>):</span>
<span id="cb2-5">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.slope <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="cb2-6">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.intercept <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="cb2-7"></span>
<span id="cb2-8">    <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>
<span id="cb2-9">        n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(X)</span>
<span id="cb2-10">        x_mean <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean(X)</span>
<span id="cb2-11">        y_mean <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean(y)</span>
<span id="cb2-12">        numerator <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="cb2-13">        denominator <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="cb2-14">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(n):</span>
<span id="cb2-15">            numerator <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> (X[i] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> x_mean) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (y[i] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y_mean)</span>
<span id="cb2-16">            denominator <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> (X[i] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> x_mean) <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="cb2-17">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.slope <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> numerator <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> denominator</span>
<span id="cb2-18">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.intercept <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y_mean <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>.slope <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x_mean</span>
<span id="cb2-19"></span>
<span id="cb2-20">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> predict(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, X):</span>
<span id="cb2-21">        y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []</span>
<span id="cb2-22">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> x <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> X:</span>
<span id="cb2-23">            y_pred.append(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.slope <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> x <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>.intercept)</span>
<span id="cb2-24">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> y_pred</span>
<span id="cb2-25"></span>
<span id="cb2-26">long_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y_pred"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.nan</span>
<span id="cb2-27">model_dict <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {}</span>
<span id="cb2-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Batting Average Model</span></span>
<span id="cb2-29"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> metric <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> [<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;">"OBP"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SLG"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OPS"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wOBA"</span>]:</span>
<span id="cb2-30">    model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression()</span>
<span id="cb2-31">    mask <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> long_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Metric"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> metric</span>
<span id="cb2-32">    X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> long_df.loc[mask, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Value"</span>].to_numpy()</span>
<span id="cb2-33">    y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> long_df.loc[mask, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"R"</span>].to_numpy()</span>
<span id="cb2-34">    model.fit(X, y)</span>
<span id="cb2-35">    model_dict[metric] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model</span>
<span id="cb2-36">    y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.predict(X)</span>
<span id="cb2-37">    long_df.loc[mask, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y_pred"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y_pred</span>
<span id="cb2-38"></span>
<span id="cb2-39">g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sns.FacetGrid(long_df, 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;">"Metric"</span>, col_wrap<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>, height<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;">4</span>, sharex<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>, sharey<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="cb2-40">g.map_dataframe(sns.scatterplot, 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;">"R"</span>)</span>
<span id="cb2-41">g.map_dataframe(sns.lineplot, 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;">"y_pred"</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;">"red"</span>)</span>
<span id="cb2-42">g.set_ylabels(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Predicted Runs"</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-linear-reg" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-linear-reg-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/ops-linear-regression/index_files/figure-html/fig-linear-reg-output-1.png" width="1142" height="758" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-linear-reg-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Scatter plots of baseball metrics and runs with linear regression line.
</figcaption>
</figure>
</div>
</div>
</div>
<p>Suppose we want to predict a team’s runs given a metric. In 2024, Dodgers had a team OPS of 0.781. Let’s use our newly trained OPS linear regression to predict the team runs.</p>
<div id="0d344b60" class="cell" data-execution_count="3">
<details class="code-fold">
<summary>Code</summary>
<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">dodgers_ops <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.781</span></span>
<span id="cb3-2"></span>
<span id="cb3-3">predicted_runs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_dict[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OPS"</span>].predict([dodgers_ops])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb3-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Dodgers predicted runs in 2024: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(predicted_runs)<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="cb3-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Dodgers actual runs in 2024: </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;">842</span><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></code></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>Dodgers predicted runs in 2024: 821
Dodgers actual runs in 2024: 842</code></pre>
</div>
</div>
<p>Not bad! The Dodgers currently have an OPS of .801 in their 2025 season. Based on the OPS model, and assuming the Dodgers maintain their high OPS throughout the remaining season, they are slated to score 860 runs.</p>
<div id="f763517f" class="cell" data-execution_count="4">
<details class="code-fold">
<summary>Code</summary>
<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">dodgers_ops <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.801</span></span>
<span id="cb5-2"></span>
<span id="cb5-3">predicted_runs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_dict[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OPS"</span>].predict([dodgers_ops])[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span></code></pre></div>
</details>
</div>
<p>I’ll have to revisit these models when the 2025 season ends.</p>
</section>
<section id="multivariable-linear-regression" class="level1">
<h1>Multivariable Linear Regression</h1>
<p>Let’s predict exit velocity from swing metrics. This season, Statcast released their swing path and swing length data on <a href="https://baseballsavant.mlb.com/leaderboard/bat-tracking/swing-path-attack-angle">BaseballSavant</a>. Granular bat tracking data can reveal mechanical trends that lendthemselves to batting outcomes.</p>
<p>Observe Figure&nbsp;3. We consider two independent variables: average swing speed and swing length. The dependent variable is average exit velocity.</p>
<div id="cell-fig-scatter-swingmetrics" class="cell" data-execution_count="5">
<details class="code-fold">
<summary>Code</summary>
<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">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"swing-metrics2.csv"</span>)</span>
<span id="cb6-2">sns.scatterplot(df, 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;">"avg_swing_speed"</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;">"avg_swing_length"</span>,hue<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;">"exit_velocity_avg"</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-scatter-swingmetrics" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-scatter-swingmetrics-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/ops-linear-regression/index_files/figure-html/fig-scatter-swingmetrics-output-1.png" width="589" height="429" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-scatter-swingmetrics-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: Scatter plots of average swing speed, swing length, and average exit velocity.
</figcaption>
</figure>
</div>
</div>
</div>
<p>We apply a multivariable linear regression to see if there’s a statistical relationship among average swing speed, swing length, and average exit velocity. To model this relationship, we turn to a vectorized version of the first-order linear regression above. <img src="https://latex.codecogs.com/png.latex?y=X.W"> and <img src="https://latex.codecogs.com/png.latex?W=(X%5ET%5Ccdot%20X)%5E%7B-1%7DX%5ET%5Ccdot%20y">.</p>
<div id="c09bb95a" class="cell" data-execution_count="6">
<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 class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> MVLinearRegression:</span>
<span id="cb7-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>):</span>
<span id="cb7-3">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.W <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="cb7-4"></span>
<span id="cb7-5">    <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>
<span id="cb7-6">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">'''</span></span>
<span id="cb7-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">        X: n x d </span></span>
<span id="cb7-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">        '''</span></span>
<span id="cb7-9">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add bias term to X -&gt; [1 X]</span></span>
<span id="cb7-10">        n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb7-11">        X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.hstack([np.ones((n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)), X])</span>
<span id="cb7-12">        <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>.W <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.inv(X.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> X) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> X.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> y</span>
<span id="cb7-13"></span>
<span id="cb7-14">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> predict(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, X):</span>
<span id="cb7-15">        n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb7-16">        X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.hstack([np.ones((n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)), X])</span>
<span id="cb7-17">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> X <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>.W</span>
<span id="cb7-18"></span>
<span id="cb7-19">df_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"year"</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2025</span>]</span>
<span id="cb7-20">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_train[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"avg_swing_speed"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"avg_swing_length"</span>]].to_numpy()</span>
<span id="cb7-21">y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_train[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"exit_velocity_avg"</span>]].to_numpy().squeeze()</span>
<span id="cb7-22"></span>
<span id="cb7-23"></span>
<span id="cb7-24">model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MVLinearRegression()</span>
<span id="cb7-25">model.fit(X,y)</span>
<span id="cb7-26"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Model weights: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>model<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>W<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="cb7-27"></span>
<span id="cb7-28">df_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df[df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"year"</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;">2025</span>]</span>
<span id="cb7-29">X_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_test[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"avg_swing_speed"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"avg_swing_length"</span>]].to_numpy()</span>
<span id="cb7-30">y_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_test[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"exit_velocity_avg"</span>]].to_numpy().squeeze()</span>
<span id="cb7-31">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.predict(X_test)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Model weights: [51.12674671  0.644755   -1.05884044]</code></pre>
</div>
</div>
<p>Figure&nbsp;4 depicts multivariable linear regression analysis reveals that swing speed and swing length have opposing effects on exit velocity. Swing speed is a strong positive predictor: for every 1 mph increase in average swing speed, exit velocity increases by approximately 0.64 mph, a relationship that is highly statistically significant. In contrast, swing length shows a significant negative association, with each additional unit of swing length reducing exit velocity by about -1.0 mph when holding swing speed constant. This suggests that while higher swing speeds directly contribute to better batted-ball outcomes, longer swings may hinder efficient energy transfer, potentially due to reduced compactness or timing inefficiencies. Overall, the model highlights the importance of optimizing both speed and mechanical efficiency to maximize exit velocity.</p>
<div class="cell" data-execution_count="7">
<details class="code-fold">
<summary>Code</summary>
<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 class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.graph_objects <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> go</span>
<span id="cb9-2"></span>
<span id="cb9-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># --- Create prediction surface ---</span></span>
<span id="cb9-4">x1_range <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(X_test[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), X_test[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)</span>
<span id="cb9-5">x2_range <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(X_test[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>(), X_test[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)</span>
<span id="cb9-6">x1_grid, x2_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.meshgrid(x1_range, x2_range)</span>
<span id="cb9-7">X_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.c_[x1_grid.ravel(), x2_grid.ravel()]</span>
<span id="cb9-8">y_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.predict(X_grid).reshape(x1_grid.shape)</span>
<span id="cb9-9"></span>
<span id="cb9-10">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> go.Figure()</span>
<span id="cb9-11"></span>
<span id="cb9-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Scatter data points</span></span>
<span id="cb9-13">fig.add_trace(go.Scatter3d(</span>
<span id="cb9-14">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>X[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], z<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y,</span>
<span id="cb9-15">    mode<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;">'markers'</span>,</span>
<span id="cb9-16">    marker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</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;">5</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;">'blue'</span>, opacity<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.0</span>),</span>
<span id="cb9-17">    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;">'Data'</span></span>
<span id="cb9-18">))</span>
<span id="cb9-19"></span>
<span id="cb9-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Regression surface</span></span>
<span id="cb9-21">fig.add_trace(go.Surface(</span>
<span id="cb9-22">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>x1_range, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>x2_range, z<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y_grid,</span>
<span id="cb9-23">    colorscale<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;">'Viridis'</span>, opacity<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>,</span>
<span id="cb9-24">    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;">'Regression Plane'</span></span>
<span id="cb9-25">))</span>
<span id="cb9-26"></span>
<span id="cb9-27">fig.update_layout(</span>
<span id="cb9-28">    scene<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb9-29">        xaxis_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;">'Swing Speed'</span>,</span>
<span id="cb9-30">        yaxis_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;">'Swing Length'</span>,</span>
<span id="cb9-31">        zaxis_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;">'Avg Exit Velocity'</span></span>
<span id="cb9-32">    ),</span>
<span id="cb9-33">    margin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(l<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>, r<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>, b<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>, t<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;">40</span>)</span>
<span id="cb9-34">)</span>
<span id="cb9-35"></span>
<span id="cb9-36">fig.show()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div>
</details>
<div id="fig-3dregression" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="7">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-3dregression-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div id="fig-3dregression-1" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-subfloat-fig figure">
<div aria-describedby="fig-3dregression-1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
        <script type="text/javascript">
        window.PlotlyConfig = {MathJaxConfig: 'local'};
        if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}
        </script>
        <script type="module">import "https://cdn.plot.ly/plotly-3.0.1.min"</script>
        
</div>
<figcaption class="quarto-float-caption-bottom quarto-subfloat-caption quarto-subfloat-fig" id="fig-3dregression-1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
(a) Predicted Exit Velocity as a Function of Swing Speed and Swing Length.
</figcaption>
</figure>
</div>
<div id="fig-3dregression-2" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-subfloat-fig figure">
<div aria-describedby="fig-3dregression-2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="092e30f3-7a17-49fd-8baf-40f21e7c35e1" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("092e30f3-7a17-49fd-8baf-40f21e7c35e1")) {                    Plotly.newPlot(                        "092e30f3-7a17-49fd-8baf-40f21e7c35e1",                        [{"marker":{"color":"blue","opacity":1.0,"size":5},"mode":"markers","name":"Data","x":{"dtype":"f8","bdata":"mpmZmZnZUUDNzMzMzIxRQDMzMzMz81FAMzMzMzMTUkBmZmZmZiZRQAAAAAAA4FFAzczMzMwsUUAAAAAAAOBRQGZmZmZmhlJAZmZmZmbGUkCamZmZmblSQAAAAAAAoFFAMzMzMzMTUkAAAAAAAABTQM3MzMzMLFNAAAAAAADAUUCamZmZmflRQM3MzMzMbFJAzczMzMzsUkDNzMzMzOxRQGZmZmZmBlFAZmZmZmbmUEAzMzMzMzNRQDMzMzMz01FAAAAAAADgUkAzMzMzM5NRQM3MzMzMTFNAAAAAAABgUkCamZmZmXlRQJqZmZmZOVJAzczMzMxMUkDNzMzMzGxRQJqZmZmZ+VFAmpmZmZmZUECamZmZmflSQAAAAAAAQFJAAAAAAAAAUkAAAAAAAIBSQJqZmZmZ2VFAAAAAAADgUkDNzMzMzAxSQDMzMzMzk1FAzczMzMyMUUDNzMzMzCxSQGZmZmZmJlFAZmZmZmYGUEBmZmZmZoZQQDMzMzMz81FAzczMzMwMUUAAAAAAAMBRQJqZmZmZmVFAZmZmZmamUkDNzMzMzCxSQGZmZmZmhlJAMzMzMzPTUUAAAAAAAKBRQDMzMzMz81FAmpmZmZn5UEDNzMzMzCxSQDMzMzMzc1JAmpmZmZmZUEAzMzMzM7NSQM3MzMzMzFFAmpmZmZm5UUBmZmZmZmZSQDMzMzMz01FAZmZmZmZmUkCamZmZmRlSQDMzMzMzE1JAAAAAAADgUkBmZmZmZiZRQDMzMzMz81JAZmZmZmamUkBmZmZmZuZRQAAAAAAAgFFAzczMzMwMUkDNzMzMzAxTQJqZmZmZ2VFAMzMzMzMzUUAzMzMzMxNSQJqZmZmZ2VJAzczMzMwMUkAAAAAAAIBSQGZmZmZmZlJAzczMzMwMUkBmZmZmZuZQQM3MzMzMzFFAMzMzMzPzT0AAAAAAAMBSQDMzMzMz01FAAAAAAAAgUkAzMzMzM\u002fNQQDMzMzMzE1FAmpmZmZlZU0CamZmZmTlSQJqZmZmZWVJAzczMzMzsUUAAAAAAAOBRQAAAAAAAwFBAMzMzMzPzUkBmZmZmZmZSQJqZmZmZGVJAzczMzMxsUkAzMzMzM7NRQGZmZmZmxlFAmpmZmZkZUkAzMzMzMzNRQJqZmZmZeVFAAAAAAACgUUDNzMzMzAxRQDMzMzMz81FAZmZmZmZGU0CamZmZmflQQJqZmZmZWVJAAAAAAADAUkBmZmZmZgZSQJqZmZmZmVFAZmZmZmYGUkAzMzMzM3NRQDMzMzMzM1BAAAAAAADAUkCamZmZmZlRQGZmZmZmplJAzczMzMzsUUBmZmZmZoZRQM3MzMzMTFJAMzMzMzNzUkAzMzMzMzNSQAAAAAAAwFJAMzMzMzNTU0AzMzMzM1NRQGZmZmZm5lFAzczMzMyMUUAzMzMzM9NRQDMzMzMz81FAMzMzMzMTUUDNzMzMzExQQAAAAAAAYFFAAAAAAADAUUAzMzMzM5NQQAAAAAAAIFJAzczMzMzMUkDNzMzMzAxRQAAAAAAAYFNAmpmZmZm5UUAzMzMzMxNSQDMzMzMzE1FAAAAAAADAUUAAAAAAAMBSQDMzMzMzc1FAzczMzMxMUkBmZmZmZiZSQAAAAAAAoFJAZmZmZmaGUkBmZmZmZqZRQAAAAAAAQFFAMzMzMzNTUkDNzMzMzMxRQDMzMzMz81FAzczMzMwMUkAAAAAAAKBSQM3MzMzMDFFAMzMzMzNzUkBmZmZmZuZRQM3MzMzMrFFAMzMzMzNTUkAAAAAAAIBSQM3MzMzMzFJAZmZmZmZmUkAAAAAAAOBRQGZmZmZmBlNAMzMzMzNzUkDNzMzMzGxSQM3MzMzMrFJAzczMzMwMUkCamZmZmblRQAAAAAAAIFNAmpmZmZnZUkCamZmZmRlSQGZmZmZm5lFAzczMzMzsUUBmZmZmZkZTQDMzMzMz01FAZmZmZmamUUDNzMzMzKxRQAAAAAAAIFJAMzMzMzPTUUAAAAAAAIBSQDMzMzMz01FAzczMzMzsUUAzMzMzM1NRQM3MzMzMTFJAZmZmZmYmU0DNzMzMzOxRQAAAAAAAAFJAMzMzMzOzUUDNzMzMzIxRQJqZmZmZ+VFAzczMzMysUkAzMzMzM5NRQM3MzMzMDFJAZmZmZmbmUUBmZmZmZkZQQDMzMzMz01FAMzMzMzMTU0BmZmZmZmZRQJqZmZmZ+VFAzczMzMyMT0BmZmZmZsZRQM3MzMzMDFFAzczMzMzMUkDNzMzMzOxRQAAAAAAAQFJAAAAAAABAUUAAAAAAAKBTQGZmZmZmhlFAMzMzMzMTU0BmZmZmZiZRQAAAAAAAIFJAmpmZmZkZUEAzMzMzM7NRQGZmZmZmhlFAmpmZmZmZUUDNzMzMzCxSQGZmZmZmRlFAzczMzMzsUUBmZmZmZsZSQM3MzMzMDFJAzczMzMysUkAzMzMzM3NRQDMzMzMzE1NAZmZmZmaGUUDNzMzMzOxRQM3MzMzMrFJAZmZmZmZmUkCamZmZmflRQAAAAAAAYFFAAAAAAAAAUUAzMzMzMxNRQJqZmZmZ+VBAmpmZmZk5UkDNzMzMzCxSQJqZmZmZGVJAZmZmZmZGUkDNzMzMzOxRQM3MzMzMzFJAmpmZmZnZUkDNzMzMzIxQQM3MzMzMbFJAzczMzMzMUkCamZmZmVlRQM3MzMzMzFFAzczMzMxMUkAzMzMzM1NSQM3MzMzMbFJAAAAAAAAgUkDNzMzMzAxRQJqZmZmZWVJAmpmZmZn5UkAzMzMzM7NRQGZmZmZm5lFAzczMzMxsUkDNzMzMzOxRQA=="},"y":{"dtype":"f8","bdata":"ZmZmZmZmIECamZmZmZkbQGZmZmZmZhpAMzMzMzMzIEDNzMzMzMwaQJqZmZmZmR1AZmZmZmZmHkAzMzMzMzMdQJqZmZmZmR1AAAAAAAAAHEAzMzMzMzMdQM3MzMzMzBpAAAAAAAAAHkDNzMzMzMweQM3MzMzMzB5AMzMzMzMzHUBmZmZmZmYeQJqZmZmZmR9AmpmZmZmZHUBmZmZmZmYcQDMzMzMzMyBAmpmZmZmZG0BmZmZmZmYcQAAAAAAAAB5AZmZmZmZmHkDNzMzMzMwcQAAAAAAAACBAZmZmZmZmHkAzMzMzMzMdQAAAAAAAAB5AMzMzMzMzG0DNzMzMzMwaQAAAAAAAAB5AAAAAAAAAGkAAAAAAAAAgQJqZmZmZmR1AmpmZmZmZHUCamZmZmZkfQAAAAAAAAB5AZmZmZmZmHkDNzMzMzMweQJqZmZmZmRtAZmZmZmZmHkAAAAAAAAAeQM3MzMzMzBxAmpmZmZmZGUDNzMzMzMwaQDMzMzMzMx9AMzMzMzMzHUBmZmZmZmYeQGZmZmZmZhxAMzMzMzMzHUCamZmZmZkfQAAAAAAAACFAZmZmZmZmHEBmZmZmZmYeQGZmZmZmZh5AAAAAAAAAHEDNzMzMzMwcQAAAAAAAAB5AZmZmZmZmHEAzMzMzMzMdQAAAAAAAABxAZmZmZmZmHEDNzMzMzMwcQDMzMzMzMx1AmpmZmZmZHUDNzMzMzMweQDMzMzMzMx9AmpmZmZmZHUAAAAAAAAAcQDMzMzMzMx9AmpmZmZmZH0AzMzMzMzMdQDMzMzMzMx1AMzMzMzMzHUAAAAAAAAAeQJqZmZmZmR1AZmZmZmZmHECamZmZmZkbQDMzMzMzMx1AAAAAAAAAHECamZmZmZkdQAAAAAAAABxAMzMzMzMzHUDNzMzMzMwYQM3MzMzMzBxAmpmZmZmZF0AzMzMzMzMfQDMzMzMzMx1AZmZmZmZmIEAzMzMzMzMdQDMzMzMzMxtAmpmZmZmZH0DNzMzMzMwcQAAAAAAAAB5AAAAAAAAAHkAzMzMzMzMdQGZmZmZmZhpAMzMzMzMzH0CamZmZmZkfQGZmZmZmZh5AMzMzMzMzHUCamZmZmZkbQM3MzMzMzB5AZmZmZmZmHEAAAAAAAAAcQGZmZmZmZh5AzczMzMzMHECamZmZmZkbQJqZmZmZmRtAmpmZmZmZH0CamZmZmZkbQDMzMzMzMx9AAAAAAAAAHkDNzMzMzMweQM3MzMzMzBxAAAAAAAAAHkBmZmZmZmYcQJqZmZmZmRtAmpmZmZmZHUAAAAAAAAAeQDMzMzMzMx9AmpmZmZmZG0DNzMzMzMwcQAAAAAAAAB5AMzMzMzMzHUAAAAAAAAAcQGZmZmZmZh5AmpmZmZmZHUAzMzMzMzMfQAAAAAAAACBAmpmZmZmZG0DNzMzMzMwcQGZmZmZmZh5AMzMzMzMzGUBmZmZmZmYaQGZmZmZmZhxAZmZmZmZmHkCamZmZmZkbQJqZmZmZmR1AMzMzMzMzHUAAAAAAAAAgQM3MzMzMzB5AmpmZmZmZHUBmZmZmZmYaQM3MzMzMzB5AZmZmZmZmHEAAAAAAAAAeQDMzMzMzMxtAMzMzMzMzH0BmZmZmZmYeQDMzMzMzMx9AMzMzMzMzHUBmZmZmZmYcQGZmZmZmZh5AAAAAAAAAHkAAAAAAAAAeQM3MzMzMzB5AAAAAAAAAHkAAAAAAAAAcQJqZmZmZmRtAMzMzMzMzHUAzMzMzMzMbQDMzMzMzMx1AMzMzMzMzHUCamZmZmZkdQJqZmZmZmRtAZmZmZmZmHkAzMzMzMzMdQAAAAAAAACBAmpmZmZmZG0AAAAAAAAAcQDMzMzMzMx1AMzMzMzMzH0CamZmZmZkfQGZmZmZmZh5AMzMzMzMzHUAAAAAAAAAcQGZmZmZmZh5AzczMzMzMHEBmZmZmZmYgQAAAAAAAABxAAAAAAAAAHkBmZmZmZmYgQJqZmZmZmR1AzczMzMzMGkAzMzMzMzMdQAAAAAAAAB5AZmZmZmZmHEBmZmZmZmYcQJqZmZmZmR9AAAAAAAAAHkAzMzMzMzMdQJqZmZmZmR9AZmZmZmZmHkAzMzMzMzMdQGZmZmZmZh5AzczMzMzMHEAzMzMzMzMdQAAAAAAAAB5AMzMzMzMzHUAzMzMzMzMZQAAAAAAAAB5AzczMzMzMHkCamZmZmZkbQAAAAAAAAB5AAAAAAAAAGECamZmZmZkdQGZmZmZmZhxAMzMzMzMzHUCamZmZmZkdQM3MzMzMzBxAmpmZmZmZG0DNzMzMzMweQAAAAAAAAB5AzczMzMzMHEAAAAAAAAAcQDMzMzMzMx9AAAAAAAAAGkDNzMzMzMwcQDMzMzMzMxtAmpmZmZmZH0CamZmZmZkdQJqZmZmZmRtAMzMzMzMzHUAAAAAAAAAeQJqZmZmZmR1AZmZmZmZmHEBmZmZmZmYcQJqZmZmZmR9AzczMzMzMHEAzMzMzMzMdQAAAAAAAAB5AMzMzMzMzIECamZmZmZkdQDMzMzMzMx1AzczMzMzMGkAAAAAAAAAcQM3MzMzMzBxAZmZmZmZmHkBmZmZmZmYeQGZmZmZmZh5AzczMzMzMHEAzMzMzMzMbQDMzMzMzMx9AmpmZmZmZH0BmZmZmZmYYQGZmZmZmZh5AZmZmZmZmHEAzMzMzMzMfQDMzMzMzMyBAmpmZmZmZHUAzMzMzMzMdQGZmZmZmZhxAzczMzMzMHEBmZmZmZmYcQAAAAAAAAB5AzczMzMzMHkCamZmZmZkdQJqZmZmZmR1AZmZmZmZmHkCamZmZmZkdQA=="},"z":{"dtype":"f8","bdata":"MzMzMzMzVkBmZmZmZiZWQDMzMzMzU1dAZmZmZmaGVkDNzMzMzKxVQM3MzMzMLFZAmpmZmZkZVkCamZmZmdlVQDMzMzMzc1ZAzczMzMysVkDNzMzMzGxXQAAAAAAAgFZAMzMzMzPzVUCamZmZmflWQAAAAAAAwFZAAAAAAACgVUAzMzMzMxNWQGZmZmZmBldAAAAAAABgVkCamZmZmVlWQJqZmZmZuVVAzczMzMyMVUAzMzMzM\u002fNVQGZmZmZmRlZAmpmZmZlZV0CamZmZmXlVQM3MzMzMLFdAMzMzMzNzVkDNzMzMzGxWQM3MzMzM7FZAAAAAAACAVkCamZmZmVlWQAAAAAAAAFZAAAAAAABgVkBmZmZmZkZWQJqZmZmZ+VZAmpmZmZlZVkAzMzMzM9NWQDMzMzMzM1ZAZmZmZmYGV0CamZmZmXlWQJqZmZmZGVZAZmZmZmamVkAzMzMzMxNWQDMzMzMzU1ZAAAAAAACAVUAzMzMzM5NVQAAAAAAA4FVAZmZmZmZmVkDNzMzMzMxWQGZmZmZmJlZAzczMzMxMV0BmZmZmZoZWQAAAAAAAAFZAzczMzMzMVkAzMzMzM5NWQM3MzMzMjFZAZmZmZmYGVkAzMzMzM\u002fNWQJqZmZmZWVdAmpmZmZnZVUCamZmZmZlWQDMzMzMz81ZAzczMzMwsVkBmZmZmZuZWQGZmZmZmhlZAzczMzMzsVkCamZmZmTlWQDMzMzMzk1ZAMzMzMzPzVkAzMzMzM5NVQGZmZmZmxlZAMzMzMzMTVkDNzMzMzGxWQM3MzMzMLFZAMzMzMzOzVkAzMzMzMxNXQAAAAAAAQFZAZmZmZmamVUDNzMzMzAxXQAAAAAAAAFdAZmZmZmZGVkAAAAAAAEBWQGZmZmZmBlZAZmZmZmbGVkDNzMzMzExWQDMzMzMzE1ZAMzMzMzMTVkAAAAAAAGBWQAAAAAAAYFZAmpmZmZnZVUCamZmZmflVQJqZmZmZ2VVAmpmZmZmZV0BmZmZmZqZWQGZmZmZmRldAmpmZmZl5VkAzMzMzM1NWQGZmZmZmplVAMzMzMzPTVkCamZmZmblWQJqZmZmZeVZAAAAAAACgVkBmZmZmZkZWQM3MzMzMDFZAmpmZmZnZVkAzMzMzMzNVQJqZmZmZ+VVAAAAAAACAVkAAAAAAAIBVQJqZmZmZeVZAmpmZmZkZV0DNzMzMzMxVQJqZmZmZ+VVAMzMzMzPzVkDNzMzMzExXQGZmZmZm5lVAMzMzMzPTVkAzMzMzM\u002fNWQGZmZmZmRlVAAAAAAAAAVkCamZmZmVlWQDMzMzMz81VAAAAAAAAgVkDNzMzMzIxWQGZmZmZmxlZAMzMzMzPTVkCamZmZmRlWQDMzMzMz81ZAzczMzMysV0AzMzMzMxNWQAAAAAAAAFZAmpmZmZm5VkCamZmZmRlXQM3MzMzMTFZAMzMzMzMTVkBmZmZmZoZVQGZmZmZmJlZAzczMzMwsVkCamZmZmdlUQM3MzMzMTFdAMzMzMzPzVkAAAAAAAEBVQGZmZmZmZldAzczMzMxMVkBmZmZmZgZXQJqZmZmZ2VVAAAAAAAAgVkDNzMzMzMxWQJqZmZmZWVZAZmZmZmamVkDNzMzMzAxWQAAAAAAAwFZAMzMzMzPTVkCamZmZmdlVQDMzMzMz81VAzczMzMwMV0DNzMzMzGxWQGZmZmZmZlZAmpmZmZmZVkBmZmZmZmZWQDMzMzMzc1VAAAAAAADgVkCamZmZmXlWQJqZmZmZmVZAmpmZmZk5VkBmZmZmZgZXQAAAAAAA4FZAMzMzMzOzVkDNzMzMzExWQM3MzMzMTFZAAAAAAACgVkAzMzMzM1NWQDMzMzMzM1dAZmZmZmZGVkDNzMzMzAxWQGZmZmZmRldAzczMzMyMV0AzMzMzM7NWQGZmZmZmRlZAzczMzMzMVUDNzMzMzAxYQGZmZmZmRlZAmpmZmZkZVkAzMzMzM5NVQM3MzMzMjFZAMzMzMzPzVUBmZmZmZsZWQAAAAAAAQFZAMzMzMzNTVkDNzMzMzOxVQGZmZmZmxlZAzczMzMxMV0AAAAAAACBWQAAAAAAAwFZAMzMzMzOTVkAAAAAAAMBVQJqZmZmZGVZAMzMzMzPTVkCamZmZmXlWQM3MzMzMDFZAzczMzMxMVkBmZmZmZsZVQDMzMzMzM1ZAMzMzMzPzV0DNzMzMzCxWQM3MzMzMbFZAMzMzMzOTVUAzMzMzM3NWQM3MzMzMbFVAMzMzMzNzVkCamZmZmVlWQM3MzMzM7FZAmpmZmZl5VkAAAAAAAOBXQGZmZmZmplVAMzMzMzMzV0DNzMzMzAxWQM3MzMzMzFZAMzMzMzOTVUCamZmZmZlWQDMzMzMz81VAmpmZmZk5VkCamZmZmZlWQM3MzMzMDFZAZmZmZmZGVkAzMzMzM7NWQJqZmZmZmVZAzczMzMwsV0CamZmZmblWQM3MzMzM7FZAZmZmZmYmVkBmZmZmZsZWQDMzMzMz01ZAZmZmZmYmVkAAAAAAAOBVQGZmZmZmJlZAAAAAAAAAVkAzMzMzM5NVQJqZmZmZWVZAmpmZmZl5VkAAAAAAACBWQJqZmZmZuVZAMzMzMzNzVkAzMzMzMzNWQAAAAAAAIFdAAAAAAACgVkAAAAAAAMBVQGZmZmZmhlVAAAAAAAAgV0AAAAAAAKBVQM3MzMzMLFZAzczMzMxsVkCamZmZmflWQJqZmZmZ+VZAZmZmZmYGV0AAAAAAAMBVQDMzMzMz81VAMzMzMzNzV0DNzMzMzIxWQAAAAAAAAFZAAAAAAACAV0AAAAAAAMBWQA=="},"type":"scatter3d"},{"colorscale":[[0.0,"#440154"],[0.1111111111111111,"#482878"],[0.2222222222222222,"#3e4989"],[0.3333333333333333,"#31688e"],[0.4444444444444444,"#26828e"],[0.5555555555555556,"#1f9e89"],[0.6666666666666666,"#35b779"],[0.7777777777777778,"#6ece58"],[0.8888888888888888,"#b5de2b"],[1.0,"#fde725"]],"name":"Regression Plane","opacity":0.5,"x":{"dtype":"f8","bdata":"ZmZmZmYmT0CE5Z5GWG5PQKJk1yZKtk9AwOMPBzz+T0BvMaTzFiNQQP5wwOMPR1BAjbDc0whrUEAc8PjDAY9QQKsvFbT6slBAOm8xpPPWUEDJrk2U7PpQQFjuaYTlHlFA5y2GdN5CUUB2baJk12ZRQAWtvlTQilFAlOzaRMmuUUAjLPc0wtJRQLJrEyW79lFAQasvFbQaUkDQ6ksFrT5SQF8qaPWlYlJA7mmE5Z6GUkB9qaDVl6pSQAzpvMWQzlJAmyjZtYnyUkAqaPWlghZTQLmnEZZ7OlNASOcthnReU0DXJkp2bYJTQGZmZmZmplNA"},"y":{"dtype":"f8","bdata":"mpmZmZmZF0CDVl8qaPUXQGwTJbs2URhAVdDqSwWtGEA+jbDc0wgZQCdKdm2iZBlAEAc8\u002fnDAGUD5wwGPPxwaQOKAxx8OeBpAyz2NsNzTGkC0+lJBqy8bQJ23GNJ5ixtAhnTeYkjnG0BwMaTzFkMcQFjuaYTlnhxAQqsvFbT6HEAqaPWlglYdQBQluzZRsh1A\u002fOGAxx8OHkDmnkZY7mkeQM5bDOm8xR5AuBjSeYshH0Ch1ZcKWn0fQIqSXZso2R9AuqcRlnsaIEAuhnTeYkggQKJk1yZKdiBAF0M6bzGkIECMIZ23GNIgQAAAAAAAACFA"},"z":{"dtype":"f8","bdata":"NAGMjw9DVUAmIswRQVpVQBhDDJRycVVACmRMFqSIVUD8hIyY1Z9VQO6lzBoHt1VA4MYMnTjOVUDS50wfauVVQMQIjaGb\u002fFVAtinNI80TVkCoSg2m\u002fipWQJprTSgwQlZAjIyNqmFZVkB+rc0sk3BWQHDODa\u002fEh1ZAYu9NMfaeVkBUEI6zJ7ZWQEYxzjVZzVZAOFIOuIrkVkAqc046vPtWQByUjrztEldADrXOPh8qV0AA1g7BUEFXQPL2TkOCWFdA5BePxbNvV0DWOM9H5YZXQMhZD8oWnldAunpPTEi1V0Csm4\u002fOecxXQJ68z1Cr41dAnWkUOPw8VUCPilS6LVRVQIGrlDxfa1VAc8zUvpCCVUBl7RRBwplVQFcOVcPzsFVASS+VRSXIVUA7UNXHVt9VQC1xFUqI9lVAH5JVzLkNVkARs5VO6yRWQALU1dAcPFZA9PQVU05TVkDmFVbVf2pWQNg2llexgVZAylfW2eKYVkC8eBZcFLBWQK6ZVt5Fx1ZAoLqWYHfeVkCS29biqPVWQIT8FmXaDFdAdh1X5wskV0BoPpdpPTtXQFpf1+tuUldATIAXbqBpV0A+oVfw0YBXQDDCl3IDmFdAIuPX9DSvV0AUBBh3ZsZXQAYlWPmX3VdABdKc4Og2VUD38txiGk5VQOkTHeVLZVVA2zRdZ318VUDNVZ3prpNVQL923WvgqlVAsZcd7hHCVUCjuF1wQ9lVQJXZnfJ08FVAh\u002frddKYHVkB5Gx731x5WQGo8XnkJNlZAXF2e+zpNVkBOft59bGRWQECfHgCee1ZAMsBegs+SVkAk4Z4EAapWQBYC34YywVZACCMfCWTYVkD6Q1+Lle9WQOxknw3HBldA3oXfj\u002fgdV0DQph8SKjVXQMLHX5RbTFdAtOifFo1jV0CmCeCYvnpXQJgqIBvwkVdAiktgnSGpV0B8bKAfU8BXQG6N4KGE11dAbjolidUwVUBgW2ULB0hVQFJ8pY04X1VARJ3lD2p2VUA2viWSm41VQCjfZRTNpFVAGgCmlv67VUAMIeYYMNNVQP5BJpth6lVA8GJmHZMBVkDig6afxBhWQNOk5iH2L1ZAxcUmpCdHVkC35mYmWV5WQKkHp6iKdVZAmyjnKryMVkCNSSet7aNWQH9qZy8fu1ZAcYunsVDSVkBjrOczgulWQFXNJ7azAFdAR+5nOOUXV0A5D6i6Fi9XQCsw6DxIRldAHVEov3ldV0APcmhBq3RXQACTqMPci1dA8rPoRQ6jV0Dk1CjIP7pXQNb1aEpx0VdA1qKtMcIqVUDIw+2z80FVQLrkLTYlWVVArAVuuFZwVUCeJq46iIdVQJBH7ry5nlVAgmguP+u1VUB0iW7BHM1VQGaqrkNO5FVAWMvuxX\u002f7VUBK7C5IsRJWQDsNb8riKVZALS6vTBRBVkAfT+\u002fORVhWQBFwL1F3b1ZAA5Fv06iGVkD1sa9V2p1WQOfS79cLtVZA2fMvWj3MVkDLFHDcbuNWQL01sF6g+lZAr1bw4NERV0ChdzBjAylXQJOYcOU0QFdAhbmwZ2ZXV0B32vDpl25XQGj7MGzJhVdAWhxx7vqcV0BMPbFwLLRXQD5e8fJdy1dAPgs22q4kVUAwLHZc4DtVQCJNtt4RU1VAFG72YENqVUAGjzbjdIFVQPivdmWmmFVA6tC259evVUDc8fZpCcdVQM4SN+w63lVAwDN3bmz1VUCyVLfwnQxWQKR193LPI1ZAlpY39QA7VkCIt3d3MlJWQHrYt\u002fljaVZAbPn3e5WAVkBeGjj+xpdWQFA7eID4rlZAQly4AirGVkA0ffiEW91WQCaeOAeN9FZAGL94ib4LV0AK4LgL8CJXQPwA+Y0hOldA7iE5EFNRV0DgQnmShGhXQNFjuRS2f1dAw4T5lueWV0C1pTkZGa5XQKfGeZtKxVdApnO+gpseVUCYlP4EzTVVQIq1Pof+TFVAfNZ+CTBkVUBu976LYXtVQGAY\u002fw2TklVAUjk\u002fkMSpVUBEWn8S9sBVQDZ7v5Qn2FVAKJz\u002fFlnvVUAavT+ZigZWQAzefxu8HVZA\u002fv6\u002fne00VkDwHwAgH0xWQOJAQKJQY1ZA1GGAJIJ6VkDGgsCms5FWQLijACnlqFZAqsRAqxbAVkCc5YAtSNdWQI4Gwa957lZAgCcBMqsFV0BySEG03BxXQGRpgTYONFdAVorBuD9LV0BIqwE7cWJXQDnMQb2ieVdAK+2BP9SQV0AdDsLBBahXQA8vAkQ3v1dADtxGK4gYVUAA\u002fYatuS9VQPIdxy\u002frRlVA5D4HshxeVUDWX0c0TnVVQMiAh7Z\u002fjFVAuqHHOLGjVUCswge74rpVQJ7jRz0U0lVAkASIv0XpVUCCJchBdwBWQHRGCMSoF1ZAZmdIRtouVkBYiIjIC0ZWQEqpyEo9XVZAPMoIzW50VkAu60hPoItWQCAMidHRolZAEi3JUwO6VkAETgnWNNFWQPZuSVhm6FZA6I+J2pf\u002fVkDasMlcyRZXQMzRCd\u002f6LVdAvvJJYSxFV0CwE4rjXVxXQKI0ymWPc1dAlFUK6MCKV0CGdkpq8qFXQHiXiuwjuVdAd0TP03QSVUBpZQ9WpilVQFuGT9jXQFVATaePWglYVUA\u002fyM\u002fcOm9VQDHpD19shlVAIwpQ4Z2dVUAVK5Bjz7RVQAdM0OUAzFVA+WwQaDLjVUDrjVDqY\u002fpVQNyukGyVEVZAzs\u002fQ7sYoVkDA8BBx+D9WQLIRUfMpV1ZApDKRdVtuVkCWU9H3jIVWQIh0EXq+nFZAepVR\u002fO+zVkBstpF+IctWQF7X0QBT4lZAUPgRg4T5VkBCGVIFthBXQDQ6kofnJ1dAJlvSCRk\u002fV0AYfBKMSlZXQAqdUg58bVdA\u002fL2SkK2EV0Du3tIS35tXQOD\u002fEpUQs1dA36xXfGEMVUDRzZf+kiNVQMPu14DEOlVAtQ8YA\u002fZRVUCnMFiFJ2lVQJlRmAdZgFVAi3LYiYqXVUB9kxgMvK5VQG+0WI7txVVAYdWYEB\u002fdVUBT9tiSUPRVQEQXGRWCC1ZANjhZl7MiVkAoWZkZ5TlWQBp62ZsWUVZADJsZHkhoVkD+u1mgeX9WQPDcmSKrllZA4v3ZpNytVkDUHhonDsVWQMY\u002fWqk\u002f3FZAuGCaK3HzVkCqgdqtogpXQJyiGjDUIVdAjsNasgU5V0CA5Jo0N1BXQHIF27ZoZ1dAZCYbOZp+V0BWR1u7y5VXQEhomz39rFdASBXgJE4GVUA6NiCnfx1VQCxXYCmxNFVAHnigq+JLVUAQmeAtFGNVQAK6ILBFelVA9NpgMneRVUDm+6C0qKhVQNgc4Tbav1VAyj0huQvXVUC8XmE7Pe5VQK1\u002fob1uBVZAn6DhP6AcVkCRwSHC0TNWQIPiYUQDS1ZAdQOixjRiVkBnJOJIZnlWQFlFIsuXkFZAS2ZiTcmnVkA9h6LP+r5WQC+o4lEs1lZAIcki1F3tVkAT6mJWjwRXQAULo9jAG1dA9yvjWvIyV0DpTCPdI0pXQNptY19VYVdAzI6j4YZ4V0C+r+NjuI9XQLDQI+bppldAsH1ozToAVUCinqhPbBdVQJS\u002f6NGdLlVAhuAoVM9FVUB4AWnWAF1VQGoiqVgydFVAXEPp2mOLVUBOZCldlaJVQECFad\u002fGuVVAMqapYfjQVUAkx+njKehVQBXoKWZb\u002f1VABwlq6IwWVkD5Kapqvi1WQOtK6uzvRFZA3WsqbyFcVkDPjGrxUnNWQMGtqnOEilZAs87q9bWhVkCl7yp457hWQJcQa\u002foY0FZAiTGrfErnVkB7Uuv+e\u002f5WQG1zK4GtFVdAX5RrA98sV0BRtauFEERXQELW6wdCW1dANPcrinNyV0AmGGwMpYlXQBg5rI7WoFdAGObwdSf6VEAKBzH4WBFVQPwncXqKKFVA7kix\u002fLs\u002fVUDgafF+7VZVQNKKMQEfblVAxKtxg1CFVUC2zLEFgpxVQKjt8Yezs1VAmg4yCuXKVUCML3KMFuJVQH5Qsg5I+VVAcHHykHkQVkBikjITqydWQFSzcpXcPlZARtSyFw5WVkA49fKZP21WQCoWMxxxhFZAHDdznqKbVkAOWLMg1LJWQAB586IFylZA8pkzJTfhVkDkunOnaPhWQNbbsymaD1dAyPzzq8smV0C6HTQu\u002fT1XQKs+dLAuVVdAnV+0MmBsV0CPgPS0kYNXQIGhNDfDmldAgE55HhT0VEByb7mgRQtVQGSQ+SJ3IlVAVrE5pag5VUBI0nkn2lBVQDrzuakLaFVALBT6Kz1\u002fVUAeNTqubpZVQBBWejCgrVVAAne6stHEVUD0l\u002fo0A9xVQOa4Orc081VA2Nl6OWYKVkDK+rq7lyFWQLwb+z3JOFZArjw7wPpPVkCgXXtCLGdWQJJ+u8RdflZAhJ\u002f7Ro+VVkB2wDvJwKxWQGjhe0vyw1ZAWgK8zSPbVkBMI\u002fxPVfJWQD5EPNKGCVdAMGV8VLggV0AihrzW6TdXQBOn\u002fFgbT1dABcg820xmV0D36Hxdfn1XQOkJvd+vlFdA6LYBxwDuVEDa10FJMgVVQMz4gctjHFVAvhnCTZUzVUCwOgLQxkpVQKJbQlL4YVVAlHyC1Cl5VUCGncJWW5BVQHi+AtmMp1VAat9CW76+VUBcAIPd79VVQE4hw18h7VVAQEID4lIEVkAyY0NkhBtWQCSEg+a1MlZAFqXDaOdJVkAIxgPrGGFWQPrmQ21KeFZA7AeE73uPVkDeKMRxraZWQNBJBPTevVZAwmpEdhDVVkC0i4T4QexWQKasxHpzA1dAmM0E\u002faQaV0CK7kR\u002f1jFXQHwPhQEISVdAbjDFgzlgV0BgUQUGa3dXQFJyRYicjldAUB+Kb+3nVEBCQMrxHv9UQDRhCnRQFlVAJoJK9oEtVUAYo4p4s0RVQArEyvrkW1VA\u002fOQKfRZzVUDuBUv\u002fR4pVQOAmi4F5oVVA0kfLA6u4VUDEaAuG3M9VQLaJSwgO51VAqKqLij\u002f+VUCay8sMcRVWQIzsC4+iLFZAfg1MEdRDVkBwLoyTBVtWQGJPzBU3clZAVHAMmGiJVkBGkUwamqBWQDiyjJzLt1ZAKtPMHv3OVkAc9AyhLuZWQA4VTSNg\u002fVZAADaNpZEUV0DyVs0nwytXQOR3Dar0QldA1phNLCZaV0DIuY2uV3FXQLrazTCJiFdAuYcSGNrhVECrqFKaC\u002flUQJ3Jkhw9EFVAj+rSnm4nVUCBCxMhoD5VQHMsU6PRVVVAZU2TJQNtVUBXbtOnNIRVQEmPEypmm1VAO7BTrJeyVUAt0ZMuyclVQB7y07D64FVAEBMUMyz4VUACNFS1XQ9WQPRUlDePJlZA5nXUucA9VkDYlhQ88lRWQMq3VL4jbFZAvNiUQFWDVkCu+dTChppWQKAaFUW4sVZAkjtVx+nIVkCEXJVJG+BWQHZ91ctM91ZAaJ4VTn4OV0Bav1XQryVXQEzglVLhPFdAPgHW1BJUV0AwIhZXRGtXQCJDVtl1gldAIfCawMbbVEATEdtC+PJUQAUyG8UpClVA91JbR1shVUDpc5vJjDhVQNuU20u+T1VAzbUbzu9mVUC\u002f1ltQIX5VQLH3m9JSlVVAoxjcVISsVUCVORzXtcNVQIZaXFnn2lVAeHuc2xjyVUBqnNxdSglWQFy9HOB7IFZATt5cYq03VkBA\u002f5zk3k5WQDIg3WYQZlZAJEEd6UF9VkAWYl1rc5RWQAiDne2kq1ZA+qPdb9bCVkDsxB3yB9pWQN7lXXQ58VZA0Aae9moIV0DCJ954nB9XQLRIHvvNNldApmleff9NV0CYip7\u002fMGVXQIqr3oFifFdAilgjabPVVEB8eWPr5OxUQG6ao20WBFVAYLvj70cbVUBS3CNyeTJVQET9Y\u002fSqSVVANh6kdtxgVUAoP+T4DXhVQBpgJHs\u002fj1VADIFk\u002fXCmVUD+oaR\u002for1VQO\u002fC5AHU1FVA4eMkhAXsVUDTBGUGNwNWQMUlpYhoGlZAt0blCpoxVkCpZyWNy0hWQJuIZQ\u002f9X1ZAjamlkS53VkB\u002fyuUTYI5WQHHrJZaRpVZAYwxmGMO8VkBVLaaa9NNWQEdO5hwm61ZAOW8mn1cCV0ArkGYhiRlXQByxpqO6MFdADtLmJexHV0AA8yaoHV9XQPITZypPdldA8sCrEaDPVEDk4euT0eZUQNYCLBYD\u002flRAyCNsmDQVVUC6RKwaZixVQKxl7JyXQ1VAnoYsH8laVUCQp2yh+nFVQILIrCMsiVVAdOnspV2gVUBmCi0oj7dVQFgrbarAzlVASkytLPLlVUA8be2uI\u002f1VQC6OLTFVFFZAIK9ts4YrVkAS0K01uEJWQATx7bfpWVZA9hEuOhtxVkDoMm68TIhWQNpTrj5+n1ZAzHTuwK+2VkC+lS5D4c1WQLC2bsUS5VZAoteuR0T8VkCU+O7JdRNXQIUZL0ynKldAdzpvzthBV0BpW69QCllXQFt879I7cFdAWik0uozJVEBMSnQ8vuBUQD5rtL7v91RAMIz0QCEPVUAirTTDUiZVQBTOdEWEPVVABu+0x7VUVUD4D\u002fVJ52tVQOowNcwYg1VA3FF1TkqaVUDOcrXQe7FVQMCT9VKtyFVAsrQ11d7fVUCk1XVXEPdVQJb2tdlBDlZAiBf2W3MlVkB6ODbepDxWQGxZdmDWU1ZAXnq24gdrVkBQm\u002fZkOYJWQEK8NudqmVZANN12aZywVkAm\u002frbrzcdWQBgf923\u002f3lZACkA38DD2VkD8YHdyYg1XQO2Bt\u002fSTJFdA36L3dsU7V0DRwzf59lJXQMPkd3soaldAwpG8YnnDVEC0svzkqtpUQKbTPGfc8VRAmPR86Q0JVUCKFb1rPyBVQHw2\u002fe1wN1VAblc9cKJOVUBgeH3y02VVQFKZvXQFfVVARLr99jaUVUA22z15aKtVQCj8ffuZwlVAGh2+fcvZVUAMPv7\u002f\u002fPBVQP5ePoIuCFZA8H9+BGAfVkDioL6GkTZWQNTB\u002fgjDTVZAxuI+i\u002fRkVkC4A38NJnxWQKokv49Xk1ZAnEX\u002fEYmqVkCOZj+UusFWQICHfxbs2FZAcqi\u002fmB3wVkBkyf8aTwdXQFbqP52AHldASAuAH7I1V0A6LMCh40xXQCxNACQVZFdAKvpEC2a9VEAcG4WNl9RUQA48xQ\u002fJ61RAAF0FkvoCVUDyfUUULBpVQOSehZZdMVVA1r\u002fFGI9IVUDI4AWbwF9VQLoBRh3ydlVArCKGnyOOVUCeQ8YhVaVVQJBkBqSGvFVAgoVGJrjTVUB0poao6epVQGbHxiobAlZAWOgGrUwZVkBKCUcvfjBWQDwqh7GvR1ZALkvHM+FeVkAgbAe2EnZWQBKNRzhEjVZABK6HunWkVkD2zsc8p7tWQOjvB7\u002fY0lZA2hBIQQrqVkDMMYjDOwFXQL5SyEVtGFdAsHMIyJ4vV0CilEhK0EZXQJS1iMwBXldAk2LNs1K3VECFgw02hM5UQHekTbi15VRAacWNOuf8VEBb5s28GBRVQE0HDj9KK1VAPyhOwXtCVUAxSY5DrVlVQCNqzsXecFVAFYsOSBCIVUAHrE7KQZ9VQPjMjkxztlVA6u3OzqTNVUDcDg9R1uRVQM4vT9MH\u002fFVAwFCPVTkTVkCycc\u002fXaipWQKSSD1qcQVZAlrNP3M1YVkCI1I9e\u002f29WQHr1z+Awh1ZAbBYQY2KeVkBeN1Dlk7VWQFBYkGfFzFZAQnnQ6fbjVkA0mhBsKPtWQCa7UO5ZEldAGNyQcIspV0AK\u002fdDyvEBXQPwdEXXuV1dA+8pVXD+xVEDt65XecMhUQN8M1mCi31RA0S0W49P2VEDDTlZlBQ5VQLVvluc2JVVAp5DWaWg8VUCZsRbsmVNVQIvSVm7LalVAffOW8PyBVUBvFNdyLplVQGA1F\u002fVfsFVAUlZXd5HHVUBEd5f5wt5VQDaY13v09VVAKLkX\u002fiUNVkAa2leAVyRWQAz7lwKJO1ZA\u002fhvYhLpSVkDwPBgH7GlWQOJdWIkdgVZA1H6YC0+YVkDGn9iNgK9WQLjAGBCyxlZAquFYkuPdVkCcApkUFfVWQI4j2ZZGDFdAgEQZGXgjV0ByZVmbqTpXQGSGmR3bUVdAZDPeBCyrVEBWVB6HXcJUQEh1XgmP2VRAOpaei8DwVEAst94N8gdVQB7YHpAjH1VAEPleElU2VUACGp+Uhk1VQPQ63xa4ZFVA5lsfmel7VUDYfF8bG5NVQMmdn51MqlVAu77fH37BVUCt3x+ir9hVQJ8AYCTh71VAkSGgphIHVkCDQuAoRB5WQHVjIKt1NVZAZ4RgLadMVkBZpaCv2GNWQEvG4DEKe1ZAPecgtDuSVkAvCGE2balWQCEpobiewFZAE0rhOtDXVkAFayG9Ae9WQPaLYT8zBldA6KyhwWQdV0DazeFDljRXQMzuIcbHS1dAzJtmrRilVEC+vKYvSrxUQLDd5rF701RAov4mNK3qVECUH2e23gFVQIZApzgQGVVAeGHnukEwVUBqgic9c0dVQFyjZ7+kXlVATsSnQdZ1VUBA5efDB41VQDIGKEY5pFVAJCdoyGq7VUAWSKhKnNJVQAhp6MzN6VVA+okoT\u002f8AVkDsqmjRMBhWQN7LqFNiL1ZA0Ozo1ZNGVkDCDSlYxV1WQLQuadr2dFZApk+pXCiMVkCYcOneWaNWQIqRKWGLulZAfLJp47zRVkBu06ll7uhWQF\u002f06ecfAFdAURUqalEXV0BDNmrsgi5XQDVXqm60RVdANATvVQWfVEAmJS\u002fYNrZUQBhGb1pozVRACmev3JnkVED8h+9ey\u002ftUQO6oL+H8ElVA4MlvYy4qVUDS6q\u002flX0FVQMQL8GeRWFVAtiww6sJvVUCoTXBs9IZVQJpusO4lnlVAjI\u002fwcFe1VUB+sDDziMxVQHDRcHW641VAYvKw9+v6VUBUE\u002fF5HRJWQEY0MfxOKVZAOFVxfoBAVkAqdrEAsldWQByX8YLjblZADrgxBRWGVkAA2XGHRp1WQPL5sQl4tFZA5Bryi6nLVkDWOzIO2+JWQMdccpAM+lZAuX2yEj4RV0CrnvKUbyhXQJ2\u002fMhehP1dAnGx3\u002fvGYVECOjbeAI7BUQICu9wJVx1RAcs83hYbeVEBk8HcHuPVUQFYRuInpDFVASDL4CxskVUA6UziOTDtVQCx0eBB+UlVAHpW4kq9pVUAQtvgU4YBVQALXOJcSmFVA9Pd4GUSvVUDmGLmbdcZVQNg5+R2n3VVAylo5oNj0VUC8e3kiCgxWQK6cuaQ7I1ZAoL35Jm06VkCS3jmpnlFWQIT\u002feSvQaFZAdiC6rQGAVkBoQfovM5dWQFpiOrJkrlZATIN6NJbFVkA+pLq2x9xWQC\u002fF+jj581ZAIeY6uyoLV0ATB3s9XCJXQAUou7+NOVdABNX\u002fpt6SVED29T8pEKpUQOgWgKtBwVRA2jfALXPYVEDMWACwpO9UQL55QDLWBlVAsJqAtAceVUCiu8A2OTVVQJTcALlqTFVAhv1AO5xjVUB4HoG9zXpVQGo\u002fwT\u002f\u002fkVVAXGABwjCpVUBOgUFEYsBVQECigcaT11VAMsPBSMXuVUAk5AHL9gVWQBYFQk0oHVZACCaCz1k0VkD6RsJRi0tWQOxnAtS8YlZA3ohCVu55VkDQqYLYH5FWQMLKwlpRqFZAtOsC3YK\u002fVkCmDENftNZWQJgtg+Hl7VZAik7DYxcFV0B8bwPmSBxXQG6QQ2h6M1dA","shape":"30, 30"},"type":"surface"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"margin":{"l":0,"r":0,"b":0,"t":40},"scene":{"xaxis":{"title":{"text":"Swing Speed"}},"yaxis":{"title":{"text":"Swing Length"}},"zaxis":{"title":{"text":"Avg Exit Velocity"}}}},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('092e30f3-7a17-49fd-8baf-40f21e7c35e1');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-subfloat-caption quarto-subfloat-fig" id="fig-3dregression-2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
(b)
</figcaption>
</figure>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig quarto-uncaptioned" id="fig-3dregression-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4
</figcaption>
</figure>
</div>
</div>
<p>The residual analysis in Figure&nbsp;5 for the 2025 test data shows that the multivariable linear regression model predicting exit velocity from average swing speed and swing length produces reasonably centered errors. The histogram of residuals appears roughly symmetric and centered near zero, suggesting that the model does not systematically over- or under-predict exit velocity on unseen data.</p>
<p>Quantitatively, the residuals are relatively small in magnitude, which indicates good calibration. However, the presence of some wider residual spread implies that other unmodeled factors—such as point-of-contact, pitch type, or bat-to-ball precision—may be influencing exit velocity and are not captured by swing speed and swing length alone.</p>
<p>Overall, the model performs well given its simplicity and the limited feature set. It serves as a useful first-order approximation for evaluating how mechanical swing inputs affect batted ball output, but more sophisticated modeling approaches (e.g., nonlinear models or additional features) would likely reduce residual variance and improve predictive accuracy.</p>
<div id="cell-fig-residuals" class="cell" data-execution_count="8">
<details class="code-fold">
<summary>Code</summary>
<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">residuals <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> y_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y_pred</span>
<span id="cb10-2">g <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sns.histplot(residuals)</span>
<span id="cb10-3">g.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Histogram of Residuals"</span>)</span>
<span id="cb10-4">g.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Residual (Actual - Predicted Exit Velocity)"</span>)</span>
<span id="cb10-5">g.set_ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Frequency"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div id="fig-residuals" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-residuals-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://runningonnumbers.com/posts/ops-linear-regression/index_files/figure-html/fig-residuals-output-1.png" width="585" height="449" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-residuals-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;5: Residuals of multivariable linear regression.
</figcaption>
</figure>
</div>
</div>
</div>
<p>I leave you all with a clip of the hardest hit ball in the statcast era by Oneil Cruz.</p>
<iframe src="https://streamable.com/m/oneil-cruz-homers-11-on-a-fly-ball-to-right-field?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<p>Thanks for reading!</p>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->


</section>

<div id="quarto-appendix" class="default"><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" data-entry-spacing="0">
<div id="ref-mlb" class="csl-entry">
<span>“Standard <span>Stats</span> <span></span> <span>Glossary</span>.”</span> 2025. <em>MLB.com</em>. <a href="https://www.mlb.com/glossary/standard-stats">https://www.mlb.com/glossary/standard-stats</a>.
</div>
</div></section></div> ]]></description>
  <category>numpy</category>
  <category>regression</category>
  <category>MLB</category>
  <guid>https://runningonnumbers.com/posts/ops-linear-regression/</guid>
  <pubDate>Sun, 15 Jun 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/ops-linear-regression/ops-main.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>Lucky and Unlucky Hitters</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/lucky-hitters/</link>
  <description><![CDATA[ 





<p><img src="https://runningonnumbers.com/posts/lucky-hitters/baseball-clover-cartoon.png" class="img-fluid" style="width:50.0%"></p>
<p>There is no denying that baseball has an element of luck. Sometimes the hardest hit balls find a glove, and sometimes a blooper falls in for a hit. We can try to quantify this luck by looking at the difference between a player’s actual stats and their expected stats.</p>
<section id="expected-batting-average-xba" class="level1">
<h1>Expected Batting Average (xBA)</h1>
<p>First let’s take a look at <a href="https://www.mlb.com/glossary/statcast/expected-batting-average">expected batting average (xBA)</a>. We grab the latest <a href="https://baseballsavant.mlb.com/leaderboard/expected_statistics?type=batter&amp;year=2025&amp;position=&amp;team=&amp;filterType=bip&amp;min=q&amp;sort=7&amp;sortDir=asc">expected statistics leaderboard</a> from baseball savant.</p>
<div id="cbde79fa" class="cell" data-execution_count="1">
<details class="code-fold">
<summary>Code</summary>
<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="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-2"></span>
<span id="cb1-3">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"expected_stats.csv"</span>)</span>
<span id="cb1-4">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"est_ba_minus_ba_diff"</span>].describe().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="1">
<pre><code>count    251.0000
mean      -0.0069
std        0.0283
min       -0.0750
25%       -0.0260
50%       -0.0060
75%        0.0125
max        0.0660
Name: est_ba_minus_ba_diff, dtype: float64</code></pre>
</div>
</div>
<p>The unluckiest batter has as a difference of -0.075, while the luckiest batter has a difference of 0.066. As it stands, Joc Pederson of the Texas Ranges holds unluckiest BA and Pavin Smith of the Arizona Diamondbacks boasts the luckiest BA. Interestingly, the mean xBA is -0.0069, suggesting that the average MLB hitter (with the minimum number of BIP/PA) is slightly unlucky when it comes to batting average.</p>
<iframe src="https://streamable.com/mlbfilmroom/00u91h9ad3Lty1uCX356/unlucky-joc?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<p>Above shows Joc Pederson lining out to Samad Taylor. The batted ball had a hit probability of <a href="https://baseballsavant.mlb.com/gamefeed?gamePk=778083">78% per baseballsavant</a>. Conversely, Pavin Smith’s single to Hyeseong Kim had a 94% chance of becoming an out.</p>
<iframe src="https://streamable.com/m/pavin-smith-singles-on-a-ground-ball-to-second-baseman-hyeseong-kim-geral?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<p>Pederson and Smith are just two players on difference ends of the spectrum. Here is a histogram, illustrating the disitrbution of expected batting average differences. Oberve the slight left-skew distribution.</p>
<div id="7f4c3229" class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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 class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.express <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> px</span>
<span id="cb3-2">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>  px.histogram(df, 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;">"est_ba_minus_ba_diff"</span>, marginal<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;">"rug"</span>, hover_data<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;">"last_name, first_name"</span>],</span>
<span id="cb3-3">    labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-4">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"est_ba_minus_ba_diff"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"BA - xBA"</span>,</span>
<span id="cb3-5">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"count"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Count"</span></span>
<span id="cb3-6">    },</span>
<span id="cb3-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;">"Distribution of xBA Difference"</span></span>
<span id="cb3-8">)</span>
<span id="cb3-9">fig.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
        <script type="text/javascript">
        window.PlotlyConfig = {MathJaxConfig: 'local'};
        if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}
        </script>
        <script type="module">import "https://cdn.plot.ly/plotly-3.0.1.min"</script>
        
</div>
<div class="cell-output cell-output-display">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="b6663386-7d94-4ff6-a14e-a8f8b097a2ee" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("b6663386-7d94-4ff6-a14e-a8f8b097a2ee")) {                    Plotly.newPlot(                        "b6663386-7d94-4ff6-a14e-a8f8b097a2ee",                        [{"bingroup":"x","hovertemplate":"BA - xBA=%{x}\u003cbr\u003ecount=%{y}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"","marker":{"color":"#636efa","pattern":{"shape":""}},"name":"","orientation":"v","showlegend":false,"x":{"dtype":"f8","bdata":"\u002fKnx0k1iYL8AtMh2vp+Kv\u002fyp8dJNYnC\u002fmx6F61G4nr9MN4lBYOWgv3sUrkfhenQ\u002f+n5qvHSTmL\u002f8qfHSTWJwP1pkO99PjZe\u002ff8QgsHJokb99bOf7qfGiv\u002fp+arx0k4i\u002faukmMQisrD\u002f6fmq8dJN4P6xJDAIrh6Y\u002fjcQgsHJoob\u002f8qfHSTWJwPwC0yHa+n4o\u002fObTIdr6fir8IrBxaZDuvv5qZmZmZmam\u002fO99PjZduor\u002f6fmq8dJOIPzs5tMh2vp+\u002fXhSuR+F6lL\u002f81qNwPQqnP\u002fyp8dJNYoA\u002f+n5qvHSTiD8730+Nl26Cv3npJjEIrHw\u002fwH5qvHSTiL\u002fdfmq8dJOYP\u002fp+arx0k4i\u002f\u002fKnx0k1iYD\u002fN+X5qvHSjP\u002fwDVg4tsp0\u002f3X5qvHSTmL\u002f8qfHSTWJwv1zpJjEIrJy\u002fgUkMAiuHhj\u002f8qfHSTWJwP7pJDAIrh5Y\u002fLd9PjZduor956SYxCKyMv\u002fp+arx0k3g\u002feekmMQisfL85tMh2vp+Kv3sUrkfhenS\u002fh35qvHSTeD9c6SYxCKycP7gehetRuJ6\u002fHbTIdr6fmr+eSQwCK4eWv7pJDAIrh4a\u002fHYcW2c73o7+6SQwCK4eWv3npJjEIrJw\u002fP+kmMQisjL+JQWDl0CKrv8B+arx0k4i\u002fQRSuR+F6hL\u002fZzvdT46Wrv\u002fp+arx0k3i\u002f+n5qvHSTiL\u002f81qNwPQqnv\u002fp+arx0k5g\u002fO99PjZdugj+cxCCwcmihP3sUrkfheoS\u002fmpmZmZmZmT85tMh2vp+KP9v5fmq8dJO\u002f+n5qvHSTiL+6SQwCK4eGP3npJjEIrHw\u002f\u002fKnx0k1iYL9YObTIdr6fvxsv3SQGgaU\u002fPIts5\u002fupsb89ZDvfT42Xv14UrkfhepS\u002f\u002fKnx0k1icL\u002fdfmq8dJOYv9+p8dJNYpA\u002f6SYxCKwcqr+4HoXrUbiOPwC0yHa+n4q\u002fO99PjZdugj97FK5H4XqUPwgUrkfhenS\u002f\u002fKnx0k1iYD9Ei2zn+6mxv7gehetRuJ6\u002f2\u002fl+arx0k78IrBxaZDuvv\u002fyp8dJNYoA\u002fuB6F61G4jj97FK5H4XqEP3sUrkfhepQ\u002f\u002fKnx0k1ikD\u002f8qfHSTWJwv\u002fp+arx0k6i\u002fexSuR+F6lL+6SQwCK4eWv3npJjEIrKy\u002f2c73U+Olm7\u002f8qfHSTWKQv\u002fyp8dJNYlC\u002fE35qvHSTaL\u002f8A1YOLbKdv\u002fyp8dJNYlC\u002fPTeJQWDloD\u002f6fmq8dJN4P7gehetRuI6\u002feekmMQisfL956SYxCKx8v38ehetRuI6\u002f\u002fKnx0k1iYL+cxCCwcmiRPzvfT42XbpI\u002fwqnx0k1igD\u002fb+X5qvHSjv\u002f4u3SQGgZW\u002fnMQgsHJoob9MN4lBYOWgv\u002fwDVg4tsp2\u002f\u002fKnx0k1iUL8AAAAAAAAAALgehetRuI6\u002fe0Fg5dAiq7+cxCCwcmiRv7zO91PjpZu\u002f7anx0k1ioD89N4lBYOWgP3sUrkfhepS\u002fK4cW2c73o79q6SYxCKysv3sUrkfhepS\u002fXLx0kxgEpr9YObTIdr6vvzvfT42XbpI\u002f36nx0k1ikD8rhxbZzvejv\u002fyp8dJNYmC\u002fnMQgsHJosb9BFK5H4XqEvzm0yHa+n5o\u002fnPHSTWIQqD8AAAAAAAAAAGrpJjEIrKy\u002f\u002fKnx0k1igD\u002f6fmq8dJOov5zEILByaJE\u002ff8QgsHJokT+8zvdT46Wbv\u002fyp8dJNYnC\u002f+n5qvHSTeD8\u002f6SYxCKyMvwAAAAAAAAAA\u002fi7dJAaBlT+q8dJNYhCoP3npJjEIrJy\u002fObTIdr6fij\u002f6fmq8dJNoP\u002fp+arx0k2g\u002feekmMQisjD+4HoXrUbiePzm0yHa+n4q\u002fXLx0kxgEpj\u002f8qfHSTWKQv\u002fp+arx0k3g\u002fRTeJQWDlsD\u002f8qfHSTWJQP\u002fp+arx0k3i\u002fTGQ730+Npz956SYxCKx8v14UrkfhepS\u002fSgwCK4cWqb+LbOf7qfGivx20yHa+n5o\u002fObTIdr6fmr99mZmZmZmZP\u002fyp8dJNYnA\u002fexSuR+F6lD8K16NwPQqnv6oehetRuK4\u002f\u002fKnx0k1igL\u002f8qfHSTWJgP9+p8dJNYpA\u002fLDMzMzMzs7+4HoXrUbiuv7pJDAIrh4Y\u002f7FG4HoXrob\u002f6fmq8dJNov\u002fp+arx0k4i\u002f\u002fKnx0k1isL+4HoXrUbiuv5zEILByaJE\u002f7anx0k1ioD+bHoXrUbieP3sUrkfhenS\u002fWmQ730+Nlz+4HoXrUbiOvzyLbOf7qbG\u002fnkkMAiuHlr\u002f8qfHSTWKAP4FJDAIrh4a\u002fukkMAiuHlj8pXI\u002fC9Sisv4FJDAIrh4a\u002fAAAAAAAAAABaZDvfT42nPwLfT42XboK\u002f2\u002fl+arx0o7\u002f8qfHSTWJgP7gehetRuJ6\u002f\u002fi7dJAaBlT85tMh2vp+qv3sUrkfheqQ\u002fXhSuR+F6lD\u002f6fmq8dJOoP8Kp8dJNYoC\u002fuB6F61G4jj\u002f8qfHSTWKgvxsv3SQGgZU\u002fvM73U+Olm7956SYxCKyMv\u002f4u3SQGgZU\u002f\u002fKnx0k1igD\u002f6fmq8dJNoP7pJDAIrh6a\u002f\u002fKnx0k1icL8730+Nl26iv+xRuB6F67G\u002fwqnx0k1igL8G6SYxCKx8Pz1kO99PjZe\u002ffZmZmZmZmb85tMh2vp+KP\u002fp+arx0k4i\u002fSgwCK4cWqT\u002f6fmq8dJOoP5zEILByaKG\u002fAAAAAAAAAAD8qfHSTWKgP1zpJjEIrJy\u002fPTeJQWDloD+cxCCwcmiRv\u002fp+arx0k3i\u002fXOkmMQisnL+6SQwCK4eGPw=="},"xaxis":"x","yaxis":"y","type":"histogram"},{"boxpoints":"all","customdata":[["Duran, Jarren"],["Carroll, Corbin"],["Devers, Rafael"],["Tucker, Kyle"],["Ohtani, Shohei"],["Lindor, Francisco"],["Bichette, Bo"],["Chourio, Jackson"],["Nootbaar, Lars"],["Harper, Bryce"],["Rooker, Brent"],["Witt Jr., Bobby"],["Judge, Aaron"],["De La Cruz, Elly"],["Bregman, Alex"],["Schwarber, Kyle"],["Adames, Willy"],["Wood, James"],["Alonso, Pete"],["Soto, Juan"],["Reynolds, Bryan"],["Rodríguez, Julio"],["Riley, Austin"],["Guerrero Jr., Vladimir"],["Soderstrom, Tyler"],["Turner, Trea"],["Paredes, Isaac"],["Kwan, Steven"],["Olson, Matt"],["Raleigh, Cal"],["Albies, Ozzie"],["Crow-Armstrong, Pete"],["Swanson, Dansby"],["Peña, Jeremy"],["Perdomo, Geraldo"],["Ramos, Heliot"],["Pasquantino, Vinnie"],["Torkelson, Spencer"],["Lowe, Nathaniel"],["Naylor, Josh"],["Turang, Brice"],["Friedl, TJ"],["Yelich, Christian"],["Lee, Jung Hoo"],["Castellanos, Nick"],["Suzuki, Seiya"],["Betts, Mookie"],["Donovan, Brendan"],["Butler, Lawrence"],["Altuve, Jose"],["Chapman, Matt"],["Ward, Taylor"],["Suárez, Eugenio"],["Tatis Jr., Fernando"],["Walker, Christian"],["Contreras, Willson"],["Greene, Riley"],["Arozarena, Randy"],["Harris II, Michael"],["Ozuna, Marcell"],["Story, Trevor"],["Semien, Marcus"],["Volpe, Anthony"],["McMahon, Ryan"],["Díaz, Yandy"],["Wilson, Jacob"],["Crawford, J.P."],["Goldschmidt, Paul"],["Larnach, Trevor"],["Garcia, Maikel"],["Ramírez, José"],["Machado, Manny"],["Happ, Ian"],["Contreras, William"],["Hoerner, Nico"],["Arenado, Nolan"],["India, Jonathan"],["Goodman, Hunter"],["Perez, Salvador"],["Gurriel Jr., Lourdes"],["Bohm, Alec"],["Hayes, Ke'Bryan"],["García, Adolis"],["Santana, Carlos"],["Nimmo, Brandon"],["Flores, Wilmer"],["Vargas, Miguel"],["Mullins, Cedric"],["Edwards, Xavier"],["Schanuel, Nolan"],["Soler, Jorge"],["Vaughn, Andrew"],["Bogaerts, Xander"],["France, Ty"],["Robert Jr., Luis"],["Frelick, Sal"],["Bellinger, Cody"],["Pages, Andy"],["Stowers, Kyle"],["Arraez, Luis"],["Bleday, JJ"],["Lowe, Brandon"],["Caminero, Junior"],["Abreu, Wilyer"],["Rutschman, Adley"],["Langeliers, Shea"],["Muncy, Max"],["Stott, Bryson"],["Vientos, Mark"],["Cruz, Oneil"],["Busch, Michael"],["Hoskins, Rhys"],["Carpenter, Kerry"],["Santander, Anthony"],["Toglia, Michael"],["Campbell, Kristian"],["Steer, Spencer"],["Henderson, Gunnar"],["McKinstry, Zach"],["Yastrzemski, Mike"],["Sweeney, Trey"],["McLain, Matt"],["Ruiz, Keibert"],["Mountcastle, Ryan"],["Diaz, Yainer"],["Wagaman, Eric"],["Manzardo, Kyle"],["Springer, George"],["Massey, Michael"],["Conforto, Michael"],["Langford, Wyatt"],["Kepler, Max"],["Lux, Gavin"],["Scott II, Victor"],["Realmuto, J.T."],["Doyle, Brenton"],["García Jr., Luis"],["McCutchen, Andrew"],["Rice, Ben"],["Crews, Dylan"],["Buxton, Byron"],["Arias, Gabriel"],["Rafaela, Ceddanne"],["Holliday, Jackson"],["Ortiz, Joey"],["Sosa, Lenyn"],["Meyers, Jake"],["Freeman, Freddie"],["Abrams, CJ"],["Bell, Josh"],["Aranda, Jonathan"],["Rengifo, Luis"],["O'Hoppe, Logan"],["Jung, Josh"],["Torres, Gleyber"],["Domínguez, Jasson"],["Winn, Masyn"],["Wells, Austin"],["Smith, Josh"],["Sheets, Gavin"],["Smith, Will"],["Correa, Carlos"],["Bart, Joey"],["O'Hearn, Ryan"],["Frazier, Adam"],["Beck, Jordan"],["Espinal, Santiago"],["Kirk, Alejandro"],["Báez, Javier"],["Grisham, Trent"],["Jeffers, Ryan"],["Smith, Pavin"],["Clement, Ernie"],["Walker, Jordan"],["Andujar, Miguel"],["Hernández, Teoscar"],["Burger, Jake"],["Keith, Colt"],["Wade Jr., LaMonte"],["Kiner-Falefa, Isiah"],["Taylor, Tyrone"],["Allen, Nick"],["Dingler, Dillon"],["Misner, Kameron"],["Moniak, Mickey"],["Bader, Harrison"],["Bailey, Patrick"],["Heim, Jonah"],["Farmer, Kyle"],["Pederson, Joc"],["Giménez, Andrés"],["Smith, Cam"],["Polanco, Jorge"],["Moreno, Gabriel"],["Baldwin, Brooks"],["Edman, Tommy"],["Adell, Jo"],["Thomas, Alek"],["Narváez, Carlos"],["Burleson, Alec"],["Neto, Zach"],["Taveras, Leody"],["Pham, Tommy"],["Lopez, Otto"],["Walls, Taylor"],["Paris, Kyren"],["Naylor, Bo"],["Urías, Luis"],["Jones, Nolan"],["Morel, Christopher"],["Acuña, Luisangel"],["Isbel, Kyle"],["Lee, Brooks"],["Kjerstad, Heston"],["Pagés, Pedro"],["Sánchez, Jesús"],["Caballero, José"],["Young, Jacob"],["Martínez, Angel"],["Mervis, Matt"],["Call, Alex"],["White, Eli"],["Moore, Dylan"],["Chisholm Jr., Jazz"],["Waters, Drew"],["Verdugo, Alex"],["Jansen, Danny"],["Kelly, Carson"],["Murphy, Sean"],["Schneemann, Daniel"],["Tellez, Rowdy"],["Cabrera, Oswaldo"],["Alvarez, Yordan"],["Trout, Mike"],["Williamson, Ben"],["Castro, Willi"],["Durbin, Caleb"],["Hernández, Enrique"],["Díaz, Elias"],["Sanoja, Javier"],["Fitzgerald, Tyler"],["Norby, Connor"],["Casas, Triston"],["Iglesias, Jose"],["Urías, Ramón"],["Marte, Ketel"],["Meidroth, Chase"],["Ramírez, Agustín"],["Simpson, Chandler"],["Lukes, Nathan"],["Laureano, Ramón"]],"fillcolor":"rgba(255,255,255,0)","hoveron":"points","hovertemplate":"BA - xBA=%{x}\u003cbr\u003elast_name, first_name=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","jitter":0,"legendgroup":"","line":{"color":"rgba(255,255,255,0)"},"marker":{"color":"#636efa","symbol":"line-ns-open"},"name":"","showlegend":false,"x":{"dtype":"f8","bdata":"\u002fKnx0k1iYL8AtMh2vp+Kv\u002fyp8dJNYnC\u002fmx6F61G4nr9MN4lBYOWgv3sUrkfhenQ\u002f+n5qvHSTmL\u002f8qfHSTWJwP1pkO99PjZe\u002ff8QgsHJokb99bOf7qfGiv\u002fp+arx0k4i\u002faukmMQisrD\u002f6fmq8dJN4P6xJDAIrh6Y\u002fjcQgsHJoob\u002f8qfHSTWJwPwC0yHa+n4o\u002fObTIdr6fir8IrBxaZDuvv5qZmZmZmam\u002fO99PjZduor\u002f6fmq8dJOIPzs5tMh2vp+\u002fXhSuR+F6lL\u002f81qNwPQqnP\u002fyp8dJNYoA\u002f+n5qvHSTiD8730+Nl26Cv3npJjEIrHw\u002fwH5qvHSTiL\u002fdfmq8dJOYP\u002fp+arx0k4i\u002f\u002fKnx0k1iYD\u002fN+X5qvHSjP\u002fwDVg4tsp0\u002f3X5qvHSTmL\u002f8qfHSTWJwv1zpJjEIrJy\u002fgUkMAiuHhj\u002f8qfHSTWJwP7pJDAIrh5Y\u002fLd9PjZduor956SYxCKyMv\u002fp+arx0k3g\u002feekmMQisfL85tMh2vp+Kv3sUrkfhenS\u002fh35qvHSTeD9c6SYxCKycP7gehetRuJ6\u002fHbTIdr6fmr+eSQwCK4eWv7pJDAIrh4a\u002fHYcW2c73o7+6SQwCK4eWv3npJjEIrJw\u002fP+kmMQisjL+JQWDl0CKrv8B+arx0k4i\u002fQRSuR+F6hL\u002fZzvdT46Wrv\u002fp+arx0k3i\u002f+n5qvHSTiL\u002f81qNwPQqnv\u002fp+arx0k5g\u002fO99PjZdugj+cxCCwcmihP3sUrkfheoS\u002fmpmZmZmZmT85tMh2vp+KP9v5fmq8dJO\u002f+n5qvHSTiL+6SQwCK4eGP3npJjEIrHw\u002f\u002fKnx0k1iYL9YObTIdr6fvxsv3SQGgaU\u002fPIts5\u002fupsb89ZDvfT42Xv14UrkfhepS\u002f\u002fKnx0k1icL\u002fdfmq8dJOYv9+p8dJNYpA\u002f6SYxCKwcqr+4HoXrUbiOPwC0yHa+n4q\u002fO99PjZdugj97FK5H4XqUPwgUrkfhenS\u002f\u002fKnx0k1iYD9Ei2zn+6mxv7gehetRuJ6\u002f2\u002fl+arx0k78IrBxaZDuvv\u002fyp8dJNYoA\u002fuB6F61G4jj97FK5H4XqEP3sUrkfhepQ\u002f\u002fKnx0k1ikD\u002f8qfHSTWJwv\u002fp+arx0k6i\u002fexSuR+F6lL+6SQwCK4eWv3npJjEIrKy\u002f2c73U+Olm7\u002f8qfHSTWKQv\u002fyp8dJNYlC\u002fE35qvHSTaL\u002f8A1YOLbKdv\u002fyp8dJNYlC\u002fPTeJQWDloD\u002f6fmq8dJN4P7gehetRuI6\u002feekmMQisfL956SYxCKx8v38ehetRuI6\u002f\u002fKnx0k1iYL+cxCCwcmiRPzvfT42XbpI\u002fwqnx0k1igD\u002fb+X5qvHSjv\u002f4u3SQGgZW\u002fnMQgsHJoob9MN4lBYOWgv\u002fwDVg4tsp2\u002f\u002fKnx0k1iUL8AAAAAAAAAALgehetRuI6\u002fe0Fg5dAiq7+cxCCwcmiRv7zO91PjpZu\u002f7anx0k1ioD89N4lBYOWgP3sUrkfhepS\u002fK4cW2c73o79q6SYxCKysv3sUrkfhepS\u002fXLx0kxgEpr9YObTIdr6vvzvfT42XbpI\u002f36nx0k1ikD8rhxbZzvejv\u002fyp8dJNYmC\u002fnMQgsHJosb9BFK5H4XqEvzm0yHa+n5o\u002fnPHSTWIQqD8AAAAAAAAAAGrpJjEIrKy\u002f\u002fKnx0k1igD\u002f6fmq8dJOov5zEILByaJE\u002ff8QgsHJokT+8zvdT46Wbv\u002fyp8dJNYnC\u002f+n5qvHSTeD8\u002f6SYxCKyMvwAAAAAAAAAA\u002fi7dJAaBlT+q8dJNYhCoP3npJjEIrJy\u002fObTIdr6fij\u002f6fmq8dJNoP\u002fp+arx0k2g\u002feekmMQisjD+4HoXrUbiePzm0yHa+n4q\u002fXLx0kxgEpj\u002f8qfHSTWKQv\u002fp+arx0k3g\u002fRTeJQWDlsD\u002f8qfHSTWJQP\u002fp+arx0k3i\u002fTGQ730+Npz956SYxCKx8v14UrkfhepS\u002fSgwCK4cWqb+LbOf7qfGivx20yHa+n5o\u002fObTIdr6fmr99mZmZmZmZP\u002fyp8dJNYnA\u002fexSuR+F6lD8K16NwPQqnv6oehetRuK4\u002f\u002fKnx0k1igL\u002f8qfHSTWJgP9+p8dJNYpA\u002fLDMzMzMzs7+4HoXrUbiuv7pJDAIrh4Y\u002f7FG4HoXrob\u002f6fmq8dJNov\u002fp+arx0k4i\u002f\u002fKnx0k1isL+4HoXrUbiuv5zEILByaJE\u002f7anx0k1ioD+bHoXrUbieP3sUrkfhenS\u002fWmQ730+Nlz+4HoXrUbiOvzyLbOf7qbG\u002fnkkMAiuHlr\u002f8qfHSTWKAP4FJDAIrh4a\u002fukkMAiuHlj8pXI\u002fC9Sisv4FJDAIrh4a\u002fAAAAAAAAAABaZDvfT42nPwLfT42XboK\u002f2\u002fl+arx0o7\u002f8qfHSTWJgP7gehetRuJ6\u002f\u002fi7dJAaBlT85tMh2vp+qv3sUrkfheqQ\u002fXhSuR+F6lD\u002f6fmq8dJOoP8Kp8dJNYoC\u002fuB6F61G4jj\u002f8qfHSTWKgvxsv3SQGgZU\u002fvM73U+Olm7956SYxCKyMv\u002f4u3SQGgZU\u002f\u002fKnx0k1igD\u002f6fmq8dJNoP7pJDAIrh6a\u002f\u002fKnx0k1icL8730+Nl26iv+xRuB6F67G\u002fwqnx0k1igL8G6SYxCKx8Pz1kO99PjZe\u002ffZmZmZmZmb85tMh2vp+KP\u002fp+arx0k4i\u002fSgwCK4cWqT\u002f6fmq8dJOoP5zEILByaKG\u002fAAAAAAAAAAD8qfHSTWKgP1zpJjEIrJy\u002fPTeJQWDloD+cxCCwcmiRv\u002fp+arx0k3i\u002fXOkmMQisnL+6SQwCK4eGPw=="},"xaxis":"x2","yaxis":"y2","type":"box"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"BA - xBA"}},"yaxis":{"anchor":"x","domain":[0.0,0.8316],"title":{"text":"count"}},"xaxis2":{"anchor":"y2","domain":[0.0,1.0],"matches":"x","showticklabels":false,"showgrid":true},"yaxis2":{"anchor":"x2","domain":[0.8416,1.0],"matches":"y2","showticklabels":false,"showline":false,"ticks":"","showgrid":false},"legend":{"tracegroupgap":0},"title":{"text":"Distribution of xBA Difference"},"barmode":"relative"},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('b6663386-7d94-4ff6-a14e-a8f8b097a2ee');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
</div>
<p>Pretty close correlation between xBA and BA with an <img src="https://latex.codecogs.com/png.latex?R%5E2"> value of 0.48. xBA is not a perfect indicator of BA. In fact, xBA should be interpreted more heavily than BA given that it removes luck from the at-bat. Note that there remains a sizable discrepancy between xBA and BA, suggesting a sizable “luck” component observed in BA that xBA does not capture.</p>
<div id="9f52e20b" class="cell" data-execution_count="3">
<details class="code-fold">
<summary>Code</summary>
<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 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> r2_score</span>
<span id="cb4-2"></span>
<span id="cb4-3">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> px.scatter(df, 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;">"est_ba"</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;">"ba"</span>, hover_data<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;">"last_name, first_name"</span>], trendline<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;">"ols"</span>,</span>
<span id="cb4-4">    labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb4-5">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"est_ba"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xBA"</span>,</span>
<span id="cb4-6">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ba"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"BA"</span></span>
<span id="cb4-7">    },</span>
<span id="cb4-8">    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;">"Relationship Between xBA and BA"</span></span>
<span id="cb4-9">)</span>
<span id="cb4-10"></span>
<span id="cb4-11">fig.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="8c510b5a-f9b5-4d8b-8eaa-b46f18131d13" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("8c510b5a-f9b5-4d8b-8eaa-b46f18131d13")) {                    Plotly.newPlot(                        "8c510b5a-f9b5-4d8b-8eaa-b46f18131d13",                        [{"customdata":[["Duran, Jarren"],["Carroll, Corbin"],["Devers, Rafael"],["Tucker, Kyle"],["Ohtani, Shohei"],["Lindor, Francisco"],["Bichette, Bo"],["Chourio, Jackson"],["Nootbaar, Lars"],["Harper, Bryce"],["Rooker, Brent"],["Witt Jr., Bobby"],["Judge, Aaron"],["De La Cruz, Elly"],["Bregman, Alex"],["Schwarber, Kyle"],["Adames, Willy"],["Wood, James"],["Alonso, Pete"],["Soto, Juan"],["Reynolds, Bryan"],["Rodríguez, Julio"],["Riley, Austin"],["Guerrero Jr., Vladimir"],["Soderstrom, Tyler"],["Turner, Trea"],["Paredes, Isaac"],["Kwan, Steven"],["Olson, Matt"],["Raleigh, Cal"],["Albies, Ozzie"],["Crow-Armstrong, Pete"],["Swanson, Dansby"],["Peña, Jeremy"],["Perdomo, Geraldo"],["Ramos, Heliot"],["Pasquantino, Vinnie"],["Torkelson, Spencer"],["Lowe, Nathaniel"],["Naylor, Josh"],["Turang, Brice"],["Friedl, TJ"],["Yelich, Christian"],["Lee, Jung Hoo"],["Castellanos, Nick"],["Suzuki, Seiya"],["Betts, Mookie"],["Donovan, Brendan"],["Butler, Lawrence"],["Altuve, Jose"],["Chapman, Matt"],["Ward, Taylor"],["Suárez, Eugenio"],["Tatis Jr., Fernando"],["Walker, Christian"],["Contreras, Willson"],["Greene, Riley"],["Arozarena, Randy"],["Harris II, Michael"],["Ozuna, Marcell"],["Story, Trevor"],["Semien, Marcus"],["Volpe, Anthony"],["McMahon, Ryan"],["Díaz, Yandy"],["Wilson, Jacob"],["Crawford, J.P."],["Goldschmidt, Paul"],["Larnach, Trevor"],["Garcia, Maikel"],["Ramírez, José"],["Machado, Manny"],["Happ, Ian"],["Contreras, William"],["Hoerner, Nico"],["Arenado, Nolan"],["India, Jonathan"],["Goodman, Hunter"],["Perez, Salvador"],["Gurriel Jr., Lourdes"],["Bohm, Alec"],["Hayes, Ke'Bryan"],["García, Adolis"],["Santana, Carlos"],["Nimmo, Brandon"],["Flores, Wilmer"],["Vargas, Miguel"],["Mullins, Cedric"],["Edwards, Xavier"],["Schanuel, Nolan"],["Soler, Jorge"],["Vaughn, Andrew"],["Bogaerts, Xander"],["France, Ty"],["Robert Jr., Luis"],["Frelick, Sal"],["Bellinger, Cody"],["Pages, Andy"],["Stowers, Kyle"],["Arraez, Luis"],["Bleday, JJ"],["Lowe, Brandon"],["Caminero, Junior"],["Abreu, Wilyer"],["Rutschman, Adley"],["Langeliers, Shea"],["Muncy, Max"],["Stott, Bryson"],["Vientos, Mark"],["Cruz, Oneil"],["Busch, Michael"],["Hoskins, Rhys"],["Carpenter, Kerry"],["Santander, Anthony"],["Toglia, Michael"],["Campbell, Kristian"],["Steer, Spencer"],["Henderson, Gunnar"],["McKinstry, Zach"],["Yastrzemski, Mike"],["Sweeney, Trey"],["McLain, Matt"],["Ruiz, Keibert"],["Mountcastle, Ryan"],["Diaz, Yainer"],["Wagaman, Eric"],["Manzardo, Kyle"],["Springer, George"],["Massey, Michael"],["Conforto, Michael"],["Langford, Wyatt"],["Kepler, Max"],["Lux, Gavin"],["Scott II, Victor"],["Realmuto, J.T."],["Doyle, Brenton"],["García Jr., Luis"],["McCutchen, Andrew"],["Rice, Ben"],["Crews, Dylan"],["Buxton, Byron"],["Arias, Gabriel"],["Rafaela, Ceddanne"],["Holliday, Jackson"],["Ortiz, Joey"],["Sosa, Lenyn"],["Meyers, Jake"],["Freeman, Freddie"],["Abrams, CJ"],["Bell, Josh"],["Aranda, Jonathan"],["Rengifo, Luis"],["O'Hoppe, Logan"],["Jung, Josh"],["Torres, Gleyber"],["Domínguez, Jasson"],["Winn, Masyn"],["Wells, Austin"],["Smith, Josh"],["Sheets, Gavin"],["Smith, Will"],["Correa, Carlos"],["Bart, Joey"],["O'Hearn, Ryan"],["Frazier, Adam"],["Beck, Jordan"],["Espinal, Santiago"],["Kirk, Alejandro"],["Báez, Javier"],["Grisham, Trent"],["Jeffers, Ryan"],["Smith, Pavin"],["Clement, Ernie"],["Walker, Jordan"],["Andujar, Miguel"],["Hernández, Teoscar"],["Burger, Jake"],["Keith, Colt"],["Wade Jr., LaMonte"],["Kiner-Falefa, Isiah"],["Taylor, Tyrone"],["Allen, Nick"],["Dingler, Dillon"],["Misner, Kameron"],["Moniak, Mickey"],["Bader, Harrison"],["Bailey, Patrick"],["Heim, Jonah"],["Farmer, Kyle"],["Pederson, Joc"],["Giménez, Andrés"],["Smith, Cam"],["Polanco, Jorge"],["Moreno, Gabriel"],["Baldwin, Brooks"],["Edman, Tommy"],["Adell, Jo"],["Thomas, Alek"],["Narváez, Carlos"],["Burleson, Alec"],["Neto, Zach"],["Taveras, Leody"],["Pham, Tommy"],["Lopez, Otto"],["Walls, Taylor"],["Paris, Kyren"],["Naylor, Bo"],["Urías, Luis"],["Jones, Nolan"],["Morel, Christopher"],["Acuña, Luisangel"],["Isbel, Kyle"],["Lee, Brooks"],["Kjerstad, Heston"],["Pagés, Pedro"],["Sánchez, Jesús"],["Caballero, José"],["Young, Jacob"],["Martínez, Angel"],["Mervis, Matt"],["Call, Alex"],["White, Eli"],["Moore, Dylan"],["Chisholm Jr., Jazz"],["Waters, Drew"],["Verdugo, Alex"],["Jansen, Danny"],["Kelly, Carson"],["Murphy, Sean"],["Schneemann, Daniel"],["Tellez, Rowdy"],["Cabrera, Oswaldo"],["Alvarez, Yordan"],["Trout, Mike"],["Williamson, Ben"],["Castro, Willi"],["Durbin, Caleb"],["Hernández, Enrique"],["Díaz, Elias"],["Sanoja, Javier"],["Fitzgerald, Tyler"],["Norby, Connor"],["Casas, Triston"],["Iglesias, Jose"],["Urías, Ramón"],["Marte, Ketel"],["Meidroth, Chase"],["Ramírez, Agustín"],["Simpson, Chandler"],["Lukes, Nathan"],["Laureano, Ramón"]],"hovertemplate":"xBA=%{x}\u003cbr\u003eBA=%{y}\u003cbr\u003elast_name, first_name=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"","marker":{"color":"#636efa","symbol":"circle"},"mode":"markers","name":"","orientation":"v","showlegend":false,"x":{"dtype":"f8","bdata":"SOF6FK5H0T+TGARWDi3SPzEIrBxaZNM\u002fL90kBoGV0z9xPQrXo3DVP5zEILByaNE\u002fg8DKoUW20z+wcmiR7XzPP0jhehSuR9E\u002fO99PjZdu0j8\u002fNV66SQzSPylcj8L1KNQ\u002fF9nO91Pj1T8UrkfhehTOP1K4HoXrUdA\u002fPQrXo3A90j+JQWDl0CLLP5zEILByaNE\u002fMzMzMzMz0z81XrpJDALTP05iEFg5tNA\u002foBov3SQG0T9OYhBYObTQP4XrUbgehdM\u002f4XoUrkfh0j\u002f2KFyPwvXQP\u002fp+arx0k9A\u002f16NwPQrX0z+oxks3iUHQP6rx0k1iENA\u002fEFg5tMh2zj+iRbbz\u002fdTQP\u002fCnxks3idE\u002fj8L1KFyP0j9OYhBYObTQP0w3iUFg5dA\u002fUI2XbhKD0D9YObTIdr7PP6rx0k1iENA\u002fmG4Sg8DK0T9GtvP91HjRP1K4HoXrUdA\u002fFK5H4XoUzj+LbOf7qfHSP\u002fT91HjpJtE\u002fnu+nxks30T+cxCCwcmjRP3e+nxov3dQ\u002fcT0K16NwzT\u002fNzMzMzMzMP6wcWmQ7388\u002fqMZLN4lB0D9g5dAi2\u002fnOPzMzMzMzM9M\u002fFK5H4XoUzj+cxCCwcmjRP1TjpZvEINA\u002fXI\u002fC9Shczz+YbhKDwMrRPz0K16NwPdI\u002fvHSTGARWzj\u002fFILByaJHNPwwCK4cW2c4\u002fJQaBlUOLzD83iUFg5dDSP4GVQ4ts59M\u002fppvEILBy0D\u002fdJAaBlUPTP\u002f7UeOkmMdA\u002fj8L1KFyP0j+Nl24Sg8DSP8uhRbbz\u002fdQ\u002f8tJNYhBY0T9g5dAi2\u002fnOP+XQItv5ftI\u002fXI\u002fC9Shczz\u002f4U+Olm8TQP2Q730+Nl84\u002f46WbxCCw0j\u002f+1HjpJjHQP+XQItv5ftI\u002ftMh2vp8azz8UrkfhehTOP9V46SYxCMw\u002fokW28\u002f3U0D9g5dAi2\u002fnOP7TIdr6fGs8\u002fKVyPwvUozD+0yHa+nxrPPz0K16NwPdI\u002fzczMzMzMzD9QjZduEoPQP6AaL90kBtE\u002fnMQgsHJo0T8MAiuHFtnOP0w3iUFg5dA\u002fYOXQItv5zj+mm8QgsHLQP4lBYOXQItM\u002f6SYxCKwc0j85tMh2vp\u002fKP5zEILByaNE\u002fppvEILBy0D9CYOXQItvRP0jhehSuR9E\u002f8tJNYhBY0T\u002fRItv5fmrMP6RwPQrXo9A\u002fFK5H4XoUzj9QjZduEoPQP6jGSzeJQdA\u002foBov3SQG0T\u002fwp8ZLN4nRP5ZDi2zn+8k\u002fiUFg5dAiyz8ZBFYOLbLNP7gehetRuM4\u002f9ihcj8L10D+kcD0K16PQPwAAAAAAANA\u002fxSCwcmiRzT+JQWDl0CLLPzVeukkMAtM\u002foBov3SQG0T+kcD0K16PQPz81XrpJDNI\u002fhetRuB6Fyz\u002f6fmq8dJPQPx1aZDvfT80\u002fKVyPwvUozD\u002f4U+Olm8TQP\u002fyp8dJNYtA\u002fpHA9Ctej0D8AAAAAAADQP05iEFg5tNA\u002f\u002ftR46SYx0D+R7Xw\u002fNV7SP5qZmZmZmdE\u002fO99PjZdu0j9QjZduEoPQP7TIdr6fGs8\u002fJQaBlUOLzD+amZmZmZnRP\u002fCnxks3idE\u002fDAIrhxbZzj\u002fl0CLb+X7SP+kmMQisHNI\u002ff2q8dJMY1D8xCKwcWmTTP+F6FK5H4co\u002f30+Nl24S0z\u002f2KFyPwvXQP6abxCCwctA\u002f8tJNYhBY0T\u002ffT42XbhLTP2Dl0CLb+c4\u002fUrgehetR0D+F61G4HoXLP\u002fCnxks3idE\u002fTDeJQWDl0D\u002fl0CLb+X7SP\u002fLSTWIQWNE\u002fCKwcWmQ7zz9\u002farx0kxjUP2iR7Xw\u002fNc4\u002fppvEILBy0D9kO99PjZfOP4ts5\u002fup8dI\u002fAAAAAAAA0D\u002fufD81XrrRP6AaL90kBtE\u002ffT81XrpJzD\u002f+1HjpJjHQP5qZmZmZmck\u002foBov3SQG0T99PzVeuknUPwwCK4cW2c4\u002f9P3UeOkm0T\u002fhehSuR+HKP\u002fT91HjpJtE\u002fmG4Sg8DK0T91kxgEVg7NPzeJQWDl0NI\u002f3SQGgZVDyz+kcD0K16PQPyUGgZVDi8w\u002fAiuHFtnOxz9U46WbxCDQP8l2vp8aL80\u002f5dAi2\u002fl+yj9SuB6F61HQP7TIdr6fGs8\u002fexSuR+F61D\u002fwp8ZLN4nRP3WTGARWDs0\u002fhxbZzvdT0z+wcmiR7XzPP6wcWmQ7388\u002f+n5qvHST0D9SuB6F61HQP+Olm8QgsNI\u002fke18PzVeyj9CYOXQItvJP5HtfD81XtI\u002fObTIdr6fyj9SuB6F61HIP42XbhKDwMo\u002fWDm0yHa+zz\u002fByqFFtvPNP90kBoGVQ8s\u002f\u002fKnx0k1i0D9xPQrXo3DNP2Q730+Nl84\u002ftMh2vp8azz+BlUOLbOfLP\u002fp+arx0k9A\u002fdZMYBFYOzT9CYOXQItvRP7x0kxgEVs4\u002fJzEIrBxaxD\u002fJdr6fGi\u002fNPz81XrpJDNI\u002f+FPjpZvE0D\u002fdJAaBlUPLPwAAAAAAANA\u002fO99PjZdu0j+BlUOLbOfLP6AaL90kBtE\u002fMQisHFpkyz8EVg4tsp3PP6wcWmQ7388\u002fBFYOLbKdzz+wcmiR7XzPP6wcWmQ7388\u002fDAIrhxbZzj8dWmQ730\u002fNP42XbhKDwMo\u002fAAAAAAAA0D8pXI\u002fC9SjMPwAAAAAAANA\u002fIbByaJHtzD8hsHJoke3MP9nO91Pjpcs\u002ftMh2vp8azz+wcmiR7XzPPzVeukkMAtM\u002fRIts5\u002fup0T9I4XoUrkfRP4ts5\u002fup8dI\u002f46WbxCCw0j9SuB6F61HQPw=="},"xaxis":"x","y":{"dtype":"f8","bdata":"9P3UeOkm0T\u002fy0k1iEFjRP4lBYOXQItM\u002fRIts5\u002fup0T+HFtnO91PTP+58PzVeutE\u002fkxgEVg4t0j8AAAAAAADQPwRWDi2ync8\u002f8tJNYhBY0T9cj8L1KFzPPzEIrBxaZNM\u002fRrbz\u002fdR42T8MAiuHFtnOP4lBYOXQItM\u002fqvHSTWIQ0D\u002fZzvdT46XLPz0K16NwPdI\u002fke18PzVe0j9oke18PzXOPzVeukkMAss\u002fcT0K16NwzT9GtvP91HjRP\u002fCnxks3idE\u002fmpmZmZmZ0T\u002fXo3A9CtfTP0oMAiuHFtE\u002fz\u002fdT46Wb1D9cj8L1KFzPP1CNl24Sg9A\u002fIbByaJHtzD+R7Xw\u002fNV7SP\u002fhT46WbxNA\u002f46WbxCCw0j+JQWDl0CLTP42XbhKDwNI\u002fwcqhRbbzzT8IrBxaZDvPPyUGgZVDi8w\u002f5dAi2\u002fl+0j\u002fufD81XrrRP+58PzVeutE\u002fRrbz\u002fdR4yT8\u002fNV66SQzSP\u002fCnxks3idE\u002f+FPjpZvE0D\u002f6fmq8dJPQPyUGgZVDi9Q\u002faJHtfD81zj\u002f+1HjpJjHQP9V46SYxCMw\u002fyXa+nxovzT8pXI\u002fC9SjMP+XQItv5ftI\u002fSgwCK4cWyT8AAAAAAADQP+xRuB6F69E\u002fxSCwcmiRzT\u002fNzMzMzMzMP0a28\u002f3UeNE\u002fdZMYBFYOzT8OLbKd76fGPxSuR+F6FM4\u002fNV66SQwCyz+sHFpkO9\u002fPP3E9CtejcNU\u002foBov3SQG0T9xPQrXo3DVP7TIdr6fGs8\u002fKVyPwvUo1D8v3SQGgZXTPy2yne+nxtM\u002f+n5qvHST0D\u002f+1HjpJjHQP4ts5\u002fup8dI\u002ftMh2vp8azz\u002fFILByaJHNP5ZDi2zn+9E\u002fJQaBlUOLzD9xPQrXo3DNP57vp8ZLN9E\u002fZDvfT42Xzj81XrpJDALLPxSuR+F6FM4\u002fiUFg5dAiyz+mm8QgsHLQP3E9CtejcM0\u002fHVpkO99PzT+iRbbz\u002fdTQP+xRuB6F69E\u002fdZMYBFYOzT\u002f+1HjpJjHIP2iR7Xw\u002fNc4\u002f\u002ftR46SYx0D8K16NwPQrHP5zEILByaNE\u002fppvEILBy0D9KDAIrhxbRP9Ei2\u002fl+atQ\u002fiUFg5dAi0z\u002fpJjEIrBzKP3npJjEIrMw\u002fvHSTGARWzj+mm8QgsHLQPzEIrBxaZMs\u002fCKwcWmQ7zz+R7Xw\u002fNV7KP\u002fp+arx0k9A\u002fGQRWDi2yzT8dWmQ730\u002fNP\u002f7UeOkmMdA\u002fiUFg5dAi0z\u002fsUbgehevRP6rx0k1iEMg\u002fPQrXo3A9yj\u002fNzMzMzMzMP83MzMzMzMw\u002fokW28\u002f3U0D\u002fufD81XrrRP\u002fT91HjpJtE\u002fZDvfT42Xzj8Sg8DKoUXGP0SLbOf7qdE\u002fGQRWDi2yzT91kxgEVg7NP\u002f7UeOkmMdA\u002fMQisHFpkyz\u002f6fmq8dJPQPzEIrBxaZMs\u002fx0s3iUFgxT9cj8L1KFzPPx1aZDvfT80\u002f46WbxCCw0j\u002fpJjEIrBzSPwwCK4cW2c4\u002fMQisHFpkyz\u002fFILByaJHNP1K4HoXrUdA\u002fXI\u002fC9Shczz9KDAIrhxbJP05iEFg5tNA\u002fZDvfT42Xzj9oke18PzXOP5zEILByaNE\u002fvp8aL90kxj9CYOXQItvRPy2yne+nxtM\u002ftMh2vp8a1z8xCKwcWmTTP4PAyqFFtsM\u002fL90kBoGV0z8tsp3vp8bLP\u002fCnxks3idE\u002fO99PjZdu0j\u002fy0k1iEFjRPxBYObTIds4\u002fTmIQWDm00D\u002fufD81XrrJP\u002fCnxks3idE\u002fPQrXo3A90j8bL90kBoHVP7TIdr6fGs8\u002fppvEILBy0D99PzVeuknUP2Q730+Nl84\u002f8tJNYhBY0T+e76fGSzfRP+kmMQisHNI\u002fjZduEoPA0j9OYhBYObTQP5zEILByaNE\u002fke18PzVe0j+oxks3iUHQP6JFtvP91Mg\u002fK4cW2c730z\u002fXo3A9CtfTP30\u002fNV66Scw\u002f1XjpJjEIzD++nxov3STGPzeJQWDl0NI\u002fVOOlm8Qg0D9U46WbxCDQP99PjZduEtM\u002fbef7qfHSzT+F61G4HoXLP+kmMQisHNI\u002fYhBYObTIxj+oxks3iUHQPwisHFpkO88\u002fTDeJQWDlwD\u002f2KFyPwvXIP6jGSzeJQdA\u002fPQrXo3A90j\u002fy0k1iEFjRP4XrUbgehcs\u002fEFg5tMh2zj8CK4cW2c7HP6AaL90kBtE\u002fObTIdr6f0j89CtejcD3SP5HtfD81XtI\u002fHVpkO99PzT9WDi2yne\u002fHP4GVQ4ts58s\u002fAiuHFtnOxz\u002fy0k1iEFjJP\u002fLSTWIQWMk\u002fSOF6FK5H0T+28\u002f3UeOnGP0Jg5dAi28k\u002f\u002fKnx0k1i0D9Ei2zn+6nRP3E9CtejcM0\u002fPQrXo3A9yj8pXI\u002fC9SjMPx1aZDvfT80\u002fWDm0yHa+zz91kxgEVg7NP+58PzVeutE\u002ftvP91Hjpxj9Ei2zn+6nRP\u002fCnxks3idE\u002f7nw\u002fNV660T9eukkMAivHP\u002fLSTWIQWNE\u002fTmIQWDm00D\u002fpJjEIrBzKP5HtfD81XtI\u002f0SLb+X5qzD8AAAAAAADQPz0K16NwPco\u002ftMh2vp8azz\u002fhehSuR+HKP7bz\u002fdR46cY\u002fbef7qfHSzT9oke18PzXOPwIrhxbZzsc\u002fzczMzMzMzD9t5\u002fup8dLNPxBYObTIds4\u002fmpmZmZmZ0T\u002fwp8ZLN4nRP7Kd76fGS8c\u002ftMh2vp8azz+YbhKDwMrRP57vp8ZLN9E\u002fLbKd76fG0z\u002f+1HjpJjHQP4\u002fC9Shcj9I\u002fTDeJQWDl0D+gGi\u002fdJAbRPw=="},"yaxis":"y","type":"scatter"},{"hovertemplate":"\u003cb\u003eOLS trendline\u003c\u002fb\u003e\u003cbr\u003eba = 0.913436 * est_ba + 0.0154085\u003cbr\u003eR\u003csup\u003e2\u003c\u002fsup\u003e=0.482529\u003cbr\u003e\u003cbr\u003exBA=%{x}\u003cbr\u003eBA=%{y} \u003cb\u003e(trend)\u003c\u002fb\u003e\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"","marker":{"color":"#636efa","symbol":"circle"},"mode":"lines","name":"","showlegend":false,"x":{"dtype":"f8","bdata":"JzEIrBxaxD8CK4cW2c7HP1K4HoXrUcg\u002fmpmZmZmZyT9CYOXQItvJP5ZDi2zn+8k\u002fke18PzVeyj\u002fl0CLb+X7KPzm0yHa+n8o\u002fObTIdr6fyj+Nl24Sg8DKP42XbhKDwMo\u002f4XoUrkfhyj\u002fhehSuR+HKP4lBYOXQIss\u002fiUFg5dAiyz+JQWDl0CLLP90kBoGVQ8s\u002f3SQGgZVDyz\u002fdJAaBlUPLPzEIrBxaZMs\u002fhetRuB6Fyz+F61G4HoXLP9nO91Pjpcs\u002fgZVDi2znyz+BlUOLbOfLP9V46SYxCMw\u002fKVyPwvUozD8pXI\u002fC9SjMPylcj8L1KMw\u002ffT81XrpJzD\u002fRItv5fmrMPyUGgZVDi8w\u002fJQaBlUOLzD8lBoGVQ4vMP83MzMzMzMw\u002fzczMzMzMzD8hsHJoke3MPyGwcmiR7cw\u002fdZMYBFYOzT91kxgEVg7NP3WTGARWDs0\u002fyXa+nxovzT\u002fJdr6fGi\u002fNPx1aZDvfT80\u002fHVpkO99PzT9xPQrXo3DNP3E9CtejcM0\u002fxSCwcmiRzT\u002fFILByaJHNPxkEVg4tss0\u002fwcqhRbbzzT8UrkfhehTOPxSuR+F6FM4\u002fFK5H4XoUzj8UrkfhehTOPxSuR+F6FM4\u002faJHtfD81zj+8dJMYBFbOP7x0kxgEVs4\u002fEFg5tMh2zj9kO99PjZfOP2Q730+Nl84\u002fZDvfT42Xzj+4HoXrUbjOPwwCK4cW2c4\u002fDAIrhxbZzj8MAiuHFtnOPwwCK4cW2c4\u002fDAIrhxbZzj9g5dAi2\u002fnOP2Dl0CLb+c4\u002fYOXQItv5zj9g5dAi2\u002fnOP2Dl0CLb+c4\u002ftMh2vp8azz+0yHa+nxrPP7TIdr6fGs8\u002ftMh2vp8azz+0yHa+nxrPP7TIdr6fGs8\u002ftMh2vp8azz8IrBxaZDvPP1yPwvUoXM8\u002fXI\u002fC9Shczz+wcmiR7XzPP7ByaJHtfM8\u002fsHJoke18zz+wcmiR7XzPPwRWDi2ync8\u002fBFYOLbKdzz9YObTIdr7PP1g5tMh2vs8\u002frBxaZDvfzz+sHFpkO9\u002fPP6wcWmQ7388\u002frBxaZDvfzz8AAAAAAADQPwAAAAAAANA\u002fAAAAAAAA0D8AAAAAAADQPwAAAAAAANA\u002fAAAAAAAA0D+q8dJNYhDQP6rx0k1iENA\u002fVOOlm8Qg0D9U46WbxCDQP\u002f7UeOkmMdA\u002f\u002ftR46SYx0D\u002f+1HjpJjHQP\u002f7UeOkmMdA\u002fqMZLN4lB0D+oxks3iUHQP6jGSzeJQdA\u002fUrgehetR0D9SuB6F61HQP1K4HoXrUdA\u002fUrgehetR0D9SuB6F61HQP1K4HoXrUdA\u002f\u002fKnx0k1i0D\u002f8qfHSTWLQP6abxCCwctA\u002fppvEILBy0D+mm8QgsHLQP6abxCCwctA\u002fppvEILBy0D9QjZduEoPQP1CNl24Sg9A\u002fUI2XbhKD0D9QjZduEoPQP\u002fp+arx0k9A\u002f+n5qvHST0D\u002f6fmq8dJPQP\u002fp+arx0k9A\u002fpHA9Ctej0D+kcD0K16PQP6RwPQrXo9A\u002fpHA9Ctej0D+kcD0K16PQP05iEFg5tNA\u002fTmIQWDm00D9OYhBYObTQP05iEFg5tNA\u002f+FPjpZvE0D\u002f4U+Olm8TQP\u002fhT46WbxNA\u002fokW28\u002f3U0D+iRbbz\u002fdTQP0w3iUFg5dA\u002fTDeJQWDl0D9MN4lBYOXQP\u002fYoXI\u002fC9dA\u002f9ihcj8L10D\u002f2KFyPwvXQP6AaL90kBtE\u002foBov3SQG0T+gGi\u002fdJAbRP6AaL90kBtE\u002foBov3SQG0T+gGi\u002fdJAbRP6AaL90kBtE\u002f9P3UeOkm0T\u002f0\u002fdR46SbRP\u002fT91HjpJtE\u002fnu+nxks30T9I4XoUrkfRP0jhehSuR9E\u002fSOF6FK5H0T9I4XoUrkfRP\u002fLSTWIQWNE\u002f8tJNYhBY0T\u002fy0k1iEFjRP\u002fLSTWIQWNE\u002fnMQgsHJo0T+cxCCwcmjRP5zEILByaNE\u002fnMQgsHJo0T+cxCCwcmjRP5zEILByaNE\u002fRrbz\u002fdR40T\u002fwp8ZLN4nRP\u002fCnxks3idE\u002f8KfGSzeJ0T\u002fwp8ZLN4nRP\u002fCnxks3idE\u002fmpmZmZmZ0T+amZmZmZnRP0SLbOf7qdE\u002f7nw\u002fNV660T+YbhKDwMrRP5huEoPAytE\u002fmG4Sg8DK0T9CYOXQItvRP0Jg5dAi29E\u002fPzVeukkM0j8\u002fNV66SQzSPz81XrpJDNI\u002f6SYxCKwc0j\u002fpJjEIrBzSP5MYBFYOLdI\u002fPQrXo3A90j89CtejcD3SPz0K16NwPdI\u002fke18PzVe0j+R7Xw\u002fNV7SPzvfT42XbtI\u002fO99PjZdu0j8730+Nl27SP+XQItv5ftI\u002f5dAi2\u002fl+0j\u002fl0CLb+X7SP+XQItv5ftI\u002fj8L1KFyP0j+PwvUoXI\u002fSP+Olm8QgsNI\u002f46WbxCCw0j\u002fjpZvEILDSP42XbhKDwNI\u002fN4lBYOXQ0j83iUFg5dDSP+F6FK5H4dI\u002fi2zn+6nx0j+LbOf7qfHSP4ts5\u002fup8dI\u002fNV66SQwC0z81XrpJDALTPzVeukkMAtM\u002f30+Nl24S0z\u002ffT42XbhLTP4lBYOXQItM\u002fMzMzMzMz0z8zMzMzMzPTP90kBoGVQ9M\u002fhxbZzvdT0z8xCKwcWmTTPzEIrBxaZNM\u002fhetRuB6F0z8v3SQGgZXTP4PAyqFFttM\u002f16NwPQrX0z+BlUOLbOfTP39qvHSTGNQ\u002ff2q8dJMY1D8pXI\u002fC9SjUP30\u002fNV66SdQ\u002fexSuR+F61D93vp8aL93UP8uhRbbz\u002fdQ\u002fcT0K16Nw1T8X2c73U+PVPw=="},"xaxis":"x","y":{"dtype":"f8","bdata":"toCypwKQxD9aMofyKLjHP3yrucTiL8g\u002fUdo3UjNbyT\u002fiFlE7EJfJPyq13a\u002f+tMk\u002fA5CDDcoOyj9LLhCCuCzKP5TMnPamSso\u002flMyc9qZKyj\u002fcailrlWjKP9xqKWuVaMo\u002fJQm234OGyj8lCbbfg4bKP7ZFz8hgwso\u002ftkXPyGDCyj+2Rc\u002fIYMLKP\u002f7jWz1P4Mo\u002f\u002fuNbPU\u002fgyj\u002f+41s9T+DKP0eC6LE9\u002fso\u002fjyB1Jiwcyz+PIHUmLBzLP9i+AZsaOss\u002fafsahPd1yz9p+xqE93XLP7GZp\u002fjlk8s\u002f+Tc0bdSxyz\u002f5NzRt1LHLP\u002fk3NG3Uscs\u002fQtbA4cLPyz+KdE1Wse3LP9MS2sqfC8w\u002f0xLayp8LzD\u002fTEtrKnwvMP2RP87N8R8w\u002fZE\u002fzs3xHzD+s7X8oa2XMP6ztfyhrZcw\u002f9YsMnVmDzD\u002f1iwydWYPMP\u002fWLDJ1Zg8w\u002fPSqZEUihzD89KpkRSKHMP4bIJYY2v8w\u002fhsglhja\u002fzD\u002fOZrL6JN3MP85msvok3cw\u002fFwU\u002fbxP7zD8XBT9vE\u002fvMP1+jy+MBGc0\u002f8N\u002fkzN5UzT84fnFBzXLNPzh+cUHNcs0\u002fOH5xQc1yzT84fnFBzXLNPzh+cUHNcs0\u002fgBz+tbuQzT\u002fJuooqqq7NP8m6iiqqrs0\u002fEVkXn5jMzT9a96MTh+rNP1r3oxOH6s0\u002fWvejE4fqzT+ilTCIdQjOP+szvfxjJs4\u002f6zO9\u002fGMmzj\u002frM738YybOP+szvfxjJs4\u002f6zO9\u002fGMmzj8z0klxUkTOPzPSSXFSRM4\u002fM9JJcVJEzj8z0klxUkTOPzPSSXFSRM4\u002ffHDW5UBizj98cNblQGLOP3xw1uVAYs4\u002ffHDW5UBizj98cNblQGLOP3xw1uVAYs4\u002ffHDW5UBizj\u002fEDmNaL4DOPw2t784dns4\u002fDa3vzh2ezj9VS3xDDLzOP1VLfEMMvM4\u002fVUt8Qwy8zj9VS3xDDLzOP57pCLj62c4\u002fnukIuPrZzj\u002fmh5Us6ffOP+aHlSzp984\u002fLyYiodcVzz8vJiKh1xXPPy8mIqHXFc8\u002fLyYiodcVzz93xK4VxjPPP3fErhXGM88\u002fd8SuFcYzzz93xK4VxjPPP3fErhXGM88\u002fd8SuFcYzzz+\u002fYjuKtFHPP79iO4q0Uc8\u002fCAHI\u002fqJvzz8IAcj+om\u002fPP1CfVHORjc8\u002fUJ9Uc5GNzz9Qn1RzkY3PP1CfVHORjc8\u002fmT3h53+rzz+ZPeHnf6vPP5k94ed\u002fq88\u002f4dttXG7Jzz\u002fh221cbsnPP+HbbVxuyc8\u002f4dttXG7Jzz\u002fh221cbsnPP+HbbVxuyc8\u002fKnr60Fznzz8qevrQXOfPPzmMw6KlAtA\u002fOYzDoqUC0D85jMOipQLQPzmMw6KlAtA\u002fOYzDoqUC0D9e2wndnBHQP17bCd2cEdA\u002fXtsJ3ZwR0D9e2wndnBHQP4IqUBeUINA\u002fgipQF5Qg0D+CKlAXlCDQP4IqUBeUINA\u002fpnmWUYsv0D+meZZRiy\u002fQP6Z5llGLL9A\u002fpnmWUYsv0D+meZZRiy\u002fQP8rI3IuCPtA\u002fysjci4I+0D\u002fKyNyLgj7QP8rI3IuCPtA\u002f7hcjxnlN0D\u002fuFyPGeU3QP+4XI8Z5TdA\u002fEmdpAHFc0D8SZ2kAcVzQPze2rzpoa9A\u002fN7avOmhr0D83tq86aGvQP1sF9nRfetA\u002fWwX2dF960D9bBfZ0X3rQP4BUPK9WidA\u002fgFQ8r1aJ0D+AVDyvVonQP4BUPK9WidA\u002fgFQ8r1aJ0D+AVDyvVonQP4BUPK9WidA\u002fyPLII0Wn0D\u002fI8sgjRafQP8jyyCNFp9A\u002f7EEPXjy20D8QkVWYM8XQPxCRVZgzxdA\u002fEJFVmDPF0D8QkVWYM8XQPzTgm9Iq1NA\u002fNOCb0irU0D804JvSKtTQPzTgm9Iq1NA\u002fWS\u002fiDCLj0D9ZL+IMIuPQP1kv4gwi49A\u002fWS\u002fiDCLj0D9ZL+IMIuPQP1kv4gwi49A\u002ffX4oRxny0D+hzW6BEAHRP6HNboEQAdE\u002foc1ugRAB0T+hzW6BEAHRP6HNboEQAdE\u002fxhy1uwcQ0T\u002fGHLW7BxDRP+pr+\u002fX+HtE\u002fDrtBMPYt0T8yCohq7TzRPzIKiGrtPNE\u002fMgqIau080T9WWc6k5EvRP1ZZzqTkS9E\u002fwkahU8p40T\u002fCRqFTynjRP8JGoVPKeNE\u002f55XnjcGH0T\u002fnleeNwYfRPwvlLci4ltE\u002fLzR0ArCl0T8vNHQCsKXRPy80dAKwpdE\u002fd9IAd57D0T930gB3nsPRP5whR7GV0tE\u002fnCFHsZXS0T+cIUexldLRP8BwjeuM4dE\u002fwHCN64zh0T\u002fAcI3rjOHRP8BwjeuM4dE\u002f5L\u002fTJYTw0T\u002fkv9MlhPDRPy1eYJpyDtI\u002fLV5gmnIO0j8tXmCacg7SP1GtptRpHdI\u002fdfzsDmEs0j91\u002fOwOYSzSP5lLM0lYO9I\u002fvpp5g09K0j++mnmDT0rSP76aeYNPStI\u002f4um\u002fvUZZ0j\u002fi6b+9RlnSP+Lpv71GWdI\u002fBjkG+D1o0j8GOQb4PWjSPyqITDI1d9I\u002fT9eSbCyG0j9P15JsLIbSP3Mm2aYjldI\u002fl3Uf4Rqk0j+7xGUbErPSP7vEZRsSs9I\u002fBGPyjwDR0j8osjjK99\u002fSP3FQxT7m\u002fdI\u002fue5Rs9Qb0z\u002fdPZjtyyrTP0ora5yxV9M\u002fSitrnLFX0z9uerHWqGbTP7cYPkuXhNM\u002fIwYR+nyx0z\u002f94LZXSAvUP0V\u002fQ8w2KdQ\u002fQ6kvZPmR1D9B0xv8u\u002frUPw=="},"yaxis":"y","type":"scatter"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"xBA"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"BA"}},"legend":{"tracegroupgap":0},"title":{"text":"Relationship Between xBA and BA"}},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('8c510b5a-f9b5-4d8b-8eaa-b46f18131d13');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
</div>
</section>
<section id="expected-weighted-oba-xwoba" class="level1">
<h1>Expected Weighted OBA (xwOBA)</h1>
<p><a href="https://www.mlb.com/glossary/statcast/expected-woba">xwOBA</a> is what statcast considers, the most important offensive metric that tells “the story of a player’s season based on the quality of and amount of contact, not coutomes.” In sum, xwOBA weighs hit types and walks with an expected run value based on historically similar batted ball events. The formulation of the coefficients use exit velocity, launch angle, and sprint speed (for topped or weakly hit balls).</p>
<div id="6087d807" class="cell" data-execution_count="4">
<details class="code-fold">
<summary>Code</summary>
<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">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"est_woba_minus_woba_diff"</span>].describe().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span></code></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="4">
<pre><code>count    251.0000
mean      -0.0107
std        0.0313
min       -0.0940
25%       -0.0300
50%       -0.0110
75%        0.0130
max        0.0580
Name: est_woba_minus_woba_diff, dtype: float64</code></pre>
</div>
</div>
<p>The mean wOBA-xwOBA difference is -0.0107. This is surpsignly greater than the mean difference of BA and xBA. In addition, the most unlucky batter with xwOBA is most unlucky than the most unlucky batter with xBA. Simiarly, the most lucky xwOBA batter is not as lucky as the most lucky xBA batter. Overall it seems like player are less lucky with xwOBA. A reason for this discrepency is that xwOBA weighs batted ball events with difference values. For example, a double is weighted more heavily than a single. As such a batted ball who’s exit velocity and launch angle that would likely result in a double will increase the diffence in xwOBA and wOBA if that double becomes a single.</p>
<div id="3dcbe2f9" class="cell" data-execution_count="5">
<details class="code-fold">
<summary>Code</summary>
<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">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>  px.histogram(df, 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;">"est_woba_minus_woba_diff"</span>, marginal<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;">"rug"</span>, hover_data<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;">"last_name, first_name"</span>], </span>
<span id="cb7-2">        labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb7-3">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"diff"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wOBA - xwOBA"</span>,</span>
<span id="cb7-4">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"count"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Count"</span></span>
<span id="cb7-5">    },</span>
<span id="cb7-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 wOBA-xwOBA"</span>)</span>
<span id="cb7-7">fig.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="2d9a7937-59e1-4627-90a4-a95a079ee003" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("2d9a7937-59e1-4627-90a4-a95a079ee003")) {                    Plotly.newPlot(                        "2d9a7937-59e1-4627-90a4-a95a079ee003",                        [{"bingroup":"x","hovertemplate":"est_woba_minus_woba_diff=%{x}\u003cbr\u003ecount=%{y}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"","marker":{"color":"#636efa","pattern":{"shape":""}},"name":"","orientation":"v","showlegend":false,"x":{"dtype":"f8","bdata":"\u002fKnx0k1icL9\u002fHoXrUbiOv7gehetRuI6\u002fPWQ730+Nl7\u002frfmq8dJOov\u002fyp8dJNYmA\u002fzfl+arx0o7+4HoXrUbiOPx20yHa+n5q\u002fukkMAiuHlr9MZDvfT42nv3sUrkfhepS\u002f7FG4HoXroT\u002f6fmq8dJNovwrXo3A9Cqc\u002fGQRWDi2ynb+4HoXrUbiOv\u002fyp8dJNYlC\u002fjcQgsHJoob\u002fTTWIQWDm0vySHFtnO97O\u002fLd9PjZduor\u002f8qfHSTWKAv3sUrkfheqS\u002fGQRWDi2ynb\u002fN+X5qvHSjP91RuB6F66E\u002f\u002fKnx0k1ikD8ZBFYOLbKdv38ehetRuI4\u002fP+kmMQisjL8bL90kBoGlP5zEILByaJG\u002f+n5qvHSTaD99bOf7qfGiP7gehetRuI4\u002f7FG4HoXrob+6SQwCK4eGv7pJDAIrh5a\u002fE35qvHSTaD8dtMh2vp+av0w3iUFg5aA\u002f2\u002fl+arx0k7+Hfmq8dJN4P7pJDAIrh4a\u002fO99PjZdugj8AAAAAAAAAABsv3SQGgZW\u002f+n5qvHSTaD\u002fdfmq8dJOYP5sehetRuJ6\u002fP+kmMQisjL85tMh2vp+av5qZmZmZmZm\u002fXLx0kxgEpr9sFK5H4Xqkv1pkO99PjZc\u002f\u002fKnx0k1ikL9q6SYxCKysv3\u002fEILByaJG\u002fPWQ730+Nl7+DwMqhRbazv\u002fyp8dJNYnC\u002fHbTIdr6fmr9cvHSTGASmv2wUrkfheqQ\u002f\u002fKnx0k1iYL+6SQwCK4eGP\u002fyp8dJNYmC\u002fukkMAiuHlj\u002f6fmq8dJOYP4ts5\u002fup8aK\u002f\u002fANWDi2ynb\u002f8qfHSTWJQP3npJjEIrHw\u002fexSuR+F6hD+LbOf7qfGivwwv3SQGgaU\u002fo\u002fHSTWIQuL956SYxCKyMv8uhRbbz\u002faS\u002f\u002fi7dJAaBlb\u002f81qNwPQqnv3sUrkfhenQ\u002fqvHSTWIQqL+cxCCwcmihP\u002fp+arx0k3i\u002fuB6F61G4nj\u002fCqfHSTWKAP\u002fyp8dJNYnC\u002f\u002fKnx0k1iYL+6SQwCK4e2v7gehetRuJ6\u002fOwwCK4cWqb+cxCCwcmixv5zEILByaJE\u002feekmMQisfD85tMh2vp+KP\u002fyp8dJNYmA\u002fK4cW2c73oz9BFK5H4XqEP2rpJjEIrKy\u002f2\u002fl+arx0k7+4HoXrUbievwisHFpkO6+\u002fH99PjZdukr+LbOf7qfGiv\u002fyp8dJNYnC\u002f\u002fKnx0k1iUD9aZDvfT42nv\u002fyp8dJNYpC\u002fObTIdr6fmj956SYxCKyMv3sUrkfheoS\u002f+n5qvHSTaL\u002f8qfHSTWJwv\u002fyp8dJNYoC\u002fnMQgsHJokT97FK5H4XqUPwC0yHa+n4o\u002f\u002fKnx0k1iUL9MZDvfT42nv7pJDAIrh4a\u002faukmMQisrL8rtMh2vp+qv835fmq8dKO\u002f+n5qvHSTaL\u002fb+X5qvHSTvz1kO99PjZe\u002fe0Fg5dAiq7956SYxCKycv\u002fp+arx0k5i\u002fmx6F61G4nj9YObTIdr6fP7pJDAIrh5a\u002fe0Fg5dAiq7+cxCCwcmixv+2p8dJNYqC\u002fDC\u002fdJAaBpb9MN4lBYOWwv3\u002fEILByaJE\u002f\u002fKnx0k1iYL+kcD0K16Owv8B+arx0k4i\u002fCKwcWmQ7r797FK5H4XqUv0EUrkfheoQ\u002fGy\u002fdJAaBpT+6SQwCK4eGP0xkO99Pjae\u002fukkMAiuHhr+6dr6fGi+tv\u002fyp8dJNYoA\u002f+n5qvHSTaD9q6SYxCKysv\u002fyp8dJNYmA\u002fnMQgsHJokT97FK5H4Xp0v\u002fp+arx0k3i\u002fXOkmMQisnD\u002ffqfHSTWKQP\u002fwDVg4tsp2\u002fukkMAiuHlr956SYxCKyMP4FJDAIrh4Y\u002f\u002fKnx0k1ikD\u002f+Lt0kBoGVP0w3iUFg5aC\u002f\u002fNajcD0Kpz8AtMh2vp+KvwC0yHa+n4q\u002fi5mZmZmZqT\u002f6fmq8dJNov3sUrkfhepS\u002fexSuR+F6pD8730+Nl26SP7gehetRuJ6\u002faukmMQisrL9c6SYxCKycv9nO91PjpZs\u002fukkMAiuHlr+cxCCwcmiRP8Kp8dJNYoC\u002fmx6F61G4nj+sSQwCK4emvxtcj8L1KKw\u002fHbTIdr6fmr97FK5H4Xp0P775fmq8dJM\u002fTDeJQWDlsL+6dr6fGi+tv7gehetRuI4\u002fGy\u002fdJAaBlb\u002f6fmq8dJN4v1zpJjEIrJy\u002fG1yPwvUorL8IrBxaZDuvv3sUrkfhenQ\u002fukkMAiuHlj8730+Nl26SP1pkO99PjZe\u002f2c73U+Olmz99mZmZmZmZvySHFtnO97O\u002fmpmZmZmZmb956SYxCKyMP\u002fyp8dJNYnC\u002f3X5qvHSTmD8rhxbZzvezvz03iUFg5aC\u002fwqnx0k1igL8KBFYOLbKtP9nO91PjpZu\u002fe0Fg5dAiq797FK5H4XqEP9smMQisHKq\u002fOzm0yHa+nz8t30+Nl26iv2wUrkfheqQ\u002fbBSuR+F6pD89ZDvfT42XP\u002fyp8dJNYoA\u002f\u002fKnx0k1ikD8bL90kBoGVv91RuB6F66E\u002fi2zn+6nxor\u002fb+X5qvHSTv91RuB6F66E\u002fHbTIdr6fmj\u002f8qfHSTWJwv1y8dJMYBKa\u002f+n5qvHSTaD+79Shcj8K1v5zEILByaLG\u002f+n5qvHSTmL\u002f8qfHSTWKAPxsv3SQGgZW\u002f\u002fKnx0k1ikL9\u002fxCCwcmiRP7pJDAIrh4a\u002fCgRWDi2yrT+cxCCwcmiRPzsMAiuHFqm\u002fAAAAAAAAAAD8qfHSTWJgPwgUrkfhenS\u002fmx6F61G4nj\u002f6fmq8dJOIPzm0yHa+n4q\u002f\u002fKnx0k1icL+6SQwCK4eGPw=="},"xaxis":"x","yaxis":"y","type":"histogram"},{"boxpoints":"all","customdata":[["Duran, Jarren"],["Carroll, Corbin"],["Devers, Rafael"],["Tucker, Kyle"],["Ohtani, Shohei"],["Lindor, Francisco"],["Bichette, Bo"],["Chourio, Jackson"],["Nootbaar, Lars"],["Harper, Bryce"],["Rooker, Brent"],["Witt Jr., Bobby"],["Judge, Aaron"],["De La Cruz, Elly"],["Bregman, Alex"],["Schwarber, Kyle"],["Adames, Willy"],["Wood, James"],["Alonso, Pete"],["Soto, Juan"],["Reynolds, Bryan"],["Rodríguez, Julio"],["Riley, Austin"],["Guerrero Jr., Vladimir"],["Soderstrom, Tyler"],["Turner, Trea"],["Paredes, Isaac"],["Kwan, Steven"],["Olson, Matt"],["Raleigh, Cal"],["Albies, Ozzie"],["Crow-Armstrong, Pete"],["Swanson, Dansby"],["Peña, Jeremy"],["Perdomo, Geraldo"],["Ramos, Heliot"],["Pasquantino, Vinnie"],["Torkelson, Spencer"],["Lowe, Nathaniel"],["Naylor, Josh"],["Turang, Brice"],["Friedl, TJ"],["Yelich, Christian"],["Lee, Jung Hoo"],["Castellanos, Nick"],["Suzuki, Seiya"],["Betts, Mookie"],["Donovan, Brendan"],["Butler, Lawrence"],["Altuve, Jose"],["Chapman, Matt"],["Ward, Taylor"],["Suárez, Eugenio"],["Tatis Jr., Fernando"],["Walker, Christian"],["Contreras, Willson"],["Greene, Riley"],["Arozarena, Randy"],["Harris II, Michael"],["Ozuna, Marcell"],["Story, Trevor"],["Semien, Marcus"],["Volpe, Anthony"],["McMahon, Ryan"],["Díaz, Yandy"],["Wilson, Jacob"],["Crawford, J.P."],["Goldschmidt, Paul"],["Larnach, Trevor"],["Garcia, Maikel"],["Ramírez, José"],["Machado, Manny"],["Happ, Ian"],["Contreras, William"],["Hoerner, Nico"],["Arenado, Nolan"],["India, Jonathan"],["Goodman, Hunter"],["Perez, Salvador"],["Gurriel Jr., Lourdes"],["Bohm, Alec"],["Hayes, Ke'Bryan"],["García, Adolis"],["Santana, Carlos"],["Nimmo, Brandon"],["Flores, Wilmer"],["Vargas, Miguel"],["Mullins, Cedric"],["Edwards, Xavier"],["Schanuel, Nolan"],["Soler, Jorge"],["Vaughn, Andrew"],["Bogaerts, Xander"],["France, Ty"],["Robert Jr., Luis"],["Frelick, Sal"],["Bellinger, Cody"],["Pages, Andy"],["Stowers, Kyle"],["Arraez, Luis"],["Bleday, JJ"],["Lowe, Brandon"],["Caminero, Junior"],["Abreu, Wilyer"],["Rutschman, Adley"],["Langeliers, Shea"],["Muncy, Max"],["Stott, Bryson"],["Vientos, Mark"],["Cruz, Oneil"],["Busch, Michael"],["Hoskins, Rhys"],["Carpenter, Kerry"],["Santander, Anthony"],["Toglia, Michael"],["Campbell, Kristian"],["Steer, Spencer"],["Henderson, Gunnar"],["McKinstry, Zach"],["Yastrzemski, Mike"],["Sweeney, Trey"],["McLain, Matt"],["Ruiz, Keibert"],["Mountcastle, Ryan"],["Diaz, Yainer"],["Wagaman, Eric"],["Manzardo, Kyle"],["Springer, George"],["Massey, Michael"],["Conforto, Michael"],["Langford, Wyatt"],["Kepler, Max"],["Lux, Gavin"],["Scott II, Victor"],["Realmuto, J.T."],["Doyle, Brenton"],["García Jr., Luis"],["McCutchen, Andrew"],["Rice, Ben"],["Crews, Dylan"],["Buxton, Byron"],["Arias, Gabriel"],["Rafaela, Ceddanne"],["Holliday, Jackson"],["Ortiz, Joey"],["Sosa, Lenyn"],["Meyers, Jake"],["Freeman, Freddie"],["Abrams, CJ"],["Bell, Josh"],["Aranda, Jonathan"],["Rengifo, Luis"],["O'Hoppe, Logan"],["Jung, Josh"],["Torres, Gleyber"],["Domínguez, Jasson"],["Winn, Masyn"],["Wells, Austin"],["Smith, Josh"],["Sheets, Gavin"],["Smith, Will"],["Correa, Carlos"],["Bart, Joey"],["O'Hearn, Ryan"],["Frazier, Adam"],["Beck, Jordan"],["Espinal, Santiago"],["Kirk, Alejandro"],["Báez, Javier"],["Grisham, Trent"],["Jeffers, Ryan"],["Smith, Pavin"],["Clement, Ernie"],["Walker, Jordan"],["Andujar, Miguel"],["Hernández, Teoscar"],["Burger, Jake"],["Keith, Colt"],["Wade Jr., LaMonte"],["Kiner-Falefa, Isiah"],["Taylor, Tyrone"],["Allen, Nick"],["Dingler, Dillon"],["Misner, Kameron"],["Moniak, Mickey"],["Bader, Harrison"],["Bailey, Patrick"],["Heim, Jonah"],["Farmer, Kyle"],["Pederson, Joc"],["Giménez, Andrés"],["Smith, Cam"],["Polanco, Jorge"],["Moreno, Gabriel"],["Baldwin, Brooks"],["Edman, Tommy"],["Adell, Jo"],["Thomas, Alek"],["Narváez, Carlos"],["Burleson, Alec"],["Neto, Zach"],["Taveras, Leody"],["Pham, Tommy"],["Lopez, Otto"],["Walls, Taylor"],["Paris, Kyren"],["Naylor, Bo"],["Urías, Luis"],["Jones, Nolan"],["Morel, Christopher"],["Acuña, Luisangel"],["Isbel, Kyle"],["Lee, Brooks"],["Kjerstad, Heston"],["Pagés, Pedro"],["Sánchez, Jesús"],["Caballero, José"],["Young, Jacob"],["Martínez, Angel"],["Mervis, Matt"],["Call, Alex"],["White, Eli"],["Moore, Dylan"],["Chisholm Jr., Jazz"],["Waters, Drew"],["Verdugo, Alex"],["Jansen, Danny"],["Kelly, Carson"],["Murphy, Sean"],["Schneemann, Daniel"],["Tellez, Rowdy"],["Cabrera, Oswaldo"],["Alvarez, Yordan"],["Trout, Mike"],["Williamson, Ben"],["Castro, Willi"],["Durbin, Caleb"],["Hernández, Enrique"],["Díaz, Elias"],["Sanoja, Javier"],["Fitzgerald, Tyler"],["Norby, Connor"],["Casas, Triston"],["Iglesias, Jose"],["Urías, Ramón"],["Marte, Ketel"],["Meidroth, Chase"],["Ramírez, Agustín"],["Simpson, Chandler"],["Lukes, Nathan"],["Laureano, Ramón"]],"fillcolor":"rgba(255,255,255,0)","hoveron":"points","hovertemplate":"est_woba_minus_woba_diff=%{x}\u003cbr\u003elast_name, first_name=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","jitter":0,"legendgroup":"","line":{"color":"rgba(255,255,255,0)"},"marker":{"color":"#636efa","symbol":"line-ns-open"},"name":"","showlegend":false,"x":{"dtype":"f8","bdata":"\u002fKnx0k1icL9\u002fHoXrUbiOv7gehetRuI6\u002fPWQ730+Nl7\u002frfmq8dJOov\u002fyp8dJNYmA\u002fzfl+arx0o7+4HoXrUbiOPx20yHa+n5q\u002fukkMAiuHlr9MZDvfT42nv3sUrkfhepS\u002f7FG4HoXroT\u002f6fmq8dJNovwrXo3A9Cqc\u002fGQRWDi2ynb+4HoXrUbiOv\u002fyp8dJNYlC\u002fjcQgsHJoob\u002fTTWIQWDm0vySHFtnO97O\u002fLd9PjZduor\u002f8qfHSTWKAv3sUrkfheqS\u002fGQRWDi2ynb\u002fN+X5qvHSjP91RuB6F66E\u002f\u002fKnx0k1ikD8ZBFYOLbKdv38ehetRuI4\u002fP+kmMQisjL8bL90kBoGlP5zEILByaJG\u002f+n5qvHSTaD99bOf7qfGiP7gehetRuI4\u002f7FG4HoXrob+6SQwCK4eGv7pJDAIrh5a\u002fE35qvHSTaD8dtMh2vp+av0w3iUFg5aA\u002f2\u002fl+arx0k7+Hfmq8dJN4P7pJDAIrh4a\u002fO99PjZdugj8AAAAAAAAAABsv3SQGgZW\u002f+n5qvHSTaD\u002fdfmq8dJOYP5sehetRuJ6\u002fP+kmMQisjL85tMh2vp+av5qZmZmZmZm\u002fXLx0kxgEpr9sFK5H4Xqkv1pkO99PjZc\u002f\u002fKnx0k1ikL9q6SYxCKysv3\u002fEILByaJG\u002fPWQ730+Nl7+DwMqhRbazv\u002fyp8dJNYnC\u002fHbTIdr6fmr9cvHSTGASmv2wUrkfheqQ\u002f\u002fKnx0k1iYL+6SQwCK4eGP\u002fyp8dJNYmC\u002fukkMAiuHlj\u002f6fmq8dJOYP4ts5\u002fup8aK\u002f\u002fANWDi2ynb\u002f8qfHSTWJQP3npJjEIrHw\u002fexSuR+F6hD+LbOf7qfGivwwv3SQGgaU\u002fo\u002fHSTWIQuL956SYxCKyMv8uhRbbz\u002faS\u002f\u002fi7dJAaBlb\u002f81qNwPQqnv3sUrkfhenQ\u002fqvHSTWIQqL+cxCCwcmihP\u002fp+arx0k3i\u002fuB6F61G4nj\u002fCqfHSTWKAP\u002fyp8dJNYnC\u002f\u002fKnx0k1iYL+6SQwCK4e2v7gehetRuJ6\u002fOwwCK4cWqb+cxCCwcmixv5zEILByaJE\u002feekmMQisfD85tMh2vp+KP\u002fyp8dJNYmA\u002fK4cW2c73oz9BFK5H4XqEP2rpJjEIrKy\u002f2\u002fl+arx0k7+4HoXrUbievwisHFpkO6+\u002fH99PjZdukr+LbOf7qfGiv\u002fyp8dJNYnC\u002f\u002fKnx0k1iUD9aZDvfT42nv\u002fyp8dJNYpC\u002fObTIdr6fmj956SYxCKyMv3sUrkfheoS\u002f+n5qvHSTaL\u002f8qfHSTWJwv\u002fyp8dJNYoC\u002fnMQgsHJokT97FK5H4XqUPwC0yHa+n4o\u002f\u002fKnx0k1iUL9MZDvfT42nv7pJDAIrh4a\u002faukmMQisrL8rtMh2vp+qv835fmq8dKO\u002f+n5qvHSTaL\u002fb+X5qvHSTvz1kO99PjZe\u002fe0Fg5dAiq7956SYxCKycv\u002fp+arx0k5i\u002fmx6F61G4nj9YObTIdr6fP7pJDAIrh5a\u002fe0Fg5dAiq7+cxCCwcmixv+2p8dJNYqC\u002fDC\u002fdJAaBpb9MN4lBYOWwv3\u002fEILByaJE\u002f\u002fKnx0k1iYL+kcD0K16Owv8B+arx0k4i\u002fCKwcWmQ7r797FK5H4XqUv0EUrkfheoQ\u002fGy\u002fdJAaBpT+6SQwCK4eGP0xkO99Pjae\u002fukkMAiuHhr+6dr6fGi+tv\u002fyp8dJNYoA\u002f+n5qvHSTaD9q6SYxCKysv\u002fyp8dJNYmA\u002fnMQgsHJokT97FK5H4Xp0v\u002fp+arx0k3i\u002fXOkmMQisnD\u002ffqfHSTWKQP\u002fwDVg4tsp2\u002fukkMAiuHlr956SYxCKyMP4FJDAIrh4Y\u002f\u002fKnx0k1ikD\u002f+Lt0kBoGVP0w3iUFg5aC\u002f\u002fNajcD0Kpz8AtMh2vp+KvwC0yHa+n4q\u002fi5mZmZmZqT\u002f6fmq8dJNov3sUrkfhepS\u002fexSuR+F6pD8730+Nl26SP7gehetRuJ6\u002faukmMQisrL9c6SYxCKycv9nO91PjpZs\u002fukkMAiuHlr+cxCCwcmiRP8Kp8dJNYoC\u002fmx6F61G4nj+sSQwCK4emvxtcj8L1KKw\u002fHbTIdr6fmr97FK5H4Xp0P775fmq8dJM\u002fTDeJQWDlsL+6dr6fGi+tv7gehetRuI4\u002fGy\u002fdJAaBlb\u002f6fmq8dJN4v1zpJjEIrJy\u002fG1yPwvUorL8IrBxaZDuvv3sUrkfhenQ\u002fukkMAiuHlj8730+Nl26SP1pkO99PjZe\u002f2c73U+Olmz99mZmZmZmZvySHFtnO97O\u002fmpmZmZmZmb956SYxCKyMP\u002fyp8dJNYnC\u002f3X5qvHSTmD8rhxbZzvezvz03iUFg5aC\u002fwqnx0k1igL8KBFYOLbKtP9nO91PjpZu\u002fe0Fg5dAiq797FK5H4XqEP9smMQisHKq\u002fOzm0yHa+nz8t30+Nl26iv2wUrkfheqQ\u002fbBSuR+F6pD89ZDvfT42XP\u002fyp8dJNYoA\u002f\u002fKnx0k1ikD8bL90kBoGVv91RuB6F66E\u002fi2zn+6nxor\u002fb+X5qvHSTv91RuB6F66E\u002fHbTIdr6fmj\u002f8qfHSTWJwv1y8dJMYBKa\u002f+n5qvHSTaD+79Shcj8K1v5zEILByaLG\u002f+n5qvHSTmL\u002f8qfHSTWKAPxsv3SQGgZW\u002f\u002fKnx0k1ikL9\u002fxCCwcmiRP7pJDAIrh4a\u002fCgRWDi2yrT+cxCCwcmiRPzsMAiuHFqm\u002fAAAAAAAAAAD8qfHSTWJgPwgUrkfhenS\u002fmx6F61G4nj\u002f6fmq8dJOIPzm0yHa+n4q\u002f\u002fKnx0k1icL+6SQwCK4eGPw=="},"xaxis":"x2","yaxis":"y2","type":"box"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"est_woba_minus_woba_diff"}},"yaxis":{"anchor":"x","domain":[0.0,0.8316],"title":{"text":"count"}},"xaxis2":{"anchor":"y2","domain":[0.0,1.0],"matches":"x","showticklabels":false,"showgrid":true},"yaxis2":{"anchor":"x2","domain":[0.8416,1.0],"matches":"y2","showticklabels":false,"showline":false,"ticks":"","showgrid":false},"legend":{"tracegroupgap":0},"title":{"text":"Distribution of wOBA-xwOBA"},"barmode":"relative"},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('2d9a7937-59e1-4627-90a4-a95a079ee003');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
</div>
</section>
<section id="combining-differences" class="level1">
<h1>Combining Differences</h1>
<div id="dd7e59f3" class="cell" data-execution_count="6">
<details class="code-fold">
<summary>Code</summary>
<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">id_cols <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;">'last_name, first_name'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'player_id'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pa'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'year'</span>]</span>
<span id="cb8-2"></span>
<span id="cb8-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># melt the three diff-cols into long form</span></span>
<span id="cb8-4">df_long <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.melt(</span>
<span id="cb8-5">    id_vars<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>id_cols,</span>
<span id="cb8-6">    value_vars<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[</span>
<span id="cb8-7">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'est_ba_minus_ba_diff'</span>,</span>
<span id="cb8-8">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'est_slg_minus_slg_diff'</span>,</span>
<span id="cb8-9">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'est_woba_minus_woba_diff'</span></span>
<span id="cb8-10">    ],</span>
<span id="cb8-11">    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;">'metric'</span>,</span>
<span id="cb8-12">    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;">'diff'</span></span>
<span id="cb8-13">)</span>
<span id="cb8-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># map the verbose column names to simple metric labels</span></span>
<span id="cb8-15">df_long[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'metric'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_long[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'metric'</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">map</span>({</span>
<span id="cb8-16">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'est_ba_minus_ba_diff'</span>:   <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BA'</span>,</span>
<span id="cb8-17">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'est_slg_minus_slg_diff'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SLG'</span>,</span>
<span id="cb8-18">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'est_woba_minus_woba_diff'</span>:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'wOBA'</span></span>
<span id="cb8-19">})</span>
<span id="cb8-20"></span>
<span id="cb8-21">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> px.histogram(df_long, 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;">"diff"</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;">"metric"</span>, marginal<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;">"rug"</span>, hover_data<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;">"last_name, first_name"</span>], </span>
<span id="cb8-22">        labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb8-23">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"diff"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Metric - Expected Metric"</span>,</span>
<span id="cb8-24">        <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"count"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Count"</span></span>
<span id="cb8-25">    },</span>
<span id="cb8-26">    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 xBA, xSLG, and xwOBA Differences"</span></span>
<span id="cb8-27">)</span>
<span id="cb8-28">fig.show()</span></code></pre></div>
</details>
<div class="cell-output cell-output-display">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="03921ba4-61bf-4f27-83e1-43c0afcf710b" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("03921ba4-61bf-4f27-83e1-43c0afcf710b")) {                    Plotly.newPlot(                        "03921ba4-61bf-4f27-83e1-43c0afcf710b",                        [{"bingroup":"x","hovertemplate":"metric=BA\u003cbr\u003eMetric - Expected Metric=%{x}\u003cbr\u003ecount=%{y}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"BA","marker":{"color":"#636efa","pattern":{"shape":""}},"name":"BA","orientation":"v","showlegend":true,"x":{"dtype":"f8","bdata":"\u002fKnx0k1iYL8AtMh2vp+Kv\u002fyp8dJNYnC\u002fmx6F61G4nr9MN4lBYOWgv3sUrkfhenQ\u002f+n5qvHSTmL\u002f8qfHSTWJwP1pkO99PjZe\u002ff8QgsHJokb99bOf7qfGiv\u002fp+arx0k4i\u002faukmMQisrD\u002f6fmq8dJN4P6xJDAIrh6Y\u002fjcQgsHJoob\u002f8qfHSTWJwPwC0yHa+n4o\u002fObTIdr6fir8IrBxaZDuvv5qZmZmZmam\u002fO99PjZduor\u002f6fmq8dJOIPzs5tMh2vp+\u002fXhSuR+F6lL\u002f81qNwPQqnP\u002fyp8dJNYoA\u002f+n5qvHSTiD8730+Nl26Cv3npJjEIrHw\u002fwH5qvHSTiL\u002fdfmq8dJOYP\u002fp+arx0k4i\u002f\u002fKnx0k1iYD\u002fN+X5qvHSjP\u002fwDVg4tsp0\u002f3X5qvHSTmL\u002f8qfHSTWJwv1zpJjEIrJy\u002fgUkMAiuHhj\u002f8qfHSTWJwP7pJDAIrh5Y\u002fLd9PjZduor956SYxCKyMv\u002fp+arx0k3g\u002feekmMQisfL85tMh2vp+Kv3sUrkfhenS\u002fh35qvHSTeD9c6SYxCKycP7gehetRuJ6\u002fHbTIdr6fmr+eSQwCK4eWv7pJDAIrh4a\u002fHYcW2c73o7+6SQwCK4eWv3npJjEIrJw\u002fP+kmMQisjL+JQWDl0CKrv8B+arx0k4i\u002fQRSuR+F6hL\u002fZzvdT46Wrv\u002fp+arx0k3i\u002f+n5qvHSTiL\u002f81qNwPQqnv\u002fp+arx0k5g\u002fO99PjZdugj+cxCCwcmihP3sUrkfheoS\u002fmpmZmZmZmT85tMh2vp+KP9v5fmq8dJO\u002f+n5qvHSTiL+6SQwCK4eGP3npJjEIrHw\u002f\u002fKnx0k1iYL9YObTIdr6fvxsv3SQGgaU\u002fPIts5\u002fupsb89ZDvfT42Xv14UrkfhepS\u002f\u002fKnx0k1icL\u002fdfmq8dJOYv9+p8dJNYpA\u002f6SYxCKwcqr+4HoXrUbiOPwC0yHa+n4q\u002fO99PjZdugj97FK5H4XqUPwgUrkfhenS\u002f\u002fKnx0k1iYD9Ei2zn+6mxv7gehetRuJ6\u002f2\u002fl+arx0k78IrBxaZDuvv\u002fyp8dJNYoA\u002fuB6F61G4jj97FK5H4XqEP3sUrkfhepQ\u002f\u002fKnx0k1ikD\u002f8qfHSTWJwv\u002fp+arx0k6i\u002fexSuR+F6lL+6SQwCK4eWv3npJjEIrKy\u002f2c73U+Olm7\u002f8qfHSTWKQv\u002fyp8dJNYlC\u002fE35qvHSTaL\u002f8A1YOLbKdv\u002fyp8dJNYlC\u002fPTeJQWDloD\u002f6fmq8dJN4P7gehetRuI6\u002feekmMQisfL956SYxCKx8v38ehetRuI6\u002f\u002fKnx0k1iYL+cxCCwcmiRPzvfT42XbpI\u002fwqnx0k1igD\u002fb+X5qvHSjv\u002f4u3SQGgZW\u002fnMQgsHJoob9MN4lBYOWgv\u002fwDVg4tsp2\u002f\u002fKnx0k1iUL8AAAAAAAAAALgehetRuI6\u002fe0Fg5dAiq7+cxCCwcmiRv7zO91PjpZu\u002f7anx0k1ioD89N4lBYOWgP3sUrkfhepS\u002fK4cW2c73o79q6SYxCKysv3sUrkfhepS\u002fXLx0kxgEpr9YObTIdr6vvzvfT42XbpI\u002f36nx0k1ikD8rhxbZzvejv\u002fyp8dJNYmC\u002fnMQgsHJosb9BFK5H4XqEvzm0yHa+n5o\u002fnPHSTWIQqD8AAAAAAAAAAGrpJjEIrKy\u002f\u002fKnx0k1igD\u002f6fmq8dJOov5zEILByaJE\u002ff8QgsHJokT+8zvdT46Wbv\u002fyp8dJNYnC\u002f+n5qvHSTeD8\u002f6SYxCKyMvwAAAAAAAAAA\u002fi7dJAaBlT+q8dJNYhCoP3npJjEIrJy\u002fObTIdr6fij\u002f6fmq8dJNoP\u002fp+arx0k2g\u002feekmMQisjD+4HoXrUbiePzm0yHa+n4q\u002fXLx0kxgEpj\u002f8qfHSTWKQv\u002fp+arx0k3g\u002fRTeJQWDlsD\u002f8qfHSTWJQP\u002fp+arx0k3i\u002fTGQ730+Npz956SYxCKx8v14UrkfhepS\u002fSgwCK4cWqb+LbOf7qfGivx20yHa+n5o\u002fObTIdr6fmr99mZmZmZmZP\u002fyp8dJNYnA\u002fexSuR+F6lD8K16NwPQqnv6oehetRuK4\u002f\u002fKnx0k1igL\u002f8qfHSTWJgP9+p8dJNYpA\u002fLDMzMzMzs7+4HoXrUbiuv7pJDAIrh4Y\u002f7FG4HoXrob\u002f6fmq8dJNov\u002fp+arx0k4i\u002f\u002fKnx0k1isL+4HoXrUbiuv5zEILByaJE\u002f7anx0k1ioD+bHoXrUbieP3sUrkfhenS\u002fWmQ730+Nlz+4HoXrUbiOvzyLbOf7qbG\u002fnkkMAiuHlr\u002f8qfHSTWKAP4FJDAIrh4a\u002fukkMAiuHlj8pXI\u002fC9Sisv4FJDAIrh4a\u002fAAAAAAAAAABaZDvfT42nPwLfT42XboK\u002f2\u002fl+arx0o7\u002f8qfHSTWJgP7gehetRuJ6\u002f\u002fi7dJAaBlT85tMh2vp+qv3sUrkfheqQ\u002fXhSuR+F6lD\u002f6fmq8dJOoP8Kp8dJNYoC\u002fuB6F61G4jj\u002f8qfHSTWKgvxsv3SQGgZU\u002fvM73U+Olm7956SYxCKyMv\u002f4u3SQGgZU\u002f\u002fKnx0k1igD\u002f6fmq8dJNoP7pJDAIrh6a\u002f\u002fKnx0k1icL8730+Nl26iv+xRuB6F67G\u002fwqnx0k1igL8G6SYxCKx8Pz1kO99PjZe\u002ffZmZmZmZmb85tMh2vp+KP\u002fp+arx0k4i\u002fSgwCK4cWqT\u002f6fmq8dJOoP5zEILByaKG\u002fAAAAAAAAAAD8qfHSTWKgP1zpJjEIrJy\u002fPTeJQWDloD+cxCCwcmiRv\u002fp+arx0k3i\u002fXOkmMQisnL+6SQwCK4eGPw=="},"xaxis":"x","yaxis":"y","type":"histogram"},{"boxpoints":"all","customdata":[["Duran, Jarren"],["Carroll, Corbin"],["Devers, Rafael"],["Tucker, Kyle"],["Ohtani, Shohei"],["Lindor, Francisco"],["Bichette, Bo"],["Chourio, Jackson"],["Nootbaar, Lars"],["Harper, Bryce"],["Rooker, Brent"],["Witt Jr., Bobby"],["Judge, Aaron"],["De La Cruz, Elly"],["Bregman, Alex"],["Schwarber, Kyle"],["Adames, Willy"],["Wood, James"],["Alonso, Pete"],["Soto, Juan"],["Reynolds, Bryan"],["Rodríguez, Julio"],["Riley, Austin"],["Guerrero Jr., Vladimir"],["Soderstrom, Tyler"],["Turner, Trea"],["Paredes, Isaac"],["Kwan, Steven"],["Olson, Matt"],["Raleigh, Cal"],["Albies, Ozzie"],["Crow-Armstrong, Pete"],["Swanson, Dansby"],["Peña, Jeremy"],["Perdomo, Geraldo"],["Ramos, Heliot"],["Pasquantino, Vinnie"],["Torkelson, Spencer"],["Lowe, Nathaniel"],["Naylor, Josh"],["Turang, Brice"],["Friedl, TJ"],["Yelich, Christian"],["Lee, Jung Hoo"],["Castellanos, Nick"],["Suzuki, Seiya"],["Betts, Mookie"],["Donovan, Brendan"],["Butler, Lawrence"],["Altuve, Jose"],["Chapman, Matt"],["Ward, Taylor"],["Suárez, Eugenio"],["Tatis Jr., Fernando"],["Walker, Christian"],["Contreras, Willson"],["Greene, Riley"],["Arozarena, Randy"],["Harris II, Michael"],["Ozuna, Marcell"],["Story, Trevor"],["Semien, Marcus"],["Volpe, Anthony"],["McMahon, Ryan"],["Díaz, Yandy"],["Wilson, Jacob"],["Crawford, J.P."],["Goldschmidt, Paul"],["Larnach, Trevor"],["Garcia, Maikel"],["Ramírez, José"],["Machado, Manny"],["Happ, Ian"],["Contreras, William"],["Hoerner, Nico"],["Arenado, Nolan"],["India, Jonathan"],["Goodman, Hunter"],["Perez, Salvador"],["Gurriel Jr., Lourdes"],["Bohm, Alec"],["Hayes, Ke'Bryan"],["García, Adolis"],["Santana, Carlos"],["Nimmo, Brandon"],["Flores, Wilmer"],["Vargas, Miguel"],["Mullins, Cedric"],["Edwards, Xavier"],["Schanuel, Nolan"],["Soler, Jorge"],["Vaughn, Andrew"],["Bogaerts, Xander"],["France, Ty"],["Robert Jr., Luis"],["Frelick, Sal"],["Bellinger, Cody"],["Pages, Andy"],["Stowers, Kyle"],["Arraez, Luis"],["Bleday, JJ"],["Lowe, Brandon"],["Caminero, Junior"],["Abreu, Wilyer"],["Rutschman, Adley"],["Langeliers, Shea"],["Muncy, Max"],["Stott, Bryson"],["Vientos, Mark"],["Cruz, Oneil"],["Busch, Michael"],["Hoskins, Rhys"],["Carpenter, Kerry"],["Santander, Anthony"],["Toglia, Michael"],["Campbell, Kristian"],["Steer, Spencer"],["Henderson, Gunnar"],["McKinstry, Zach"],["Yastrzemski, Mike"],["Sweeney, Trey"],["McLain, Matt"],["Ruiz, Keibert"],["Mountcastle, Ryan"],["Diaz, Yainer"],["Wagaman, Eric"],["Manzardo, Kyle"],["Springer, George"],["Massey, Michael"],["Conforto, Michael"],["Langford, Wyatt"],["Kepler, Max"],["Lux, Gavin"],["Scott II, Victor"],["Realmuto, J.T."],["Doyle, Brenton"],["García Jr., Luis"],["McCutchen, Andrew"],["Rice, Ben"],["Crews, Dylan"],["Buxton, Byron"],["Arias, Gabriel"],["Rafaela, Ceddanne"],["Holliday, Jackson"],["Ortiz, Joey"],["Sosa, Lenyn"],["Meyers, Jake"],["Freeman, Freddie"],["Abrams, CJ"],["Bell, Josh"],["Aranda, Jonathan"],["Rengifo, Luis"],["O'Hoppe, Logan"],["Jung, Josh"],["Torres, Gleyber"],["Domínguez, Jasson"],["Winn, Masyn"],["Wells, Austin"],["Smith, Josh"],["Sheets, Gavin"],["Smith, Will"],["Correa, Carlos"],["Bart, Joey"],["O'Hearn, Ryan"],["Frazier, Adam"],["Beck, Jordan"],["Espinal, Santiago"],["Kirk, Alejandro"],["Báez, Javier"],["Grisham, Trent"],["Jeffers, Ryan"],["Smith, Pavin"],["Clement, Ernie"],["Walker, Jordan"],["Andujar, Miguel"],["Hernández, Teoscar"],["Burger, Jake"],["Keith, Colt"],["Wade Jr., LaMonte"],["Kiner-Falefa, Isiah"],["Taylor, Tyrone"],["Allen, Nick"],["Dingler, Dillon"],["Misner, Kameron"],["Moniak, Mickey"],["Bader, Harrison"],["Bailey, Patrick"],["Heim, Jonah"],["Farmer, Kyle"],["Pederson, Joc"],["Giménez, Andrés"],["Smith, Cam"],["Polanco, Jorge"],["Moreno, Gabriel"],["Baldwin, Brooks"],["Edman, Tommy"],["Adell, Jo"],["Thomas, Alek"],["Narváez, Carlos"],["Burleson, Alec"],["Neto, Zach"],["Taveras, Leody"],["Pham, Tommy"],["Lopez, Otto"],["Walls, Taylor"],["Paris, Kyren"],["Naylor, Bo"],["Urías, Luis"],["Jones, Nolan"],["Morel, Christopher"],["Acuña, Luisangel"],["Isbel, Kyle"],["Lee, Brooks"],["Kjerstad, Heston"],["Pagés, Pedro"],["Sánchez, Jesús"],["Caballero, José"],["Young, Jacob"],["Martínez, Angel"],["Mervis, Matt"],["Call, Alex"],["White, Eli"],["Moore, Dylan"],["Chisholm Jr., Jazz"],["Waters, Drew"],["Verdugo, Alex"],["Jansen, Danny"],["Kelly, Carson"],["Murphy, Sean"],["Schneemann, Daniel"],["Tellez, Rowdy"],["Cabrera, Oswaldo"],["Alvarez, Yordan"],["Trout, Mike"],["Williamson, Ben"],["Castro, Willi"],["Durbin, Caleb"],["Hernández, Enrique"],["Díaz, Elias"],["Sanoja, Javier"],["Fitzgerald, Tyler"],["Norby, Connor"],["Casas, Triston"],["Iglesias, Jose"],["Urías, Ramón"],["Marte, Ketel"],["Meidroth, Chase"],["Ramírez, Agustín"],["Simpson, Chandler"],["Lukes, Nathan"],["Laureano, Ramón"]],"fillcolor":"rgba(255,255,255,0)","hoveron":"points","hovertemplate":"metric=BA\u003cbr\u003eMetric - Expected Metric=%{x}\u003cbr\u003elast_name, first_name=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","jitter":0,"legendgroup":"BA","line":{"color":"rgba(255,255,255,0)"},"marker":{"color":"#636efa","symbol":"line-ns-open"},"name":"BA","showlegend":false,"x":{"dtype":"f8","bdata":"\u002fKnx0k1iYL8AtMh2vp+Kv\u002fyp8dJNYnC\u002fmx6F61G4nr9MN4lBYOWgv3sUrkfhenQ\u002f+n5qvHSTmL\u002f8qfHSTWJwP1pkO99PjZe\u002ff8QgsHJokb99bOf7qfGiv\u002fp+arx0k4i\u002faukmMQisrD\u002f6fmq8dJN4P6xJDAIrh6Y\u002fjcQgsHJoob\u002f8qfHSTWJwPwC0yHa+n4o\u002fObTIdr6fir8IrBxaZDuvv5qZmZmZmam\u002fO99PjZduor\u002f6fmq8dJOIPzs5tMh2vp+\u002fXhSuR+F6lL\u002f81qNwPQqnP\u002fyp8dJNYoA\u002f+n5qvHSTiD8730+Nl26Cv3npJjEIrHw\u002fwH5qvHSTiL\u002fdfmq8dJOYP\u002fp+arx0k4i\u002f\u002fKnx0k1iYD\u002fN+X5qvHSjP\u002fwDVg4tsp0\u002f3X5qvHSTmL\u002f8qfHSTWJwv1zpJjEIrJy\u002fgUkMAiuHhj\u002f8qfHSTWJwP7pJDAIrh5Y\u002fLd9PjZduor956SYxCKyMv\u002fp+arx0k3g\u002feekmMQisfL85tMh2vp+Kv3sUrkfhenS\u002fh35qvHSTeD9c6SYxCKycP7gehetRuJ6\u002fHbTIdr6fmr+eSQwCK4eWv7pJDAIrh4a\u002fHYcW2c73o7+6SQwCK4eWv3npJjEIrJw\u002fP+kmMQisjL+JQWDl0CKrv8B+arx0k4i\u002fQRSuR+F6hL\u002fZzvdT46Wrv\u002fp+arx0k3i\u002f+n5qvHSTiL\u002f81qNwPQqnv\u002fp+arx0k5g\u002fO99PjZdugj+cxCCwcmihP3sUrkfheoS\u002fmpmZmZmZmT85tMh2vp+KP9v5fmq8dJO\u002f+n5qvHSTiL+6SQwCK4eGP3npJjEIrHw\u002f\u002fKnx0k1iYL9YObTIdr6fvxsv3SQGgaU\u002fPIts5\u002fupsb89ZDvfT42Xv14UrkfhepS\u002f\u002fKnx0k1icL\u002fdfmq8dJOYv9+p8dJNYpA\u002f6SYxCKwcqr+4HoXrUbiOPwC0yHa+n4q\u002fO99PjZdugj97FK5H4XqUPwgUrkfhenS\u002f\u002fKnx0k1iYD9Ei2zn+6mxv7gehetRuJ6\u002f2\u002fl+arx0k78IrBxaZDuvv\u002fyp8dJNYoA\u002fuB6F61G4jj97FK5H4XqEP3sUrkfhepQ\u002f\u002fKnx0k1ikD\u002f8qfHSTWJwv\u002fp+arx0k6i\u002fexSuR+F6lL+6SQwCK4eWv3npJjEIrKy\u002f2c73U+Olm7\u002f8qfHSTWKQv\u002fyp8dJNYlC\u002fE35qvHSTaL\u002f8A1YOLbKdv\u002fyp8dJNYlC\u002fPTeJQWDloD\u002f6fmq8dJN4P7gehetRuI6\u002feekmMQisfL956SYxCKx8v38ehetRuI6\u002f\u002fKnx0k1iYL+cxCCwcmiRPzvfT42XbpI\u002fwqnx0k1igD\u002fb+X5qvHSjv\u002f4u3SQGgZW\u002fnMQgsHJoob9MN4lBYOWgv\u002fwDVg4tsp2\u002f\u002fKnx0k1iUL8AAAAAAAAAALgehetRuI6\u002fe0Fg5dAiq7+cxCCwcmiRv7zO91PjpZu\u002f7anx0k1ioD89N4lBYOWgP3sUrkfhepS\u002fK4cW2c73o79q6SYxCKysv3sUrkfhepS\u002fXLx0kxgEpr9YObTIdr6vvzvfT42XbpI\u002f36nx0k1ikD8rhxbZzvejv\u002fyp8dJNYmC\u002fnMQgsHJosb9BFK5H4XqEvzm0yHa+n5o\u002fnPHSTWIQqD8AAAAAAAAAAGrpJjEIrKy\u002f\u002fKnx0k1igD\u002f6fmq8dJOov5zEILByaJE\u002ff8QgsHJokT+8zvdT46Wbv\u002fyp8dJNYnC\u002f+n5qvHSTeD8\u002f6SYxCKyMvwAAAAAAAAAA\u002fi7dJAaBlT+q8dJNYhCoP3npJjEIrJy\u002fObTIdr6fij\u002f6fmq8dJNoP\u002fp+arx0k2g\u002feekmMQisjD+4HoXrUbiePzm0yHa+n4q\u002fXLx0kxgEpj\u002f8qfHSTWKQv\u002fp+arx0k3g\u002fRTeJQWDlsD\u002f8qfHSTWJQP\u002fp+arx0k3i\u002fTGQ730+Npz956SYxCKx8v14UrkfhepS\u002fSgwCK4cWqb+LbOf7qfGivx20yHa+n5o\u002fObTIdr6fmr99mZmZmZmZP\u002fyp8dJNYnA\u002fexSuR+F6lD8K16NwPQqnv6oehetRuK4\u002f\u002fKnx0k1igL\u002f8qfHSTWJgP9+p8dJNYpA\u002fLDMzMzMzs7+4HoXrUbiuv7pJDAIrh4Y\u002f7FG4HoXrob\u002f6fmq8dJNov\u002fp+arx0k4i\u002f\u002fKnx0k1isL+4HoXrUbiuv5zEILByaJE\u002f7anx0k1ioD+bHoXrUbieP3sUrkfhenS\u002fWmQ730+Nlz+4HoXrUbiOvzyLbOf7qbG\u002fnkkMAiuHlr\u002f8qfHSTWKAP4FJDAIrh4a\u002fukkMAiuHlj8pXI\u002fC9Sisv4FJDAIrh4a\u002fAAAAAAAAAABaZDvfT42nPwLfT42XboK\u002f2\u002fl+arx0o7\u002f8qfHSTWJgP7gehetRuJ6\u002f\u002fi7dJAaBlT85tMh2vp+qv3sUrkfheqQ\u002fXhSuR+F6lD\u002f6fmq8dJOoP8Kp8dJNYoC\u002fuB6F61G4jj\u002f8qfHSTWKgvxsv3SQGgZU\u002fvM73U+Olm7956SYxCKyMv\u002f4u3SQGgZU\u002f\u002fKnx0k1igD\u002f6fmq8dJNoP7pJDAIrh6a\u002f\u002fKnx0k1icL8730+Nl26iv+xRuB6F67G\u002fwqnx0k1igL8G6SYxCKx8Pz1kO99PjZe\u002ffZmZmZmZmb85tMh2vp+KP\u002fp+arx0k4i\u002fSgwCK4cWqT\u002f6fmq8dJOoP5zEILByaKG\u002fAAAAAAAAAAD8qfHSTWKgP1zpJjEIrJy\u002fPTeJQWDloD+cxCCwcmiRv\u002fp+arx0k3i\u002fXOkmMQisnL+6SQwCK4eGPw=="},"xaxis":"x2","yaxis":"y2","type":"box"},{"bingroup":"x","hovertemplate":"metric=SLG\u003cbr\u003eMetric - Expected Metric=%{x}\u003cbr\u003ecount=%{y}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"SLG","marker":{"color":"#EF553B","pattern":{"shape":""}},"name":"SLG","orientation":"v","showlegend":true,"x":{"dtype":"f8","bdata":"ALTIdr6fij9MN4lBYOWgvz03iUFg5aC\u002fbBSuR+F6pL\u002fSzvdT46W7vxN+arx0k2g\u002fg8DKoUW2s7+bHoXrUbiePylcj8L1KKy\u002fi5mZmZmZqb9aZDvfT423v\u002fp+arx0k4i\u002f\u002fKnx0k1ikD89ZDvfT42Xv0SLbOf7qbE\u002fVOOlm8QgsL\u002f6fmq8dJOov\u002fwDVg4tsp2\u002fo\u002fHSTWIQuL8s3SQGgZXDv89NYhBYOcS\u002fTDeJQWDlsL+LmZmZmZmpvyuHFtnO97O\u002f9P3UeOkmsb9sFK5H4XqkP7v1KFyPwrU\u002fGy\u002fdJAaBlT\u002fb+X5qvHSzvxkEVg4tsp0\u002fXOkmMQisnL98wMqhRbazP9v5fmq8dKO\u002fexSuR+F6hD98wMqhRbazP\u002fyp8dJNYlC\u002fRIts5\u002fupsb+bHoXrUbievz1kO99PjZe\u002fexSuR+F6dL+kcD0K16Owv\u002fT91HjpJrE\u002fuB6F61G4jr\u002fb+X5qvHSjP7yhRbbz\u002faS\u002f7FG4HoXroT956SYxCKx8P3tBYOXQIqu\u002feekmMQisfL\u002fZzvdT46WbP6RwPQrXo7C\u002fuB6F61G4jr8rhxbZzvejv3tBYOXQIqu\u002f2\u002fl+arx0s79LuB6F61G4v\u002fyp8dJNYpA\u002fzfl+arx0o7\u002fkUbgeheuxv5qZmZmZmam\u002fuB6F61G4rr8zMzMzMzPDv\u002fp+arx0k2g\u002f7FG4HoXrsb9YObTIdr6vv0SLbOf7qbE\u002fmpmZmZmZmb9aZDvfT42Xv\u002fyp8dJNYlC\u002fHbTIdr6fmj8bXI\u002fC9SisP2IQWDm0yLa\u002fpHA9CtejsL8730+Nl26Cv\u002fyp8dJNYlA\u002f2c73U+Olmz+TGARWDi2yv3npJjEIrKw\u002fZmZmZmZmxr97FK5H4XqEv\u002fT91HjpJrG\u002fCgRWDi2yrb8zMzMzMzOzv\u002fyp8dJNYoC\u002fkxgEVg4tsr\u002f8qfHSTWKwPzvfT42XboK\u002f46WbxCCwsj\u002f8qfHSTWJQv38ehetRuI6\u002fexSuR+F6dL83iUFg5dDCv3sUrkfheqS\u002fEQRWDi2yvb+wcmiR7Xy\u002fv5zEILByaKE\u002fuB6F61G4jj\u002f6fmq8dJOYP9v5fmq8dJO\u002f001iEFg5tD99bOf7qfGiP9p6FK5H4bq\u002fGy\u002fdJAaBlb\u002fkUbgeheuxvxqwcmiR7by\u002f\u002fKnx0k1ikL+bRbbz\u002fdS4v3sUrkfhepS\u002f\u002fKnx0k1iYL8rhxbZzvezv8vO91Pjpau\u002fLd9PjZduoj\u002f6fmq8dJOov\u002fyp8dJNYoC\u002f\u002fKnx0k1icL+6SQwCK4eGv\u002fp+arx0k4i\u002fGy\u002fdJAaBpT9MZDvfT42nPzvfT42XboI\u002fObTIdr6fir+yne+nxku3v\u002fp+arx0k4i\u002fwXa+nxovvb\u002fZzvdT46W7v9ylm8QgsLK\u002fwqnx0k1igL+kcD0K16Owv1y8dJMYBKa\u002fkpmZmZmZub+6dr6fGi+tv2wUrkfheqS\u002fDC\u002fdJAaBpT87DAIrhxapP\u002fzWo3A9Cqe\u002f4iYxCKwcur\u002f6fmq8dJO4vyPb+X5qvLS\u002fK7TIdr6fqr9pPQrXo3C9v0w3iUFg5aA\u002fnMQgsHJokb9Ei2zn+6nBv7yhRbbz\u002faS\u002fCtejcD0Kt797QWDl0CKrv3sUrkfhenS\u002fkxgEVg4tsj9aZDvfT42XP0SLbOf7qbG\u002fWmQ730+Np7+rne+nxku3v\u002fp+arx0k3i\u002fWmQ730+Nl7+YbhKDwMrBv\u002fp+arx0k2g\u002fPTeJQWDloD956SYxCKyMP32ZmZmZmZm\u002fK4cW2c73oz8730+Nl26Sv7pJDAIrh6a\u002fA9ejcD0Kt785tMh2vp+aP9v5fmq8dJM\u002fTDeJQWDloD\u002f6fmq8dJOIP3Noke18P7W\u002faJHtfD81rj87ObTIdr6fv4lBYOXQIqu\u002fCgRWDi2yrT8AAAAAAAAAAOt+arx0k6i\u002f9P3UeOkmsT+LmZmZmZmpP+kmMQisHKq\u002fIlyPwvUovL8rhxbZzvejvx2HFtnO96M\u002fuB6F61G4nr+BSQwCK4eGP91RuB6F66G\u002faukmMQisrD+kcD0K16Owv9NNYhBYObQ\u002fuB6F61G4rr8IFK5H4Xp0P5zx0k1iEKg\u002fIlyPwvUovL\u002fsUbgeheuxv7pJDAIrh5Y\u002fCBSuR+F6hL+amZmZmZmZv+2p8dJNYqC\u002fKVyPwvUorL\u002faehSuR+G6v\u002fyp8dJNYoA\u002fwH5qvHSTiD\u002f8qfHSTWJQP1qR7Xw\u002fNa6\u002fLd9PjZduoj+JQWDl0CKrv\u002fCnxks3icG\u002f6SYxCKwcqr\u002f6fmq8dJOYP3sUrkfhenS\u002fe0Fg5dAiqz93vp8aL93Ev2O8dJMYBLa\u002fnMQgsHJokb+K7Xw\u002fNV66Pxtcj8L1KKy\u002fMrTIdr6fur\u002fdfmq8dJOYP1TjpZvEIMC\u002f\u002fKnx0k1isD\u002fLoUW28\u002f2kv0SLbOf7qbE\u002fWmQ730+Ntz8ML90kBoGlP3npJjEIrJw\u002fDC\u002fdJAaBpT+4HoXrUbiev6RwPQrXo7A\u002fdBSuR+F6tL87DAIrhxapv4wYBFYOLbI\u002faukmMQisrD8dtMh2vp+avwisHFpkO6+\u002f+n5qvHSTeD\u002fTo3A9CtfDv2k9CtejcL2\u002faJHtfD81rr97FK5H4XqEP2wUrkfheqS\u002fPWQ730+Nl7+eSQwCK4eWP3sUrkfhepS\u002fm0W28\u002f3UuD\u002f6fmq8dJOYv4JBYOXQIru\u002f+n5qvHSTaL956SYxCKx8v3npJjEIrHw\u002fi2zn+6nxoj8bL90kBoGlPzvfT42XboK\u002fO99PjZdugj\u002f6fmq8dJNoPw=="},"xaxis":"x","yaxis":"y","type":"histogram"},{"boxpoints":"all","customdata":[["Duran, Jarren"],["Carroll, Corbin"],["Devers, Rafael"],["Tucker, Kyle"],["Ohtani, Shohei"],["Lindor, Francisco"],["Bichette, Bo"],["Chourio, Jackson"],["Nootbaar, Lars"],["Harper, Bryce"],["Rooker, Brent"],["Witt Jr., Bobby"],["Judge, Aaron"],["De La Cruz, Elly"],["Bregman, Alex"],["Schwarber, Kyle"],["Adames, Willy"],["Wood, James"],["Alonso, Pete"],["Soto, Juan"],["Reynolds, Bryan"],["Rodríguez, Julio"],["Riley, Austin"],["Guerrero Jr., Vladimir"],["Soderstrom, Tyler"],["Turner, Trea"],["Paredes, Isaac"],["Kwan, Steven"],["Olson, Matt"],["Raleigh, Cal"],["Albies, Ozzie"],["Crow-Armstrong, Pete"],["Swanson, Dansby"],["Peña, Jeremy"],["Perdomo, Geraldo"],["Ramos, Heliot"],["Pasquantino, Vinnie"],["Torkelson, Spencer"],["Lowe, Nathaniel"],["Naylor, Josh"],["Turang, Brice"],["Friedl, TJ"],["Yelich, Christian"],["Lee, Jung Hoo"],["Castellanos, Nick"],["Suzuki, Seiya"],["Betts, Mookie"],["Donovan, Brendan"],["Butler, Lawrence"],["Altuve, Jose"],["Chapman, Matt"],["Ward, Taylor"],["Suárez, Eugenio"],["Tatis Jr., Fernando"],["Walker, Christian"],["Contreras, Willson"],["Greene, Riley"],["Arozarena, Randy"],["Harris II, Michael"],["Ozuna, Marcell"],["Story, Trevor"],["Semien, Marcus"],["Volpe, Anthony"],["McMahon, Ryan"],["Díaz, Yandy"],["Wilson, Jacob"],["Crawford, J.P."],["Goldschmidt, Paul"],["Larnach, Trevor"],["Garcia, Maikel"],["Ramírez, José"],["Machado, Manny"],["Happ, Ian"],["Contreras, William"],["Hoerner, Nico"],["Arenado, Nolan"],["India, Jonathan"],["Goodman, Hunter"],["Perez, Salvador"],["Gurriel Jr., Lourdes"],["Bohm, Alec"],["Hayes, Ke'Bryan"],["García, Adolis"],["Santana, Carlos"],["Nimmo, Brandon"],["Flores, Wilmer"],["Vargas, Miguel"],["Mullins, Cedric"],["Edwards, Xavier"],["Schanuel, Nolan"],["Soler, Jorge"],["Vaughn, Andrew"],["Bogaerts, Xander"],["France, Ty"],["Robert Jr., Luis"],["Frelick, Sal"],["Bellinger, Cody"],["Pages, Andy"],["Stowers, Kyle"],["Arraez, Luis"],["Bleday, JJ"],["Lowe, Brandon"],["Caminero, Junior"],["Abreu, Wilyer"],["Rutschman, Adley"],["Langeliers, Shea"],["Muncy, Max"],["Stott, Bryson"],["Vientos, Mark"],["Cruz, Oneil"],["Busch, Michael"],["Hoskins, Rhys"],["Carpenter, Kerry"],["Santander, Anthony"],["Toglia, Michael"],["Campbell, Kristian"],["Steer, Spencer"],["Henderson, Gunnar"],["McKinstry, Zach"],["Yastrzemski, Mike"],["Sweeney, Trey"],["McLain, Matt"],["Ruiz, Keibert"],["Mountcastle, Ryan"],["Diaz, Yainer"],["Wagaman, Eric"],["Manzardo, Kyle"],["Springer, George"],["Massey, Michael"],["Conforto, Michael"],["Langford, Wyatt"],["Kepler, Max"],["Lux, Gavin"],["Scott II, Victor"],["Realmuto, J.T."],["Doyle, Brenton"],["García Jr., Luis"],["McCutchen, Andrew"],["Rice, Ben"],["Crews, Dylan"],["Buxton, Byron"],["Arias, Gabriel"],["Rafaela, Ceddanne"],["Holliday, Jackson"],["Ortiz, Joey"],["Sosa, Lenyn"],["Meyers, Jake"],["Freeman, Freddie"],["Abrams, CJ"],["Bell, Josh"],["Aranda, Jonathan"],["Rengifo, Luis"],["O'Hoppe, Logan"],["Jung, Josh"],["Torres, Gleyber"],["Domínguez, Jasson"],["Winn, Masyn"],["Wells, Austin"],["Smith, Josh"],["Sheets, Gavin"],["Smith, Will"],["Correa, Carlos"],["Bart, Joey"],["O'Hearn, Ryan"],["Frazier, Adam"],["Beck, Jordan"],["Espinal, Santiago"],["Kirk, Alejandro"],["Báez, Javier"],["Grisham, Trent"],["Jeffers, Ryan"],["Smith, Pavin"],["Clement, Ernie"],["Walker, Jordan"],["Andujar, Miguel"],["Hernández, Teoscar"],["Burger, Jake"],["Keith, Colt"],["Wade Jr., LaMonte"],["Kiner-Falefa, Isiah"],["Taylor, Tyrone"],["Allen, Nick"],["Dingler, Dillon"],["Misner, Kameron"],["Moniak, Mickey"],["Bader, Harrison"],["Bailey, Patrick"],["Heim, Jonah"],["Farmer, Kyle"],["Pederson, Joc"],["Giménez, Andrés"],["Smith, Cam"],["Polanco, Jorge"],["Moreno, Gabriel"],["Baldwin, Brooks"],["Edman, Tommy"],["Adell, Jo"],["Thomas, Alek"],["Narváez, Carlos"],["Burleson, Alec"],["Neto, Zach"],["Taveras, Leody"],["Pham, Tommy"],["Lopez, Otto"],["Walls, Taylor"],["Paris, Kyren"],["Naylor, Bo"],["Urías, Luis"],["Jones, Nolan"],["Morel, Christopher"],["Acuña, Luisangel"],["Isbel, Kyle"],["Lee, Brooks"],["Kjerstad, Heston"],["Pagés, Pedro"],["Sánchez, Jesús"],["Caballero, José"],["Young, Jacob"],["Martínez, Angel"],["Mervis, Matt"],["Call, Alex"],["White, Eli"],["Moore, Dylan"],["Chisholm Jr., Jazz"],["Waters, Drew"],["Verdugo, Alex"],["Jansen, Danny"],["Kelly, Carson"],["Murphy, Sean"],["Schneemann, Daniel"],["Tellez, Rowdy"],["Cabrera, Oswaldo"],["Alvarez, Yordan"],["Trout, Mike"],["Williamson, Ben"],["Castro, Willi"],["Durbin, Caleb"],["Hernández, Enrique"],["Díaz, Elias"],["Sanoja, Javier"],["Fitzgerald, Tyler"],["Norby, Connor"],["Casas, Triston"],["Iglesias, Jose"],["Urías, Ramón"],["Marte, Ketel"],["Meidroth, Chase"],["Ramírez, Agustín"],["Simpson, Chandler"],["Lukes, Nathan"],["Laureano, Ramón"]],"fillcolor":"rgba(255,255,255,0)","hoveron":"points","hovertemplate":"metric=SLG\u003cbr\u003eMetric - Expected Metric=%{x}\u003cbr\u003elast_name, first_name=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","jitter":0,"legendgroup":"SLG","line":{"color":"rgba(255,255,255,0)"},"marker":{"color":"#EF553B","symbol":"line-ns-open"},"name":"SLG","showlegend":false,"x":{"dtype":"f8","bdata":"ALTIdr6fij9MN4lBYOWgvz03iUFg5aC\u002fbBSuR+F6pL\u002fSzvdT46W7vxN+arx0k2g\u002fg8DKoUW2s7+bHoXrUbiePylcj8L1KKy\u002fi5mZmZmZqb9aZDvfT423v\u002fp+arx0k4i\u002f\u002fKnx0k1ikD89ZDvfT42Xv0SLbOf7qbE\u002fVOOlm8QgsL\u002f6fmq8dJOov\u002fwDVg4tsp2\u002fo\u002fHSTWIQuL8s3SQGgZXDv89NYhBYOcS\u002fTDeJQWDlsL+LmZmZmZmpvyuHFtnO97O\u002f9P3UeOkmsb9sFK5H4XqkP7v1KFyPwrU\u002fGy\u002fdJAaBlT\u002fb+X5qvHSzvxkEVg4tsp0\u002fXOkmMQisnL98wMqhRbazP9v5fmq8dKO\u002fexSuR+F6hD98wMqhRbazP\u002fyp8dJNYlC\u002fRIts5\u002fupsb+bHoXrUbievz1kO99PjZe\u002fexSuR+F6dL+kcD0K16Owv\u002fT91HjpJrE\u002fuB6F61G4jr\u002fb+X5qvHSjP7yhRbbz\u002faS\u002f7FG4HoXroT956SYxCKx8P3tBYOXQIqu\u002feekmMQisfL\u002fZzvdT46WbP6RwPQrXo7C\u002fuB6F61G4jr8rhxbZzvejv3tBYOXQIqu\u002f2\u002fl+arx0s79LuB6F61G4v\u002fyp8dJNYpA\u002fzfl+arx0o7\u002fkUbgeheuxv5qZmZmZmam\u002fuB6F61G4rr8zMzMzMzPDv\u002fp+arx0k2g\u002f7FG4HoXrsb9YObTIdr6vv0SLbOf7qbE\u002fmpmZmZmZmb9aZDvfT42Xv\u002fyp8dJNYlC\u002fHbTIdr6fmj8bXI\u002fC9SisP2IQWDm0yLa\u002fpHA9CtejsL8730+Nl26Cv\u002fyp8dJNYlA\u002f2c73U+Olmz+TGARWDi2yv3npJjEIrKw\u002fZmZmZmZmxr97FK5H4XqEv\u002fT91HjpJrG\u002fCgRWDi2yrb8zMzMzMzOzv\u002fyp8dJNYoC\u002fkxgEVg4tsr\u002f8qfHSTWKwPzvfT42XboK\u002f46WbxCCwsj\u002f8qfHSTWJQv38ehetRuI6\u002fexSuR+F6dL83iUFg5dDCv3sUrkfheqS\u002fEQRWDi2yvb+wcmiR7Xy\u002fv5zEILByaKE\u002fuB6F61G4jj\u002f6fmq8dJOYP9v5fmq8dJO\u002f001iEFg5tD99bOf7qfGiP9p6FK5H4bq\u002fGy\u002fdJAaBlb\u002fkUbgeheuxvxqwcmiR7by\u002f\u002fKnx0k1ikL+bRbbz\u002fdS4v3sUrkfhepS\u002f\u002fKnx0k1iYL8rhxbZzvezv8vO91Pjpau\u002fLd9PjZduoj\u002f6fmq8dJOov\u002fyp8dJNYoC\u002f\u002fKnx0k1icL+6SQwCK4eGv\u002fp+arx0k4i\u002fGy\u002fdJAaBpT9MZDvfT42nPzvfT42XboI\u002fObTIdr6fir+yne+nxku3v\u002fp+arx0k4i\u002fwXa+nxovvb\u002fZzvdT46W7v9ylm8QgsLK\u002fwqnx0k1igL+kcD0K16Owv1y8dJMYBKa\u002fkpmZmZmZub+6dr6fGi+tv2wUrkfheqS\u002fDC\u002fdJAaBpT87DAIrhxapP\u002fzWo3A9Cqe\u002f4iYxCKwcur\u002f6fmq8dJO4vyPb+X5qvLS\u002fK7TIdr6fqr9pPQrXo3C9v0w3iUFg5aA\u002fnMQgsHJokb9Ei2zn+6nBv7yhRbbz\u002faS\u002fCtejcD0Kt797QWDl0CKrv3sUrkfhenS\u002fkxgEVg4tsj9aZDvfT42XP0SLbOf7qbG\u002fWmQ730+Np7+rne+nxku3v\u002fp+arx0k3i\u002fWmQ730+Nl7+YbhKDwMrBv\u002fp+arx0k2g\u002fPTeJQWDloD956SYxCKyMP32ZmZmZmZm\u002fK4cW2c73oz8730+Nl26Sv7pJDAIrh6a\u002fA9ejcD0Kt785tMh2vp+aP9v5fmq8dJM\u002fTDeJQWDloD\u002f6fmq8dJOIP3Noke18P7W\u002faJHtfD81rj87ObTIdr6fv4lBYOXQIqu\u002fCgRWDi2yrT8AAAAAAAAAAOt+arx0k6i\u002f9P3UeOkmsT+LmZmZmZmpP+kmMQisHKq\u002fIlyPwvUovL8rhxbZzvejvx2HFtnO96M\u002fuB6F61G4nr+BSQwCK4eGP91RuB6F66G\u002faukmMQisrD+kcD0K16Owv9NNYhBYObQ\u002fuB6F61G4rr8IFK5H4Xp0P5zx0k1iEKg\u002fIlyPwvUovL\u002fsUbgeheuxv7pJDAIrh5Y\u002fCBSuR+F6hL+amZmZmZmZv+2p8dJNYqC\u002fKVyPwvUorL\u002faehSuR+G6v\u002fyp8dJNYoA\u002fwH5qvHSTiD\u002f8qfHSTWJQP1qR7Xw\u002fNa6\u002fLd9PjZduoj+JQWDl0CKrv\u002fCnxks3icG\u002f6SYxCKwcqr\u002f6fmq8dJOYP3sUrkfhenS\u002fe0Fg5dAiqz93vp8aL93Ev2O8dJMYBLa\u002fnMQgsHJokb+K7Xw\u002fNV66Pxtcj8L1KKy\u002fMrTIdr6fur\u002fdfmq8dJOYP1TjpZvEIMC\u002f\u002fKnx0k1isD\u002fLoUW28\u002f2kv0SLbOf7qbE\u002fWmQ730+Ntz8ML90kBoGlP3npJjEIrJw\u002fDC\u002fdJAaBpT+4HoXrUbiev6RwPQrXo7A\u002fdBSuR+F6tL87DAIrhxapv4wYBFYOLbI\u002faukmMQisrD8dtMh2vp+avwisHFpkO6+\u002f+n5qvHSTeD\u002fTo3A9CtfDv2k9CtejcL2\u002faJHtfD81rr97FK5H4XqEP2wUrkfheqS\u002fPWQ730+Nl7+eSQwCK4eWP3sUrkfhepS\u002fm0W28\u002f3UuD\u002f6fmq8dJOYv4JBYOXQIru\u002f+n5qvHSTaL956SYxCKx8v3npJjEIrHw\u002fi2zn+6nxoj8bL90kBoGlPzvfT42XboK\u002fO99PjZdugj\u002f6fmq8dJNoPw=="},"xaxis":"x2","yaxis":"y2","type":"box"},{"bingroup":"x","hovertemplate":"metric=wOBA\u003cbr\u003eMetric - Expected Metric=%{x}\u003cbr\u003ecount=%{y}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"wOBA","marker":{"color":"#00cc96","pattern":{"shape":""}},"name":"wOBA","orientation":"v","showlegend":true,"x":{"dtype":"f8","bdata":"\u002fKnx0k1icL9\u002fHoXrUbiOv7gehetRuI6\u002fPWQ730+Nl7\u002frfmq8dJOov\u002fyp8dJNYmA\u002fzfl+arx0o7+4HoXrUbiOPx20yHa+n5q\u002fukkMAiuHlr9MZDvfT42nv3sUrkfhepS\u002f7FG4HoXroT\u002f6fmq8dJNovwrXo3A9Cqc\u002fGQRWDi2ynb+4HoXrUbiOv\u002fyp8dJNYlC\u002fjcQgsHJoob\u002fTTWIQWDm0vySHFtnO97O\u002fLd9PjZduor\u002f8qfHSTWKAv3sUrkfheqS\u002fGQRWDi2ynb\u002fN+X5qvHSjP91RuB6F66E\u002f\u002fKnx0k1ikD8ZBFYOLbKdv38ehetRuI4\u002fP+kmMQisjL8bL90kBoGlP5zEILByaJG\u002f+n5qvHSTaD99bOf7qfGiP7gehetRuI4\u002f7FG4HoXrob+6SQwCK4eGv7pJDAIrh5a\u002fE35qvHSTaD8dtMh2vp+av0w3iUFg5aA\u002f2\u002fl+arx0k7+Hfmq8dJN4P7pJDAIrh4a\u002fO99PjZdugj8AAAAAAAAAABsv3SQGgZW\u002f+n5qvHSTaD\u002fdfmq8dJOYP5sehetRuJ6\u002fP+kmMQisjL85tMh2vp+av5qZmZmZmZm\u002fXLx0kxgEpr9sFK5H4Xqkv1pkO99PjZc\u002f\u002fKnx0k1ikL9q6SYxCKysv3\u002fEILByaJG\u002fPWQ730+Nl7+DwMqhRbazv\u002fyp8dJNYnC\u002fHbTIdr6fmr9cvHSTGASmv2wUrkfheqQ\u002f\u002fKnx0k1iYL+6SQwCK4eGP\u002fyp8dJNYmC\u002fukkMAiuHlj\u002f6fmq8dJOYP4ts5\u002fup8aK\u002f\u002fANWDi2ynb\u002f8qfHSTWJQP3npJjEIrHw\u002fexSuR+F6hD+LbOf7qfGivwwv3SQGgaU\u002fo\u002fHSTWIQuL956SYxCKyMv8uhRbbz\u002faS\u002f\u002fi7dJAaBlb\u002f81qNwPQqnv3sUrkfhenQ\u002fqvHSTWIQqL+cxCCwcmihP\u002fp+arx0k3i\u002fuB6F61G4nj\u002fCqfHSTWKAP\u002fyp8dJNYnC\u002f\u002fKnx0k1iYL+6SQwCK4e2v7gehetRuJ6\u002fOwwCK4cWqb+cxCCwcmixv5zEILByaJE\u002feekmMQisfD85tMh2vp+KP\u002fyp8dJNYmA\u002fK4cW2c73oz9BFK5H4XqEP2rpJjEIrKy\u002f2\u002fl+arx0k7+4HoXrUbievwisHFpkO6+\u002fH99PjZdukr+LbOf7qfGiv\u002fyp8dJNYnC\u002f\u002fKnx0k1iUD9aZDvfT42nv\u002fyp8dJNYpC\u002fObTIdr6fmj956SYxCKyMv3sUrkfheoS\u002f+n5qvHSTaL\u002f8qfHSTWJwv\u002fyp8dJNYoC\u002fnMQgsHJokT97FK5H4XqUPwC0yHa+n4o\u002f\u002fKnx0k1iUL9MZDvfT42nv7pJDAIrh4a\u002faukmMQisrL8rtMh2vp+qv835fmq8dKO\u002f+n5qvHSTaL\u002fb+X5qvHSTvz1kO99PjZe\u002fe0Fg5dAiq7956SYxCKycv\u002fp+arx0k5i\u002fmx6F61G4nj9YObTIdr6fP7pJDAIrh5a\u002fe0Fg5dAiq7+cxCCwcmixv+2p8dJNYqC\u002fDC\u002fdJAaBpb9MN4lBYOWwv3\u002fEILByaJE\u002f\u002fKnx0k1iYL+kcD0K16Owv8B+arx0k4i\u002fCKwcWmQ7r797FK5H4XqUv0EUrkfheoQ\u002fGy\u002fdJAaBpT+6SQwCK4eGP0xkO99Pjae\u002fukkMAiuHhr+6dr6fGi+tv\u002fyp8dJNYoA\u002f+n5qvHSTaD9q6SYxCKysv\u002fyp8dJNYmA\u002fnMQgsHJokT97FK5H4Xp0v\u002fp+arx0k3i\u002fXOkmMQisnD\u002ffqfHSTWKQP\u002fwDVg4tsp2\u002fukkMAiuHlr956SYxCKyMP4FJDAIrh4Y\u002f\u002fKnx0k1ikD\u002f+Lt0kBoGVP0w3iUFg5aC\u002f\u002fNajcD0Kpz8AtMh2vp+KvwC0yHa+n4q\u002fi5mZmZmZqT\u002f6fmq8dJNov3sUrkfhepS\u002fexSuR+F6pD8730+Nl26SP7gehetRuJ6\u002faukmMQisrL9c6SYxCKycv9nO91PjpZs\u002fukkMAiuHlr+cxCCwcmiRP8Kp8dJNYoC\u002fmx6F61G4nj+sSQwCK4emvxtcj8L1KKw\u002fHbTIdr6fmr97FK5H4Xp0P775fmq8dJM\u002fTDeJQWDlsL+6dr6fGi+tv7gehetRuI4\u002fGy\u002fdJAaBlb\u002f6fmq8dJN4v1zpJjEIrJy\u002fG1yPwvUorL8IrBxaZDuvv3sUrkfhenQ\u002fukkMAiuHlj8730+Nl26SP1pkO99PjZe\u002f2c73U+Olmz99mZmZmZmZvySHFtnO97O\u002fmpmZmZmZmb956SYxCKyMP\u002fyp8dJNYnC\u002f3X5qvHSTmD8rhxbZzvezvz03iUFg5aC\u002fwqnx0k1igL8KBFYOLbKtP9nO91PjpZu\u002fe0Fg5dAiq797FK5H4XqEP9smMQisHKq\u002fOzm0yHa+nz8t30+Nl26iv2wUrkfheqQ\u002fbBSuR+F6pD89ZDvfT42XP\u002fyp8dJNYoA\u002f\u002fKnx0k1ikD8bL90kBoGVv91RuB6F66E\u002fi2zn+6nxor\u002fb+X5qvHSTv91RuB6F66E\u002fHbTIdr6fmj\u002f8qfHSTWJwv1y8dJMYBKa\u002f+n5qvHSTaD+79Shcj8K1v5zEILByaLG\u002f+n5qvHSTmL\u002f8qfHSTWKAPxsv3SQGgZW\u002f\u002fKnx0k1ikL9\u002fxCCwcmiRP7pJDAIrh4a\u002fCgRWDi2yrT+cxCCwcmiRPzsMAiuHFqm\u002fAAAAAAAAAAD8qfHSTWJgPwgUrkfhenS\u002fmx6F61G4nj\u002f6fmq8dJOIPzm0yHa+n4q\u002f\u002fKnx0k1icL+6SQwCK4eGPw=="},"xaxis":"x","yaxis":"y","type":"histogram"},{"boxpoints":"all","customdata":[["Duran, Jarren"],["Carroll, Corbin"],["Devers, Rafael"],["Tucker, Kyle"],["Ohtani, Shohei"],["Lindor, Francisco"],["Bichette, Bo"],["Chourio, Jackson"],["Nootbaar, Lars"],["Harper, Bryce"],["Rooker, Brent"],["Witt Jr., Bobby"],["Judge, Aaron"],["De La Cruz, Elly"],["Bregman, Alex"],["Schwarber, Kyle"],["Adames, Willy"],["Wood, James"],["Alonso, Pete"],["Soto, Juan"],["Reynolds, Bryan"],["Rodríguez, Julio"],["Riley, Austin"],["Guerrero Jr., Vladimir"],["Soderstrom, Tyler"],["Turner, Trea"],["Paredes, Isaac"],["Kwan, Steven"],["Olson, Matt"],["Raleigh, Cal"],["Albies, Ozzie"],["Crow-Armstrong, Pete"],["Swanson, Dansby"],["Peña, Jeremy"],["Perdomo, Geraldo"],["Ramos, Heliot"],["Pasquantino, Vinnie"],["Torkelson, Spencer"],["Lowe, Nathaniel"],["Naylor, Josh"],["Turang, Brice"],["Friedl, TJ"],["Yelich, Christian"],["Lee, Jung Hoo"],["Castellanos, Nick"],["Suzuki, Seiya"],["Betts, Mookie"],["Donovan, Brendan"],["Butler, Lawrence"],["Altuve, Jose"],["Chapman, Matt"],["Ward, Taylor"],["Suárez, Eugenio"],["Tatis Jr., Fernando"],["Walker, Christian"],["Contreras, Willson"],["Greene, Riley"],["Arozarena, Randy"],["Harris II, Michael"],["Ozuna, Marcell"],["Story, Trevor"],["Semien, Marcus"],["Volpe, Anthony"],["McMahon, Ryan"],["Díaz, Yandy"],["Wilson, Jacob"],["Crawford, J.P."],["Goldschmidt, Paul"],["Larnach, Trevor"],["Garcia, Maikel"],["Ramírez, José"],["Machado, Manny"],["Happ, Ian"],["Contreras, William"],["Hoerner, Nico"],["Arenado, Nolan"],["India, Jonathan"],["Goodman, Hunter"],["Perez, Salvador"],["Gurriel Jr., Lourdes"],["Bohm, Alec"],["Hayes, Ke'Bryan"],["García, Adolis"],["Santana, Carlos"],["Nimmo, Brandon"],["Flores, Wilmer"],["Vargas, Miguel"],["Mullins, Cedric"],["Edwards, Xavier"],["Schanuel, Nolan"],["Soler, Jorge"],["Vaughn, Andrew"],["Bogaerts, Xander"],["France, Ty"],["Robert Jr., Luis"],["Frelick, Sal"],["Bellinger, Cody"],["Pages, Andy"],["Stowers, Kyle"],["Arraez, Luis"],["Bleday, JJ"],["Lowe, Brandon"],["Caminero, Junior"],["Abreu, Wilyer"],["Rutschman, Adley"],["Langeliers, Shea"],["Muncy, Max"],["Stott, Bryson"],["Vientos, Mark"],["Cruz, Oneil"],["Busch, Michael"],["Hoskins, Rhys"],["Carpenter, Kerry"],["Santander, Anthony"],["Toglia, Michael"],["Campbell, Kristian"],["Steer, Spencer"],["Henderson, Gunnar"],["McKinstry, Zach"],["Yastrzemski, Mike"],["Sweeney, Trey"],["McLain, Matt"],["Ruiz, Keibert"],["Mountcastle, Ryan"],["Diaz, Yainer"],["Wagaman, Eric"],["Manzardo, Kyle"],["Springer, George"],["Massey, Michael"],["Conforto, Michael"],["Langford, Wyatt"],["Kepler, Max"],["Lux, Gavin"],["Scott II, Victor"],["Realmuto, J.T."],["Doyle, Brenton"],["García Jr., Luis"],["McCutchen, Andrew"],["Rice, Ben"],["Crews, Dylan"],["Buxton, Byron"],["Arias, Gabriel"],["Rafaela, Ceddanne"],["Holliday, Jackson"],["Ortiz, Joey"],["Sosa, Lenyn"],["Meyers, Jake"],["Freeman, Freddie"],["Abrams, CJ"],["Bell, Josh"],["Aranda, Jonathan"],["Rengifo, Luis"],["O'Hoppe, Logan"],["Jung, Josh"],["Torres, Gleyber"],["Domínguez, Jasson"],["Winn, Masyn"],["Wells, Austin"],["Smith, Josh"],["Sheets, Gavin"],["Smith, Will"],["Correa, Carlos"],["Bart, Joey"],["O'Hearn, Ryan"],["Frazier, Adam"],["Beck, Jordan"],["Espinal, Santiago"],["Kirk, Alejandro"],["Báez, Javier"],["Grisham, Trent"],["Jeffers, Ryan"],["Smith, Pavin"],["Clement, Ernie"],["Walker, Jordan"],["Andujar, Miguel"],["Hernández, Teoscar"],["Burger, Jake"],["Keith, Colt"],["Wade Jr., LaMonte"],["Kiner-Falefa, Isiah"],["Taylor, Tyrone"],["Allen, Nick"],["Dingler, Dillon"],["Misner, Kameron"],["Moniak, Mickey"],["Bader, Harrison"],["Bailey, Patrick"],["Heim, Jonah"],["Farmer, Kyle"],["Pederson, Joc"],["Giménez, Andrés"],["Smith, Cam"],["Polanco, Jorge"],["Moreno, Gabriel"],["Baldwin, Brooks"],["Edman, Tommy"],["Adell, Jo"],["Thomas, Alek"],["Narváez, Carlos"],["Burleson, Alec"],["Neto, Zach"],["Taveras, Leody"],["Pham, Tommy"],["Lopez, Otto"],["Walls, Taylor"],["Paris, Kyren"],["Naylor, Bo"],["Urías, Luis"],["Jones, Nolan"],["Morel, Christopher"],["Acuña, Luisangel"],["Isbel, Kyle"],["Lee, Brooks"],["Kjerstad, Heston"],["Pagés, Pedro"],["Sánchez, Jesús"],["Caballero, José"],["Young, Jacob"],["Martínez, Angel"],["Mervis, Matt"],["Call, Alex"],["White, Eli"],["Moore, Dylan"],["Chisholm Jr., Jazz"],["Waters, Drew"],["Verdugo, Alex"],["Jansen, Danny"],["Kelly, Carson"],["Murphy, Sean"],["Schneemann, Daniel"],["Tellez, Rowdy"],["Cabrera, Oswaldo"],["Alvarez, Yordan"],["Trout, Mike"],["Williamson, Ben"],["Castro, Willi"],["Durbin, Caleb"],["Hernández, Enrique"],["Díaz, Elias"],["Sanoja, Javier"],["Fitzgerald, Tyler"],["Norby, Connor"],["Casas, Triston"],["Iglesias, Jose"],["Urías, Ramón"],["Marte, Ketel"],["Meidroth, Chase"],["Ramírez, Agustín"],["Simpson, Chandler"],["Lukes, Nathan"],["Laureano, Ramón"]],"fillcolor":"rgba(255,255,255,0)","hoveron":"points","hovertemplate":"metric=wOBA\u003cbr\u003eMetric - Expected Metric=%{x}\u003cbr\u003elast_name, first_name=%{customdata[0]}\u003cextra\u003e\u003c\u002fextra\u003e","jitter":0,"legendgroup":"wOBA","line":{"color":"rgba(255,255,255,0)"},"marker":{"color":"#00cc96","symbol":"line-ns-open"},"name":"wOBA","showlegend":false,"x":{"dtype":"f8","bdata":"\u002fKnx0k1icL9\u002fHoXrUbiOv7gehetRuI6\u002fPWQ730+Nl7\u002frfmq8dJOov\u002fyp8dJNYmA\u002fzfl+arx0o7+4HoXrUbiOPx20yHa+n5q\u002fukkMAiuHlr9MZDvfT42nv3sUrkfhepS\u002f7FG4HoXroT\u002f6fmq8dJNovwrXo3A9Cqc\u002fGQRWDi2ynb+4HoXrUbiOv\u002fyp8dJNYlC\u002fjcQgsHJoob\u002fTTWIQWDm0vySHFtnO97O\u002fLd9PjZduor\u002f8qfHSTWKAv3sUrkfheqS\u002fGQRWDi2ynb\u002fN+X5qvHSjP91RuB6F66E\u002f\u002fKnx0k1ikD8ZBFYOLbKdv38ehetRuI4\u002fP+kmMQisjL8bL90kBoGlP5zEILByaJG\u002f+n5qvHSTaD99bOf7qfGiP7gehetRuI4\u002f7FG4HoXrob+6SQwCK4eGv7pJDAIrh5a\u002fE35qvHSTaD8dtMh2vp+av0w3iUFg5aA\u002f2\u002fl+arx0k7+Hfmq8dJN4P7pJDAIrh4a\u002fO99PjZdugj8AAAAAAAAAABsv3SQGgZW\u002f+n5qvHSTaD\u002fdfmq8dJOYP5sehetRuJ6\u002fP+kmMQisjL85tMh2vp+av5qZmZmZmZm\u002fXLx0kxgEpr9sFK5H4Xqkv1pkO99PjZc\u002f\u002fKnx0k1ikL9q6SYxCKysv3\u002fEILByaJG\u002fPWQ730+Nl7+DwMqhRbazv\u002fyp8dJNYnC\u002fHbTIdr6fmr9cvHSTGASmv2wUrkfheqQ\u002f\u002fKnx0k1iYL+6SQwCK4eGP\u002fyp8dJNYmC\u002fukkMAiuHlj\u002f6fmq8dJOYP4ts5\u002fup8aK\u002f\u002fANWDi2ynb\u002f8qfHSTWJQP3npJjEIrHw\u002fexSuR+F6hD+LbOf7qfGivwwv3SQGgaU\u002fo\u002fHSTWIQuL956SYxCKyMv8uhRbbz\u002faS\u002f\u002fi7dJAaBlb\u002f81qNwPQqnv3sUrkfhenQ\u002fqvHSTWIQqL+cxCCwcmihP\u002fp+arx0k3i\u002fuB6F61G4nj\u002fCqfHSTWKAP\u002fyp8dJNYnC\u002f\u002fKnx0k1iYL+6SQwCK4e2v7gehetRuJ6\u002fOwwCK4cWqb+cxCCwcmixv5zEILByaJE\u002feekmMQisfD85tMh2vp+KP\u002fyp8dJNYmA\u002fK4cW2c73oz9BFK5H4XqEP2rpJjEIrKy\u002f2\u002fl+arx0k7+4HoXrUbievwisHFpkO6+\u002fH99PjZdukr+LbOf7qfGiv\u002fyp8dJNYnC\u002f\u002fKnx0k1iUD9aZDvfT42nv\u002fyp8dJNYpC\u002fObTIdr6fmj956SYxCKyMv3sUrkfheoS\u002f+n5qvHSTaL\u002f8qfHSTWJwv\u002fyp8dJNYoC\u002fnMQgsHJokT97FK5H4XqUPwC0yHa+n4o\u002f\u002fKnx0k1iUL9MZDvfT42nv7pJDAIrh4a\u002faukmMQisrL8rtMh2vp+qv835fmq8dKO\u002f+n5qvHSTaL\u002fb+X5qvHSTvz1kO99PjZe\u002fe0Fg5dAiq7956SYxCKycv\u002fp+arx0k5i\u002fmx6F61G4nj9YObTIdr6fP7pJDAIrh5a\u002fe0Fg5dAiq7+cxCCwcmixv+2p8dJNYqC\u002fDC\u002fdJAaBpb9MN4lBYOWwv3\u002fEILByaJE\u002f\u002fKnx0k1iYL+kcD0K16Owv8B+arx0k4i\u002fCKwcWmQ7r797FK5H4XqUv0EUrkfheoQ\u002fGy\u002fdJAaBpT+6SQwCK4eGP0xkO99Pjae\u002fukkMAiuHhr+6dr6fGi+tv\u002fyp8dJNYoA\u002f+n5qvHSTaD9q6SYxCKysv\u002fyp8dJNYmA\u002fnMQgsHJokT97FK5H4Xp0v\u002fp+arx0k3i\u002fXOkmMQisnD\u002ffqfHSTWKQP\u002fwDVg4tsp2\u002fukkMAiuHlr956SYxCKyMP4FJDAIrh4Y\u002f\u002fKnx0k1ikD\u002f+Lt0kBoGVP0w3iUFg5aC\u002f\u002fNajcD0Kpz8AtMh2vp+KvwC0yHa+n4q\u002fi5mZmZmZqT\u002f6fmq8dJNov3sUrkfhepS\u002fexSuR+F6pD8730+Nl26SP7gehetRuJ6\u002faukmMQisrL9c6SYxCKycv9nO91PjpZs\u002fukkMAiuHlr+cxCCwcmiRP8Kp8dJNYoC\u002fmx6F61G4nj+sSQwCK4emvxtcj8L1KKw\u002fHbTIdr6fmr97FK5H4Xp0P775fmq8dJM\u002fTDeJQWDlsL+6dr6fGi+tv7gehetRuI4\u002fGy\u002fdJAaBlb\u002f6fmq8dJN4v1zpJjEIrJy\u002fG1yPwvUorL8IrBxaZDuvv3sUrkfhenQ\u002fukkMAiuHlj8730+Nl26SP1pkO99PjZe\u002f2c73U+Olmz99mZmZmZmZvySHFtnO97O\u002fmpmZmZmZmb956SYxCKyMP\u002fyp8dJNYnC\u002f3X5qvHSTmD8rhxbZzvezvz03iUFg5aC\u002fwqnx0k1igL8KBFYOLbKtP9nO91PjpZu\u002fe0Fg5dAiq797FK5H4XqEP9smMQisHKq\u002fOzm0yHa+nz8t30+Nl26iv2wUrkfheqQ\u002fbBSuR+F6pD89ZDvfT42XP\u002fyp8dJNYoA\u002f\u002fKnx0k1ikD8bL90kBoGVv91RuB6F66E\u002fi2zn+6nxor\u002fb+X5qvHSTv91RuB6F66E\u002fHbTIdr6fmj\u002f8qfHSTWJwv1y8dJMYBKa\u002f+n5qvHSTaD+79Shcj8K1v5zEILByaLG\u002f+n5qvHSTmL\u002f8qfHSTWKAPxsv3SQGgZW\u002f\u002fKnx0k1ikL9\u002fxCCwcmiRP7pJDAIrh4a\u002fCgRWDi2yrT+cxCCwcmiRPzsMAiuHFqm\u002fAAAAAAAAAAD8qfHSTWJgPwgUrkfhenS\u002fmx6F61G4nj\u002f6fmq8dJOIPzm0yHa+n4q\u002f\u002fKnx0k1icL+6SQwCK4eGPw=="},"xaxis":"x2","yaxis":"y2","type":"box"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"Metric - Expected Metric"}},"yaxis":{"anchor":"x","domain":[0.0,0.7326],"title":{"text":"count"}},"xaxis2":{"anchor":"y2","domain":[0.0,1.0],"matches":"x","showticklabels":false,"showgrid":true},"yaxis2":{"anchor":"x2","domain":[0.7426,1.0],"matches":"y2","showticklabels":false,"showline":false,"ticks":"","showgrid":false},"legend":{"title":{"text":"metric"},"tracegroupgap":0},"title":{"text":"Distribution of xBA, xSLG, and xwOBA Differences"},"barmode":"relative"},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('03921ba4-61bf-4f27-83e1-43c0afcf710b');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
</div>
<p>Observe the histogram above that combines xBA, <a href="https://www.mlb.com/glossary/statcast/expected-slugging-percentage">expected slugging (xSLG)</a>, and xwOBA. Among xBA, xSLG, and xwOBA, xSLG shows the greated spread in difference values. This is likely a result of how SLG assign weights to hits. Specifically, SLG is defined as (1B + 2Bx2 + 3Bx3 + HRx4)/AB. Unlike, wOBA, slugging weights are fixed and higher-valued. Hence, a batted ball that does not result in its expected outcome faces a greater difference penalty.</p>
<p>Who’s that unlucky slugger to the very left? That’s Royals veteran Salvador Perez.</p>
<iframe src="https://streamable.com/m/salvador-perez-flies-out-sharply-to-center-fielder-harrison-bader-bfpeh6?partnerId=web_video-playback-page_video-share" width="560" height="315">
</iframe>
<p>That ball had a 97% hit probability and would have been a homerun in 9/30 ballparks.</p>
<p>Salvador Pérez’s recent flyout underscores the value of integrating ballpark- and weather-specific factors into our expected-stat models. Although current metrics leverage historical launch-angle and exit-velocity data to predict outcomes, they omit critical dimensions—namely batted-ball trajectory, precise horizontal launch direction, and wind conditions. In Pérez’s case, a strong tailwind or a gust toward the wall might readily have turned that routine out into a home run. That said, Statcast remains an extraordinary tool for quantifying the game, and enriching it with environmental and park-design variables promises even deeper insights into batted-ball performance.</p>
<p>Thanks for reading!</p>
<script async="" data-uid="5d16db9e50" src="https://runningonnumbers.kit.com/5d16db9e50/index.js"></script>


<!-- -->

</section>

 ]]></description>
  <category>python</category>
  <category>analysis</category>
  <category>MLB</category>
  <guid>https://runningonnumbers.com/posts/lucky-hitters/</guid>
  <pubDate>Fri, 23 May 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/lucky-hitters/baseball-clover-cartoon.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>State of the Dodgers: Dominant Start or Warning Signs Under the Surface? (Mid May 2025 Check-in)</title>
  <dc:creator>Oliver Chang</dc:creator>
  <link>https://runningonnumbers.com/posts/dodgers-may25/</link>
  <description><![CDATA[ 





<div id="6f853c3c" class="cell" data-execution_count="1">
<details class="code-fold">
<summary>Code</summary>
<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="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-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.express <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> px</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> helper <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> process_baseball_data</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> plotly.graph_objects <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> go</span>
<span id="cb1-5"></span>
<span id="cb1-6">REFERENCE_YEAR <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;">2025</span></span></code></pre></div>
</details>
</div>
<p>The Dodgers, defending World Series champs, entered 2025 with sky-high expectations. How are they measuring up about 33 games in?</p>
<p>As of early May, they boast a stellar 27-14 (.659) record, sitting atop the NL West with a 1-game lead over the Padres. They’re recently split a 4-game series against the Arizona Diamondbacks. The Dbacks could very well be a play-off opponent. A series split, coupled with a sub-0.500 record against winning teams, could orchestrate a rivertting play-off scene.</p>
<table class="caption-top table">
<caption>NL West Standings</caption>
<thead>
<tr class="header">
<th>Team</th>
<th>W</th>
<th>L</th>
<th>PCT</th>
<th>L10</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Dodgers</td>
<td>27</td>
<td>14</td>
<td>0.659</td>
<td>6-4</td>
</tr>
<tr class="even">
<td>Padres</td>
<td>25</td>
<td>14</td>
<td>0.641</td>
<td>7-3</td>
</tr>
<tr class="odd">
<td>Giants</td>
<td>24</td>
<td>18</td>
<td>0.571</td>
<td>5-5</td>
</tr>
<tr class="even">
<td>Diamondbacks</td>
<td>22</td>
<td>20</td>
<td>0.524</td>
<td>5-5</td>
</tr>
<tr class="odd">
<td>Rockies</td>
<td>7</td>
<td>34</td>
<td>0.171</td>
<td>1-9</td>
</tr>
</tbody>
</table>
<section id="offense-comparison" class="level1">
<h1>Offense Comparison</h1>
<p>They surpass their record from one year ago today, where they were 27-14 and 41 games into the season. Let’s see how their expected wOBA fares from last year.</p>
<div class="cell" data-execution_count="2">
<details class="code-fold">
<summary>Code</summary>
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># data load and prep</span></span>
<span id="cb2-2">xwoba_2025 <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/team-xwoba-2025.csv"</span></span>
<span id="cb2-3">xwoba_2024 <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/team-xwoba-2024.csv"</span></span>
<span id="cb2-4">df_2025 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> process_baseball_data(xwoba_2025, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2025</span>, end_date_str<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;">"2025-05-03"</span>)</span>
<span id="cb2-5">df_2024 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> process_baseball_data(xwoba_2024, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2024</span>, end_date_str<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;">"2024-05-03"</span>)</span>
<span id="cb2-6"></span>
<span id="cb2-7">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.concat([df_2025, df_2024], ignore_index<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="cb2-8">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Plot Date"</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;">'Game Date'</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">apply</span>(</span>
<span id="cb2-9">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> dt: pd.Timestamp(year<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>REFERENCE_YEAR, month<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>dt.month, day<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>dt.day)</span>
<span id="cb2-10">)</span>
<span id="cb2-11">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Year"</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;">"Game Date"</span>].dt.year</span>
<span id="cb2-12">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.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;">"Plot Date"</span>)</span>
<span id="cb2-13"></span>
<span id="cb2-14">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> px.line(df, 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;">"Plot Date"</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;">"Rolling XWOBA"</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;">"Year"</span>, markers<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="cb2-15">    color_discrete_sequence<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;">'blue'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'orange'</span>])</span>
<span id="cb2-16"></span>
<span id="cb2-17">league_average_xwoba_2025 <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.326</span></span>
<span id="cb2-18">fig.add_hline(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>league_average_xwoba_2025,</span>
<span id="cb2-19">    line_dash<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;">"dash"</span>,</span>
<span id="cb2-20">    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;">"red"</span>,</span>
<span id="cb2-21">    annotation_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"2025 MLB Avg XWOBA (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>league_average_xwoba_2025<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="cb2-22">    annotation_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;">"bottom right"</span>)</span>
<span id="cb2-23"></span>
<span id="cb2-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Update layout and legend</span></span>
<span id="cb2-25">fig.update_layout(</span>
<span id="cb2-26">    xaxis_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;">'Game Date'</span>,</span>
<span id="cb2-27">    yaxis_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;">'Rolling XWOBA'</span>,</span>
<span id="cb2-28">    hovermode<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;">'x unified'</span>,</span>
<span id="cb2-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;">"Dodgers xwOBA (2024 vs 2025)"</span></span>
<span id="cb2-30">)</span>
<span id="cb2-31"></span>
<span id="cb2-32">fig.show()</span></code></pre></div>
</details>
<div id="fig-team-xwoba" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="2">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-team-xwoba-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div id="fig-team-xwoba-1" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-subfloat-fig figure">
<div aria-describedby="fig-team-xwoba-1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
        <script type="text/javascript">
        window.PlotlyConfig = {MathJaxConfig: 'local'};
        if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}
        </script>
        <script type="module">import "https://cdn.plot.ly/plotly-3.0.1.min"</script>
        
</div>
<figcaption class="quarto-float-caption-bottom quarto-subfloat-caption quarto-subfloat-fig" id="fig-team-xwoba-1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
(a) Team XWOBA
</figcaption>
</figure>
</div>
<div id="fig-team-xwoba-2" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-subfloat-fig figure">
<div aria-describedby="fig-team-xwoba-2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="bd344aea-2c86-424e-965a-bb278f8f2b88" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("bd344aea-2c86-424e-965a-bb278f8f2b88")) {                    Plotly.newPlot(                        "bd344aea-2c86-424e-965a-bb278f8f2b88",                        [{"hovertemplate":"Year=2025\u003cbr\u003ePlot Date=%{x}\u003cbr\u003eRolling XWOBA=%{y}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"2025","line":{"color":"blue","dash":"solid"},"marker":{"symbol":"circle"},"mode":"lines+markers","name":"2025","orientation":"v","showlegend":true,"x":["2025-03-27T00:00:00","2025-03-28T00:00:00","2025-03-29T00:00:00","2025-03-31T00:00:00","2025-04-01T00:00:00","2025-04-02T00:00:00","2025-04-04T00:00:00","2025-04-05T00:00:00","2025-04-06T00:00:00","2025-04-07T00:00:00","2025-04-08T00:00:00","2025-04-09T00:00:00","2025-04-11T00:00:00","2025-04-12T00:00:00","2025-04-13T00:00:00","2025-04-14T00:00:00","2025-04-15T00:00:00","2025-04-16T00:00:00","2025-04-18T00:00:00","2025-04-19T00:00:00","2025-04-20T00:00:00","2025-04-22T00:00:00","2025-04-23T00:00:00","2025-04-25T00:00:00","2025-04-26T00:00:00","2025-04-27T00:00:00","2025-04-28T00:00:00","2025-04-29T00:00:00","2025-04-30T00:00:00","2025-05-02T00:00:00","2025-05-03T00:00:00"],"xaxis":"x","y":{"dtype":"f8","bdata":"QmDl0CLb2T+yne+nxkvXP3zNhaQpFdc\u002f9ihcj8L12D9SSZ2AJsLWP2kDnTbQadc\u002fDTn32QXE1j+38\u002f3UeOnWPxL9nayWN9Y\u002fvqtfa\u002fNA1j92RMI4OuvUP2cjVddgX9Y\u002fcfr4R55p1T\u002fQ6w6nj3\u002fUP9+SniZ0GdM\u002fH8j84L0l1T9yJYBedzjVPxr4ENIWltU\u002fISpQSobf1D95YwQT\u002fZ3UP8Wm0pBzn9U\u002fYByddcrk1j\u002fDptKQc5\u002fVP9V46SYxCNQ\u002fJvo7WS1v1D8b7MuVAHrVP7u3pKcJXdY\u002f\u002fp2sljdG2D\u002f4ENIWlr3YP1J1DfblStg\u002f7\u002fYcF1Os2T8="},"yaxis":"y","type":"scatter"},{"hovertemplate":"Year=2024\u003cbr\u003ePlot Date=%{x}\u003cbr\u003eRolling XWOBA=%{y}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"2024","line":{"color":"orange","dash":"solid"},"marker":{"symbol":"circle"},"mode":"lines+markers","name":"2024","orientation":"v","showlegend":true,"x":["2025-03-28T00:00:00","2025-03-29T00:00:00","2025-03-30T00:00:00","2025-03-31T00:00:00","2025-04-01T00:00:00","2025-04-02T00:00:00","2025-04-03T00:00:00","2025-04-05T00:00:00","2025-04-06T00:00:00","2025-04-07T00:00:00","2025-04-08T00:00:00","2025-04-09T00:00:00","2025-04-10T00:00:00","2025-04-12T00:00:00","2025-04-13T00:00:00","2025-04-14T00:00:00","2025-04-15T00:00:00","2025-04-16T00:00:00","2025-04-17T00:00:00","2025-04-19T00:00:00","2025-04-20T00:00:00","2025-04-21T00:00:00","2025-04-23T00:00:00","2025-04-24T00:00:00","2025-04-25T00:00:00","2025-04-26T00:00:00","2025-04-27T00:00:00","2025-04-28T00:00:00","2025-04-29T00:00:00","2025-04-30T00:00:00","2025-05-01T00:00:00","2025-05-03T00:00:00"],"xaxis":"x","y":{"dtype":"f8","bdata":"JQaBlUOL1D86tMh2vp\u002fSP5HtfD81XtI\u002f0SLb+X5q1D++MJkqGJXUP7sC5F5zIdU\u002fcAY+hLSF1T9pQpexIxLWP7\u002fiK77iK9Y\u002fZ1ohKlBK1j9xdNYpk1vVP3H6+EeeadU\u002fJYyjs06Z1D\u002fQZeyIhHHUP9GcuNtzXNQ\u002fISpQSobf1D8o7vYcF1PUP8j84L0lPdU\u002f0C4gNpWG1D91GTsiYRzVP3UZOyJhHNU\u002fyIID3DBL1T\u002fCODrrlMnVP60cWmQ739c\u002fCSb6O1kt1z9NblWUT9DYP6N8gkbtv9g\u002f\u002fSPPtEJU2D\u002f4ENIWlr3YP6nx0k1iENg\u002fA5kfvLek1z+1yHa+nxrXPw=="},"yaxis":"y","type":"scatter"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"Game Date"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"Rolling XWOBA"}},"legend":{"title":{"text":"Year"},"tracegroupgap":0},"shapes":[{"line":{"color":"red","dash":"dash"},"type":"line","x0":0,"x1":1,"xref":"x domain","y0":0.326,"y1":0.326,"yref":"y"}],"annotations":[{"showarrow":false,"text":"2025 MLB Avg XWOBA (0.326)","x":1,"xanchor":"right","xref":"x domain","y":0.326,"yanchor":"top","yref":"y"}],"hovermode":"x unified","title":{"text":"Dodgers xwOBA (2024 vs 2025)"}},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('bd344aea-2c86-424e-965a-bb278f8f2b88');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-subfloat-caption quarto-subfloat-fig" id="fig-team-xwoba-2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
(b)
</figcaption>
</figure>
</div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig quarto-uncaptioned" id="fig-team-xwoba-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1
</figcaption>
</figure>
</div>
</div>
<p>A hot start for the Dodgers! Figure&nbsp;1 illustrates the Dodgers’ team rolling xwOBA from the start of the season throughout mid May for both 2024 and 2025.</p>
<p>We can see that the 2025 Dodgers started the season significantly hotter offensively compared to 2024, based on expected wOBA. However, their performance has dipped recently, bringing their rolling xwOBA closer to their 2024 levels around the same point in the season. Both years show the Dodgers performing well above the 2025 league average xwOBA.</p>
<p>Will the rest of 2025 look like 2024?</p>
<div id="cell-fig-team-xwoba2024" class="cell" data-execution_count="3">
<details class="code-fold">
<summary>Code</summary>
<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># data load and prep</span></span>
<span id="cb3-2">xwoba_2025 <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/team-xwoba-2025.csv"</span></span>
<span id="cb3-3">xwoba_2024 <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/team-xwoba-2024.csv"</span></span>
<span id="cb3-4">df_2025 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> process_baseball_data(xwoba_2025, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2025</span>, end_date_str<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;">"2025-05-03"</span>)</span>
<span id="cb3-5">df_2024 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> process_baseball_data(xwoba_2024, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2024</span>, end_date_str<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;">"2024-10-01"</span>)</span>
<span id="cb3-6"></span>
<span id="cb3-7">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.concat([df_2025, df_2024], ignore_index<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="cb3-8">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Plot Date"</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;">'Game Date'</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">apply</span>(</span>
<span id="cb3-9">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">lambda</span> dt: pd.Timestamp(year<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>REFERENCE_YEAR, month<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>dt.month, day<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>dt.day)</span>
<span id="cb3-10">)</span>
<span id="cb3-11">df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Year"</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;">"Game Date"</span>].dt.year</span>
<span id="cb3-12">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.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;">"Plot Date"</span>)</span>
<span id="cb3-13"></span>
<span id="cb3-14">fig <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> px.line(df, 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;">"Plot Date"</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;">"Rolling XWOBA"</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;">"Year"</span>, markers<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="cb3-15">    color_discrete_sequence<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;">'blue'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'orange'</span>])</span>
<span id="cb3-16"></span>
<span id="cb3-17">league_average_xwoba_2024 <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.312</span></span>
<span id="cb3-18">fig.add_hline(y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>league_average_xwoba_2024,</span>
<span id="cb3-19">    line_dash<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;">"dash"</span>,</span>
<span id="cb3-20">    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;">"red"</span>,</span>
<span id="cb3-21">    annotation_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"2024 MLB Avg XWOBA (</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>league_average_xwoba_2024<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="cb3-22">    annotation_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;">"bottom right"</span>)</span>
<span id="cb3-23"></span>
<span id="cb3-24">fig.update_layout(</span>
<span id="cb3-25">    xaxis_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;">'Game Date'</span>,</span>
<span id="cb3-26">    yaxis_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;">'Rolling XWOBA'</span>,</span>
<span id="cb3-27">    hovermode<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;">'x unified'</span>,</span>
<span id="cb3-28">    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;">"Dodgers xwOBA (2024 vs 2025)"</span></span>
<span id="cb3-29">)</span>
<span id="cb3-30"></span>
<span id="cb3-31">fig.show()</span></code></pre></div>
</details>
<div id="fig-team-xwoba2024" class="cell-output cell-output-display quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-team-xwoba2024-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div>            <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_SVG"></script><script type="text/javascript">if (window.MathJax && window.MathJax.Hub && window.MathJax.Hub.Config) {window.MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}</script>                <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script charset="utf-8" src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>                <div id="71edf134-94e7-4f5a-8158-5ed04cb89614" class="plotly-graph-div" style="height:525px; width:100%;"></div>            <script type="text/javascript">                window.PLOTLYENV=window.PLOTLYENV || {};                                if (document.getElementById("71edf134-94e7-4f5a-8158-5ed04cb89614")) {                    Plotly.newPlot(                        "71edf134-94e7-4f5a-8158-5ed04cb89614",                        [{"hovertemplate":"Year=2025\u003cbr\u003ePlot Date=%{x}\u003cbr\u003eRolling XWOBA=%{y}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"2025","line":{"color":"blue","dash":"solid"},"marker":{"symbol":"circle"},"mode":"lines+markers","name":"2025","orientation":"v","showlegend":true,"x":["2025-03-27T00:00:00","2025-03-28T00:00:00","2025-03-29T00:00:00","2025-03-31T00:00:00","2025-04-01T00:00:00","2025-04-02T00:00:00","2025-04-04T00:00:00","2025-04-05T00:00:00","2025-04-06T00:00:00","2025-04-07T00:00:00","2025-04-08T00:00:00","2025-04-09T00:00:00","2025-04-11T00:00:00","2025-04-12T00:00:00","2025-04-13T00:00:00","2025-04-14T00:00:00","2025-04-15T00:00:00","2025-04-16T00:00:00","2025-04-18T00:00:00","2025-04-19T00:00:00","2025-04-20T00:00:00","2025-04-22T00:00:00","2025-04-23T00:00:00","2025-04-25T00:00:00","2025-04-26T00:00:00","2025-04-27T00:00:00","2025-04-28T00:00:00","2025-04-29T00:00:00","2025-04-30T00:00:00","2025-05-02T00:00:00","2025-05-03T00:00:00"],"xaxis":"x","y":{"dtype":"f8","bdata":"QmDl0CLb2T+yne+nxkvXP3zNhaQpFdc\u002f9ihcj8L12D9SSZ2AJsLWP2kDnTbQadc\u002fDTn32QXE1j+38\u002f3UeOnWPxL9nayWN9Y\u002fvqtfa\u002fNA1j92RMI4OuvUP2cjVddgX9Y\u002fcfr4R55p1T\u002fQ6w6nj3\u002fUP9+SniZ0GdM\u002fH8j84L0l1T9yJYBedzjVPxr4ENIWltU\u002fISpQSobf1D95YwQT\u002fZ3UP8Wm0pBzn9U\u002fYByddcrk1j\u002fDptKQc5\u002fVP9V46SYxCNQ\u002fJvo7WS1v1D8b7MuVAHrVP7u3pKcJXdY\u002f\u002fp2sljdG2D\u002f4ENIWlr3YP1J1DfblStg\u002f7\u002fYcF1Os2T8="},"yaxis":"y","type":"scatter"},{"hovertemplate":"Year=2024\u003cbr\u003ePlot Date=%{x}\u003cbr\u003eRolling XWOBA=%{y}\u003cextra\u003e\u003c\u002fextra\u003e","legendgroup":"2024","line":{"color":"orange","dash":"solid"},"marker":{"symbol":"circle"},"mode":"lines+markers","name":"2024","orientation":"v","showlegend":true,"x":["2025-03-28T00:00:00","2025-03-29T00:00:00","2025-03-30T00:00:00","2025-03-31T00:00:00","2025-04-01T00:00:00","2025-04-02T00:00:00","2025-04-03T00:00:00","2025-04-05T00:00:00","2025-04-06T00:00:00","2025-04-07T00:00:00","2025-04-08T00:00:00","2025-04-09T00:00:00","2025-04-10T00:00:00","2025-04-12T00:00:00","2025-04-13T00:00:00","2025-04-14T00:00:00","2025-04-15T00:00:00","2025-04-16T00:00:00","2025-04-17T00:00:00","2025-04-19T00:00:00","2025-04-20T00:00:00","2025-04-21T00:00:00","2025-04-23T00:00:00","2025-04-24T00:00:00","2025-04-25T00:00:00","2025-04-26T00:00:00","2025-04-27T00:00:00","2025-04-28T00:00:00","2025-04-29T00:00:00","2025-04-30T00:00:00","2025-05-01T00:00:00","2025-05-03T00:00:00","2025-05-04T00:00:00","2025-05-05T00:00:00","2025-05-06T00:00:00","2025-05-07T00:00:00","2025-05-08T00:00:00","2025-05-10T00:00:00","2025-05-11T00:00:00","2025-05-12T00:00:00","2025-05-13T00:00:00","2025-05-14T00:00:00","2025-05-15T00:00:00","2025-05-16T00:00:00","2025-05-17T00:00:00","2025-05-18T00:00:00","2025-05-19T00:00:00","2025-05-20T00:00:00","2025-05-21T00:00:00","2025-05-22T00:00:00","2025-05-24T00:00:00","2025-05-25T00:00:00","2025-05-26T00:00:00","2025-05-27T00:00:00","2025-05-28T00:00:00","2025-05-29T00:00:00","2025-05-31T00:00:00","2025-06-01T00:00:00","2025-06-02T00:00:00","2025-06-04T00:00:00","2025-06-05T00:00:00","2025-06-06T00:00:00","2025-06-07T00:00:00","2025-06-08T00:00:00","2025-06-09T00:00:00","2025-06-11T00:00:00","2025-06-12T00:00:00","2025-06-13T00:00:00","2025-06-14T00:00:00","2025-06-15T00:00:00","2025-06-16T00:00:00","2025-06-17T00:00:00","2025-06-18T00:00:00","2025-06-19T00:00:00","2025-06-20T00:00:00","2025-06-21T00:00:00","2025-06-22T00:00:00","2025-06-24T00:00:00","2025-06-25T00:00:00","2025-06-26T00:00:00","2025-06-28T00:00:00","2025-06-29T00:00:00","2025-06-30T00:00:00","2025-07-02T00:00:00","2025-07-03T00:00:00","2025-07-04T00:00:00","2025-07-05T00:00:00","2025-07-06T00:00:00","2025-07-07T00:00:00","2025-07-09T00:00:00","2025-07-10T00:00:00","2025-07-11T00:00:00","2025-07-12T00:00:00","2025-07-13T00:00:00","2025-07-14T00:00:00","2025-07-19T00:00:00","2025-07-20T00:00:00","2025-07-21T00:00:00","2025-07-22T00:00:00","2025-07-23T00:00:00","2025-07-24T00:00:00","2025-07-25T00:00:00","2025-07-26T00:00:00","2025-07-27T00:00:00","2025-07-28T00:00:00","2025-07-30T00:00:00","2025-07-31T00:00:00","2025-08-02T00:00:00","2025-08-03T00:00:00","2025-08-04T00:00:00","2025-08-05T00:00:00","2025-08-06T00:00:00","2025-08-07T00:00:00","2025-08-09T00:00:00","2025-08-10T00:00:00","2025-08-11T00:00:00","2025-08-12T00:00:00","2025-08-13T00:00:00","2025-08-14T00:00:00","2025-08-15T00:00:00","2025-08-16T00:00:00","2025-08-17T00:00:00","2025-08-18T00:00:00","2025-08-19T00:00:00","2025-08-20T00:00:00","2025-08-21T00:00:00","2025-08-23T00:00:00","2025-08-24T00:00:00","2025-08-25T00:00:00","2025-08-27T00:00:00","2025-08-28T00:00:00","2025-08-29T00:00:00","2025-08-30T00:00:00","2025-08-31T00:00:00","2025-09-01T00:00:00","2025-09-02T00:00:00","2025-09-03T00:00:00","2025-09-04T00:00:00","2025-09-06T00:00:00","2025-09-07T00:00:00","2025-09-08T00:00:00","2025-09-09T00:00:00","2025-09-10T00:00:00","2025-09-11T00:00:00","2025-09-13T00:00:00","2025-09-14T00:00:00","2025-09-15T00:00:00","2025-09-16T00:00:00","2025-09-17T00:00:00","2025-09-18T00:00:00","2025-09-19T00:00:00","2025-09-20T00:00:00","2025-09-21T00:00:00","2025-09-22T00:00:00","2025-09-24T00:00:00","2025-09-25T00:00:00","2025-09-26T00:00:00","2025-09-27T00:00:00","2025-09-28T00:00:00","2025-09-29T00:00:00"],"xaxis":"x","y":{"dtype":"f8","bdata":"JQaBlUOL1D86tMh2vp\u002fSP5HtfD81XtI\u002f0SLb+X5q1D++MJkqGJXUP7sC5F5zIdU\u002fcAY+hLSF1T9pQpexIxLWP7\u002fiK77iK9Y\u002fZ1ohKlBK1j9xdNYpk1vVP3H6+EeeadU\u002fJYyjs06Z1D\u002fQZeyIhHHUP9GcuNtzXNQ\u002fISpQSobf1D8o7vYcF1PUP8j84L0lPdU\u002f0C4gNpWG1D91GTsiYRzVP3UZOyJhHNU\u002fyIID3DBL1T\u002fCODrrlMnVP60cWmQ739c\u002fCSb6O1kt1z9NblWUT9DYP6N8gkbtv9g\u002f\u002fSPPtEJU2D\u002f4ENIWlr3YP6nx0k1iENg\u002fA5kfvLek1z+1yHa+nxrXP69+rc0Dmdc\u002fqxxaZDvf1z\u002fvp8ZLN4nZP6DXHU4f\u002f9g\u002fnjK5VVE+2T8GgZVDi2zXP17GjkgYR9c\u002fexSuR+F61D\u002fTClGBUjLUPzFLvatfa9M\u002ficeCA9ww0z\u002frlMmtivLRPzEIrBxaZNM\u002fMnZEwjg60z+BlUOLbOfTP9JZp0xuVdQ\u002f4rHgADfM0j\u002fnPruA2FTSP9OELmNHJNQ\u002fO2Vyq6J80j\u002flVkX5BI3SPzrrlMmtitI\u002fQ0hbWPai0T+L5sTdnuPSPzYbqboG+9I\u002fl\u002fQ0ocvY0T\u002ffT42XbhLTP38z8CGkLdQ\u002fKOKx4AA31D9yMcWajVTVP8YUazZSddU\u002fFiglw28G1j\u002fDbwY+hLTVP7Kd76fGS9c\u002fs06Z3Koo1z+w7EVz4m7XP74lPU3oMtY\u002fxtFZp0xu1T\u002fIdr6fGi\u002fVP2lCl7EjEtY\u002fw+njH3mm1T\u002fFILByaJHVP7dt27Zt29Y\u002fY0ckjKOz1j8GxKbSkHPXP7nbc1xMsdY\u002fwgFumKXe1T8nMQisHFrUPzLFmo1UXdM\u002fjwUHuGGW0j+Kuz3HxRTTPzsWHOCGWdI\u002fMEu9q19r0z+FLmNHJIzTPyho1P4LRdQ\u002fGi\u002fdJAaB1T\u002fI\u002fOC9JT3VPyIeCw5ww9Q\u002fKKvljRFM1D\u002ffkp4mdBnTP4brUbgehdM\u002ffnYBsak01D8zdkTCODrTP+aNEUz0d9I\u002fgzqogzqo0z8jEsbRWafUP3aH08c\u002f8tQ\u002fHVpkO99P1T\u002fZEQnj6KzTP8+0QlSglNQ\u002f04QuY0ck1D8w0d\u002fJannTP41gor+T1dI\u002fP\u002fJMK0QF0j9NpSHnPrvQP+\u002fq19o8kNE\u002foNcdTh\u002f\u002f0D+bBzI\u002feG\u002fRPzvTClGBUtI\u002fkaprsC9X0j\u002fZzvdT46XTP3G357iYYtU\u002f0GXsiIRx1D92yuRWRfnUPxk7ImEcndU\u002fGnLuswuI1T\u002fBh5C2sOzVPxtmqXf1a9U\u002fz7RCVKCU1D94OH38I8\u002fUP3rd4fTxj9Q\u002fdZ9dQGwq1T949WttHsjUPya3KsonaNQ\u002fxpqNVF2D1T9wwyz1rn7VP8CT1fLGCNY\u002fFxCbSkPO1T9yMcWajVTVP3aH08c\u002f8tQ\u002fcD0K16Nw1T8Sg8DKoUXWP2v\u002fhSIeC9Y\u002ftrDsRXPi1j8QFSglw2\u002fWP8NjwQFumNU\u002fymp5YwQT1T8ndBk7ImHUP4kKlJLhN9M\u002fLTjADbPU0z\u002fbc1xMsWbTPyd0GTsiYdQ\u002ffvwjz7RC1D96V7\u002fW5oHUPx7I\u002fOC9JdU\u002fIxLG0Vmn1D\u002fTxz\u002fyTCvUP4Bedzh9\u002fNM\u002fyHa+nxov1T8NfAhpC8vWP7HgADfMUtc\u002fVssbI5jo1z9N9HeyWt7YP5ncqiifoNk\u002fRzDR38lq2T\u002f5iq\u002f4iq\u002fYP5s+\u002fpFnWtk\u002f\u002fheKeCw42D8="},"yaxis":"y","type":"scatter"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"},"margin":{"b":0,"l":0,"r":0,"t":30}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"Game Date"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"Rolling XWOBA"}},"legend":{"title":{"text":"Year"},"tracegroupgap":0},"shapes":[{"line":{"color":"red","dash":"dash"},"type":"line","x0":0,"x1":1,"xref":"x domain","y0":0.312,"y1":0.312,"yref":"y"}],"annotations":[{"showarrow":false,"text":"2024 MLB Avg XWOBA (0.312)","x":1,"xanchor":"right","xref":"x domain","y":0.312,"yanchor":"top","yref":"y"}],"hovermode":"x unified","title":{"text":"Dodgers xwOBA (2024 vs 2025)"}},                        {"responsive": true}                    ).then(function(){
                            
var gd = document.getElementById('71edf134-94e7-4f5a-8158-5ed04cb89614');
var x = new MutationObserver(function (mutations, observer) {{
        var display = window.getComputedStyle(gd).display;
        if (!display || display === 'none') {{
            console.log([gd, 'removed!']);
            Plotly.purge(gd);
            observer.disconnect();
        }}
}});

// Listen for the removal of the full notebook cells
var notebookContainer = gd.closest('#notebook-container');
if (notebookContainer) {{
    x.observe(notebookContainer, {childList: true});
}}

// Listen for the clearing of the current output cell
var outputEl = gd.closest('.output');
if (outputEl) {{
    x.observe(outputEl, {childList: true});
}}

                        })                };            </script>        </div>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-team-xwoba2024-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Team XWOBA 2024
</figcaption>
</figure>
</div>
</div>
<p>Let’s sure hope we do not witness another late-May struggle.</p>
</section>
<section id="shohei-ohtani" class="level1">
<h1>Shohei Ohtani</h1>
<p>While the team’s overall offensive performance has shown some regression towards 2024 levels, it’s important to look at individual player contributions. Let’s examine Shohei Ohtani’s rolling xwOBA as an example.</p>
<p><img src="https://runningonnumbers.com/posts/dodgers-may25/ohtani-rolling-xwoba.png" class="img-fluid"></p>
<p>I am hedging my bets that Ohtani will win NL MVP again. Observe that Ohtani exhibits cylical patterns in his rolling xwOBA.</p>
<p><img src="https://runningonnumbers.com/posts/dodgers-may25/ohtani-chart.png" class="img-fluid"></p>
<p>In 2021, Ohtani brandished an above 0.500 xwOBA during the summer months of the season. In 2021, writes a similar story to 2021 with the addition of a 1.0 OPS in August. Last year, a year unlike any other, Ohtani wins MVP, concluding his 2024 campaign with a 1.225 OPS in September and October.</p>
<p><em>Are we due for another Shohei Summer?</em></p>
<p>I rooting for it. However, with Ohtani pitching on the horizon after the all-star break, it will interesting to see how that will influence with offensive performance heading into the fall. 2023 Ohtani was as close as we will ever get to the most athletically impressive season in all of baseball. His batting slash line was .304/.412/.654 and boasted a 142 ERA+ on the season. Unfortunately, Ohtani had a season ending injury in his throwing elbow in 2023.</p>
<p>Is this symbolic of Icarsus’s Hubris? 2025, 2026, and 2027 will determine if Ohtani is Icarsus or a living God, standing among mere mortals. With only half a season of pitching, it is unkliekly Ohtani will garner any Cy Young votes. However, a full season of pitching, alongside a 1.0 OPS, will cement Ohtani as the greatest of all time.</p>


<!-- -->

</section>

 ]]></description>
  <category>python</category>
  <category>analysis</category>
  <category>Dodgers</category>
  <guid>https://runningonnumbers.com/posts/dodgers-may25/</guid>
  <pubDate>Mon, 12 May 2025 05:00:00 GMT</pubDate>
  <media:content url="https://runningonnumbers.com/posts/dodgers-may25/dodgers.jpg" medium="image" type="image/jpeg"/>
</item>
</channel>
</rss>
