<?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>Andrew Gard, Ph.D</title>
<link>https://equitableequations.com/posts.html</link>
<atom:link href="https://equitableequations.com/posts.xml" rel="self" type="application/rss+xml"/>
<description>Statistics and machine learning for everyone!</description>
<image>
<url>https://equitableequations.com/assets/me_contemplative_sm.jpg</url>
<title>Andrew Gard, Ph.D</title>
<link>https://equitableequations.com/posts.html</link>
</image>
<generator>quarto-1.7.32</generator>
<lastBuildDate>Mon, 12 Oct 2026 05:00:00 GMT</lastBuildDate>
<item>
  <title>Stabilizing regression coefficients with the lasso</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2026-10-12/</link>
  <description><![CDATA[ 




<p>Sometimes linear regression gives poor results even when the data comes from a linear relationship. I’ll explain why and then show you what you can do about it.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/hBqEECNP5mQ?si=tFJEWFTZhY-RGNAj" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p><button class="btn btn-default downloadthis  " id="dnldts5444"><i class="bi bi-download"></i> Download slides </button></p>



 ]]></description>
  <category>Machine learning</category>
  <guid>https://equitableequations.com/posts/2026-10-12/</guid>
  <pubDate>Mon, 12 Oct 2026 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2026-10-12/lasso thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Cross validation</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2026-10-05/</link>
  <description><![CDATA[ 




<iframe width="560" height="315" src="https://www.youtube.com/embed/U1LxW3DWn1M?si=itcYKAcIrBIkMQ0o" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p><button class="btn btn-default downloadthis  " id="dnldts17344"><i class="bi bi-download"></i> Download slides </button></p>



 ]]></description>
  <category>Machine learning</category>
  <guid>https://equitableequations.com/posts/2026-10-05/</guid>
  <pubDate>Mon, 05 Oct 2026 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2026-10-05/cross validation thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>How to tidymodels</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2026-09-21/</link>
  <description><![CDATA[ 




<div class="cell">
<div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tidymodels)</span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ISLR2) </span></code></pre></div>
</div>
<p>The <code>tidymodels</code> family of packages is a unified framework for machine learning in R. I recommend it for <em>predictive</em> modeling, where future performance is the primary benchmark for success. For descriptive modeling and statistical inference, <code>tidymodels</code> can be unwieldy.</p>
<p><img src="https://equitableequations.com/posts/2026-09-21/tidymodels_workflow.png" class="img-fluid"></p>
<p>When using data to estimate the future performance of a model, we always adhere to one essential core principle, which <code>tidymodels</code> works hard to enforce: <em>Never use the same data to both train and assess any model.</em></p>
<section id="the-college-data-set" class="level2">
<h2 class="anchored" data-anchor-id="the-college-data-set">The <code>College</code> data set</h2>
<p>Throughout this demonstration, I’ll use the <code>ISLR2::College</code> data set, which includes information about 777 US colleges in 1995. We’ll view <code>Outstate</code> tuition as the response variable, attempting to model it using the other variables in the set.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glimpse</span>(College)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Rows: 777
Columns: 18
$ Private     &lt;fct&gt; Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes…
$ Apps        &lt;dbl&gt; 1660, 2186, 1428, 417, 193, 587, 353, 1899, 1038, 582, 173…
$ Accept      &lt;dbl&gt; 1232, 1924, 1097, 349, 146, 479, 340, 1720, 839, 498, 1425…
$ Enroll      &lt;dbl&gt; 721, 512, 336, 137, 55, 158, 103, 489, 227, 172, 472, 484,…
$ Top10perc   &lt;dbl&gt; 23, 16, 22, 60, 16, 38, 17, 37, 30, 21, 37, 44, 38, 44, 23…
$ Top25perc   &lt;dbl&gt; 52, 29, 50, 89, 44, 62, 45, 68, 63, 44, 75, 77, 64, 73, 46…
$ F.Undergrad &lt;dbl&gt; 2885, 2683, 1036, 510, 249, 678, 416, 1594, 973, 799, 1830…
$ P.Undergrad &lt;dbl&gt; 537, 1227, 99, 63, 869, 41, 230, 32, 306, 78, 110, 44, 638…
$ Outstate    &lt;dbl&gt; 7440, 12280, 11250, 12960, 7560, 13500, 13290, 13868, 1559…
$ Room.Board  &lt;dbl&gt; 3300, 6450, 3750, 5450, 4120, 3335, 5720, 4826, 4400, 3380…
$ Books       &lt;dbl&gt; 450, 750, 400, 450, 800, 500, 500, 450, 300, 660, 500, 400…
$ Personal    &lt;dbl&gt; 2200, 1500, 1165, 875, 1500, 675, 1500, 850, 500, 1800, 60…
$ PhD         &lt;dbl&gt; 70, 29, 53, 92, 76, 67, 90, 89, 79, 40, 82, 73, 60, 79, 36…
$ Terminal    &lt;dbl&gt; 78, 30, 66, 97, 72, 73, 93, 100, 84, 41, 88, 91, 84, 87, 6…
$ S.F.Ratio   &lt;dbl&gt; 18.1, 12.2, 12.9, 7.7, 11.9, 9.4, 11.5, 13.7, 11.3, 11.5, …
$ perc.alumni &lt;dbl&gt; 12, 16, 30, 37, 2, 11, 26, 37, 23, 15, 31, 41, 21, 32, 26,…
$ Expend      &lt;dbl&gt; 7041, 10527, 8735, 19016, 10922, 9727, 8861, 11487, 11644,…
$ Grad.Rate   &lt;dbl&gt; 60, 56, 54, 59, 15, 55, 63, 73, 80, 52, 73, 76, 74, 68, 55…</code></pre>
</div>
</div>
</section>
<section id="splitting-the-data" class="level2">
<h2 class="anchored" data-anchor-id="splitting-the-data">Splitting the data</h2>
<p>The <code>rsample::initial_split()</code> function partitions a data set by randomly assigning rows (<code>prop = 3/4</code> is the default) to the training set and storing them, along with the full data frame, in a list (technically, an <code>rsplit</code> object).</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb4-2"></span>
<span id="cb4-3">split <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">initial_split</span>(College)</span>
<span id="cb4-4">split</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>&lt;Training/Testing/Total&gt;
&lt;582/195/777&gt;</code></pre>
</div>
<div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(split) </span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "data"   "in_id"  "out_id" "id"    </code></pre>
</div>
<div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1">split<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>in_id <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Training set row numbers</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] 398 679 129 509 471 299 270 187 307 597 277 494 330 591 725  37 105 729 485
[20] 677</code></pre>
</div>
</div>
<p><code>tidymodels</code> provides simple functions to extract both the training and testing sets.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1">train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">training</span>(split)</span>
<span id="cb10-2">test <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">testing</span>(split)</span>
<span id="cb10-3"></span>
<span id="cb10-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glimpse</span>(train) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 582 rows, ~75% of the original set</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Rows: 582
Columns: 18
$ Private     &lt;fct&gt; Yes, No, Yes, No, Yes, Yes, No, Yes, Yes, Yes, Yes, Yes, Y…
$ Apps        &lt;dbl&gt; 657, 1401, 344, 4216, 427, 2929, 8681, 1457, 1243, 2425, 4…
$ Accept      &lt;dbl&gt; 537, 1239, 264, 2290, 385, 1834, 6695, 1045, 947, 1818, 35…
$ Enroll      &lt;dbl&gt; 113, 605, 97, 736, 143, 622, 2408, 345, 324, 601, 913, 225…
$ Top10perc   &lt;dbl&gt; 37, 10, 11, 20, 18, 20, 10, 27, 50, 62, 13, 24, 25, 57, 42…
$ Top25perc   &lt;dbl&gt; 90, 34, 42, 52, 38, 56, 35, 50, 77, 93, 33, 42, 55, 81, 64…
$ F.Undergrad &lt;dbl&gt; 1039, 3716, 500, 4296, 581, 2738, 15701, 1109, 1129, 2110,…
$ P.Undergrad &lt;dbl&gt; 466, 675, 331, 1027, 533, 1662, 1823, 502, 74, 95, 1446, 2…
$ Outstate    &lt;dbl&gt; 12474, 7100, 12600, 5130, 12700, 12600, 7799, 14990, 17163…
$ Room.Board  &lt;dbl&gt; 5678, 4380, 5520, 4690, 5800, 5610, 3403, 4980, 3891, 5150…
$ Books       &lt;dbl&gt; 630, 540, 630, 600, 450, 450, 537, 450, 525, 500, 570, 600…
$ Personal    &lt;dbl&gt; 1278, 2948, 2250, 1450, 700, 3160, 2605, 550, 975, 490, 11…
$ PhD         &lt;dbl&gt; 53, 63, 77, 73, 81, 90, 77, 77, 76, 94, 66, 55, 94, 81, 91…
$ Terminal    &lt;dbl&gt; 71, 88, 80, 75, 85, 90, 84, 98, 92, 96, 83, 60, 95, 91, 91…
$ S.F.Ratio   &lt;dbl&gt; 11.9, 19.4, 10.4, 17.9, 10.3, 15.1, 21.0, 21.5, 10.1, 9.6,…
$ perc.alumni &lt;dbl&gt; 19, 0, 7, 18, 37, 9, 16, 21, 57, 20, 14, 19, 15, 41, 40, 3…
$ Expend      &lt;dbl&gt; 10613, 5389, 9773, 5125, 11758, 9084, 5569, 7502, 13965, 1…
$ Grad.Rate   &lt;dbl&gt; 72, 36, 43, 56, 84, 84, 54, 64, 77, 93, 66, 67, 65, 70, 86…</code></pre>
</div>
</div>
<p>We could also consider stratifying the split by the response variable. If the response is quantitative, as is the case here, <code>initial_split()</code> will automatically group it into quartiles.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">split <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">initial_split</span>(</span>
<span id="cb12-2">  College, </span>
<span id="cb12-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">strata =</span> Outstate</span>
<span id="cb12-4">  )</span></code></pre></div>
</div>
<p>We now leave the test set aside and build the model entirely using <code>train</code>.</p>
</section>
<section id="specifying-the-model" class="level2">
<h2 class="anchored" data-anchor-id="specifying-the-model">Specifying the model</h2>
<p><code>tidymodels</code> distinguishes between model <em>specification</em>, where we make choices about how the data will be modeled, and <em>fitting</em>, where training data is used to construct a concrete algorithm for making predictions.</p>
<p>If you’re used to base R modeling functions like <code>lm()</code>, this may feel awkward at first.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lm</span>(</span>
<span id="cb13-2">  Outstate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> Top10perc  <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> PhD, </span>
<span id="cb13-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> College</span>
<span id="cb13-4">  ) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># standard</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>
Call:
lm(formula = Outstate ~ Top10perc + PhD, data = College)

Coefficients:
(Intercept)    Top10perc          PhD  
    5202.71       114.05        28.83  </code></pre>
</div>
<div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">linear_reg</span>(</span>
<span id="cb15-2">  Outstate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> Top10perc  <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> PhD,</span>
<span id="cb15-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> College</span>
<span id="cb15-4">  ) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fails</span></span></code></pre></div>
<div class="cell-output cell-output-error">
<pre><code>Error in `linear_reg()`:
! unused argument (data = College)</code></pre>
</div>
</div>
<p>The <code>tidymodels</code> code to obtain regression coefficients is somewhat more verbose.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb17-1">my_lm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">linear_reg</span>() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># parsnip specification</span></span>
<span id="cb17-2"></span>
<span id="cb17-3">my_lm_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fit</span>(</span>
<span id="cb17-4">  my_lm,</span>
<span id="cb17-5">  Outstate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> Top10perc <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> PhD,</span>
<span id="cb17-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> College</span>
<span id="cb17-7">  ) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fit the model</span></span>
<span id="cb17-8"></span>
<span id="cb17-9">my_lm_fit</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>parsnip model object


Call:
stats::lm(formula = Outstate ~ Top10perc + PhD, data = data)

Coefficients:
(Intercept)    Top10perc          PhD  
    5202.71       114.05        28.83  </code></pre>
</div>
<div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb19-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tidy</span>(my_lm_fit) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># results as a tibble</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 3 × 5
  term        estimate std.error statistic  p.value
  &lt;chr&gt;          &lt;dbl&gt;     &lt;dbl&gt;     &lt;dbl&gt;    &lt;dbl&gt;
1 (Intercept)   5203.     553.        9.41 5.64e-20
2 Top10perc      114.       7.95     14.4  1.37e-41
3 PhD             28.8      8.59      3.36 8.23e- 4</code></pre>
</div>
</div>
<p>This is underwhelming because the model is so simple and the <code>lm()</code> syntax so familiar.</p>
<p>Let’s switch to a modestly more complicated <img src="https://latex.codecogs.com/png.latex?k">-nearest neighbor regression, where the closest points to a new observation are used to estimate an unknown response value. For this, we use <code>parsnip::nearest_neighbor()</code>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb21-1">my_knn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nearest_neighbor</span>(</span>
<span id="cb21-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mode =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"regression"</span>,</span>
<span id="cb21-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">engine =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"kknn"</span>,</span>
<span id="cb21-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">neighbors =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">27</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a reasonable first choice</span></span>
<span id="cb21-5">  )</span>
<span id="cb21-6"></span>
<span id="cb21-7">my_knn</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>K-Nearest Neighbor Model Specification (regression)

Main Arguments:
  neighbors = 27

Computational engine: kknn </code></pre>
</div>
</div>
<p>Fitting this model immediately would give sub-optimal results, however, as the data set is not yet in an appropriate form for knn regression.</p>
</section>
<section id="preprocessing" class="level2">
<h2 class="anchored" data-anchor-id="preprocessing">Preprocessing</h2>
<p>A <em>recipe</em>, as the name suggests, is a documented set of steps to be followed when any data (training, test, or otherwise) is handled by a model. Storing our steps in this way allows us to automate the process so that it be easily applied as needed.</p>
<p>Let’s create a simple recipe appropriate to a knn model.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb23-1">col_rec <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">recipe</span>(</span>
<span id="cb23-2">  Outstate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> ., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> train) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb23-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_dummy</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all_nominal_predictors</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb23-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_normalize</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all_numeric_predictors</span>())</span>
<span id="cb23-5"></span>
<span id="cb23-6">col_rec</span></code></pre></div>
<div class="cell-output cell-output-stderr">
<pre><code></code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>── Recipe ──────────────────────────────────────────────────────────────────────</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code></code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>── Inputs </code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>Number of variables by role</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>outcome:    1
predictor: 17</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code></code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>── Operations </code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>• Dummy variables from: all_nominal_predictors()</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>• Centering and scaling for: all_numeric_predictors()</code></pre>
</div>
</div>
<p>Preprocessing tools generally have the form <code>step_*()</code>. Most common techniques have built-in functions, including the two used above.</p>
<p>You may have noticed that some steps (including <code>step_normalize</code>) require input from the training set. Currently the recipe, which is just a set of instructions, has not performed any such computations. Use <code>prep()</code> to tell <code>tidymodels</code> to incorporate the training data into the recipe.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb34" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb34-1">rec_prepped <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prep</span>(col_rec)</span>
<span id="cb34-2">rec_prepped</span></code></pre></div>
<div class="cell-output cell-output-stderr">
<pre><code></code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>── Recipe ──────────────────────────────────────────────────────────────────────</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code></code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>── Inputs </code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>Number of variables by role</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>outcome:    1
predictor: 17</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code></code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>── Training information </code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>Training data contained 582 data points and no incomplete rows.</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code></code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>── Operations </code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>• Dummy variables from: Private | Trained</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>• Centering and scaling for: Apps, Accept, Enroll, Top10perc, ... | Trained</code></pre>
</div>
</div>
<p>Once the recipe is trained (prepped), it can be applied to any set with the correct column names, including <code>train</code> and <code>test</code>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb48" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb48-1">train_baked <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bake</span>(</span>
<span id="cb48-2">  rec_prepped,</span>
<span id="cb48-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">new_data =</span> train</span>
<span id="cb48-4">  )</span>
<span id="cb48-5"></span>
<span id="cb48-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glimpse</span>(train_baked)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Rows: 582
Columns: 18
$ Apps        &lt;dbl&gt; -0.584565901, -0.392108788, -0.665532402, 0.336072357, -0.…
$ Accept      &lt;dbl&gt; -0.59303713, -0.29578081, -0.70863680, 0.14925677, -0.6574…
$ Enroll      &lt;dbl&gt; -0.73007850, -0.16151757, -0.74856828, -0.01013245, -0.695…
$ Top10perc   &lt;dbl&gt; 0.53780784, -1.01427892, -0.95679422, -0.43943197, -0.5544…
$ Top25perc   &lt;dbl&gt; 1.718305395, -1.097897433, -0.695582743, -0.192689381, -0.…
$ F.Undergrad &lt;dbl&gt; -0.54793004, 0.03889871, -0.66608495, 0.16604129, -0.64832…
$ P.Undergrad &lt;dbl&gt; -0.25540460, -0.12116108, -0.34211693, 0.10493328, -0.2123…
$ Room.Board  &lt;dbl&gt; 1.1778784439, -0.0004757491, 1.0344424173, 0.2809493663, 1…
$ Books       &lt;dbl&gt; 0.45651909, -0.07400850, 0.45651909, 0.27967656, -0.604536…
$ Personal    &lt;dbl&gt; -0.08996942, 2.29903910, 1.30051937, 0.15608415, -0.916823…
$ PhD         &lt;dbl&gt; -1.21449875, -0.59630890, 0.26915688, 0.02188095, 0.516432…
$ Terminal    &lt;dbl&gt; -0.60448281, 0.56500349, 0.01465699, -0.32930956, 0.358623…
$ S.F.Ratio   &lt;dbl&gt; -0.54144438, 1.38707844, -0.92714895, 1.00137388, -0.95286…
$ perc.alumni &lt;dbl&gt; -0.30283014, -1.84957177, -1.27971959, -0.38423759, 1.1625…
$ Expend      &lt;dbl&gt; 0.164258830, -0.812840693, 0.007144818, -0.862219382, 0.37…
$ Grad.Rate   &lt;dbl&gt; 0.39369765, -1.70682518, -1.29839018, -0.53986805, 1.09387…
$ Outstate    &lt;dbl&gt; 12474, 7100, 12600, 5130, 12700, 12600, 7799, 14990, 17163…
$ Private_Yes &lt;dbl&gt; 0.5913933, -1.6880167, 0.5913933, -1.6880167, 0.5913933, 0…</code></pre>
</div>
</div>
<p>In general, you only need <code>prep()</code> and <code>bake()</code> if you want to explicitly see the transformed predictors. More typically, we just incorporate the preprocessor directly into a <code>tidymodels</code> workflow.</p>
</section>
<section id="creating-a-workflow" class="level2">
<h2 class="anchored" data-anchor-id="creating-a-workflow">Creating a workflow</h2>
<p>A <code>workflow</code> incorporates both a recipe and a model specification.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb50" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb50-1">knn_wf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">workflow</span>(</span>
<span id="cb50-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">spec =</span> my_knn,</span>
<span id="cb50-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">preprocessor =</span> col_rec,</span>
<span id="cb50-4">  )</span></code></pre></div>
</div>
<p>Often, you’ll see this step written using the pipe.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb51" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb51-1">knn_wf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">workflow</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb51-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add_recipe</span>(col_rec) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb51-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add_model</span>(my_knn) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># same as before</span></span></code></pre></div>
</div>
<p>Importantly, creating a <code>workflow</code> does <strong>not</strong> actually perform any preprocessing or model fitting.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb52" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb52-1">knn_wf</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>══ Workflow ════════════════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: nearest_neighbor()

── Preprocessor ────────────────────────────────────────────────────────────────
2 Recipe Steps

• step_dummy()
• step_normalize()

── Model ───────────────────────────────────────────────────────────────────────
K-Nearest Neighbor Model Specification (regression)

Main Arguments:
  neighbors = 27

Computational engine: kknn </code></pre>
</div>
</div>
<p>We can take this next step using the <code>fit()</code> function.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb54" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb54-1">knn_wf_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fit</span>(</span>
<span id="cb54-2">  knn_wf, </span>
<span id="cb54-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> train</span>
<span id="cb54-4">  )</span></code></pre></div>
</div>
<p>The model is now ready to use.</p>
</section>
<section id="putting-a-trained-workflow-into-action" class="level2">
<h2 class="anchored" data-anchor-id="putting-a-trained-workflow-into-action">Putting a trained workflow into action</h2>
<p>Use <code>predict()</code> to make predictions, duh. To start, we might just look at the training set, checking how far actual results are from the model’s predictions. The output is a tibble, not a vector.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb55" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb55-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(</span>
<span id="cb55-2">  knn_wf_fit, </span>
<span id="cb55-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">new_data =</span> train</span>
<span id="cb55-4">  )</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 582 × 1
    .pred
    &lt;dbl&gt;
 1 10953.
 2  6386.
 3 11191.
 4  6389.
 5 12944.
 6 12481.
 7  7213.
 8 12128.
 9 15024.
10 16666.
# ℹ 572 more rows</code></pre>
</div>
</div>
<p>Predictions made on the same data used to train the model will almost always be overly optimistic. It’s like when your mom tells you that you look nice.</p>
</section>
<section id="model-tuning-and-cross-validation" class="level2">
<h2 class="anchored" data-anchor-id="model-tuning-and-cross-validation">Model tuning and cross validation</h2>
<p>It’s unlikely that our choice of <img src="https://latex.codecogs.com/png.latex?k=27"> neighbors was optimal. <em>Model tuning</em> refers to the process of comparing a range of hyperparameter values and selecting the best one. <code>tidymodels</code> is built to facilitate this.</p>
<p>We start by specifying within our model that a hyperparameter needs to be tuned. We do this with the <code>tune()</code> placeholder.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb57" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb57-1">my_knn_cv <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nearest_neighbor</span>(</span>
<span id="cb57-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mode =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"regression"</span>,</span>
<span id="cb57-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">engine =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"kknn"</span>,</span>
<span id="cb57-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">neighbors =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tune</span>()</span>
<span id="cb57-5">  )</span>
<span id="cb57-6"></span>
<span id="cb57-7">knn_wf_cv <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">workflow</span>(</span>
<span id="cb57-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">preprocessor =</span> col_rec,</span>
<span id="cb57-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">spec =</span> my_knn_cv</span>
<span id="cb57-10">  )</span></code></pre></div>
</div>
<p>The most common way of comparing competing models during the tuning process is using <em>cross-validation</em>, where the training set is split into pieces (often <img src="https://latex.codecogs.com/png.latex?v=10">) of approximately equal size, called <em>folds</em>. The models are all then trained once per fold, with that one fold used as a holdout set while the others are used for training. The <img src="https://latex.codecogs.com/png.latex?v"> results are then averaged to give performance estimates for each of the competing models.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb58" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb58-1">folds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vfold_cv</span>(</span>
<span id="cb58-2">  train, </span>
<span id="cb58-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">v =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>,</span>
<span id="cb58-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">repeats =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># create folds</span></span>
<span id="cb58-5"></span>
<span id="cb58-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(folds)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 6 × 3
  splits           id      id2   
  &lt;list&gt;           &lt;chr&gt;   &lt;chr&gt; 
1 &lt;split [523/59]&gt; Repeat1 Fold01
2 &lt;split [523/59]&gt; Repeat1 Fold02
3 &lt;split [524/58]&gt; Repeat1 Fold03
4 &lt;split [524/58]&gt; Repeat1 Fold04
5 &lt;split [524/58]&gt; Repeat1 Fold05
6 &lt;split [524/58]&gt; Repeat1 Fold06</code></pre>
</div>
</div>
<p>The simplest tool to perform model fitting on cross-validation folds is <code>tune_grid()</code>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb60" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb60-1">tune_results <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tune_grid</span>(</span>
<span id="cb60-2">  knn_wf_cv,</span>
<span id="cb60-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">resamples =</span> folds</span>
<span id="cb60-4">  )</span></code></pre></div>
</div>
<p>This function operates by brute force using a default set of 10 values that make sense for the hyperparameter being tuned. You can tweak these values by passing new ones within a data frame.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb61" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb61-1">neighbors <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">11</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">33</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb61-2">knn_grid <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(neighbors)</span>
<span id="cb61-3">knn_grid</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>   neighbors
1         11
2         13
3         15
4         17
5         19
6         21
7         23
8         25
9         27
10        29
11        31
12        33</code></pre>
</div>
<div class="sourceCode cell-code" id="cb63" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb63-1">tune_results <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tune_grid</span>(</span>
<span id="cb63-2">  knn_wf_cv,</span>
<span id="cb63-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">resamples =</span> folds,</span>
<span id="cb63-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">grid =</span> knn_grid</span>
<span id="cb63-5">  )</span></code></pre></div>
</div>
<p>Another option for modifying the tuning grid is to use one of the dedicated functions from the <code>dials</code> package.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb64" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb64-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glimpse</span>(tune_results)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Rows: 50
Columns: 5
$ splits   &lt;list&gt; [&lt;vfold_split[523 x 59 x 582 x 18]&gt;], [&lt;vfold_split[523 x 59…
$ id       &lt;chr&gt; "Repeat1", "Repeat1", "Repeat1", "Repeat1", "Repeat1", "Repea…
$ id2      &lt;chr&gt; "Fold01", "Fold02", "Fold03", "Fold04", "Fold05", "Fold06", "…
$ .metrics &lt;list&gt; [&lt;tbl_df[24 x 5]&gt;], [&lt;tbl_df[24 x 5]&gt;], [&lt;tbl_df[24 x 5]&gt;], …
$ .notes   &lt;list&gt; [&lt;tbl_df[0 x 4]&gt;], [&lt;tbl_df[0 x 4]&gt;], [&lt;tbl_df[0 x 4]&gt;], [&lt;t…</code></pre>
</div>
</div>
<p>The result of <code>tune_grid()</code> is a mutated version of the output of <code>vfold_cv()</code> that includes new columns for <code>.metrics</code> and <code>.notes</code>.</p>
<p>Use <code>collect_metrics()</code> to compare performance across parameter values.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb66" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb66-1">tuning_metrics <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">collect_metrics</span>(tune_results)</span>
<span id="cb66-2">tuning_metrics</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 24 × 7
   neighbors .metric .estimator     mean     n  std_err .config         
       &lt;dbl&gt; &lt;chr&gt;   &lt;chr&gt;         &lt;dbl&gt; &lt;int&gt;    &lt;dbl&gt; &lt;chr&gt;           
 1        11 rmse    standard   1944.       50 30.6     pre0_mod01_post0
 2        11 rsq     standard      0.770    50  0.00895 pre0_mod01_post0
 3        13 rmse    standard   1927.       50 30.6     pre0_mod02_post0
 4        13 rsq     standard      0.774    50  0.00900 pre0_mod02_post0
 5        15 rmse    standard   1917.       50 30.7     pre0_mod03_post0
 6        15 rsq     standard      0.777    50  0.00905 pre0_mod03_post0
 7        17 rmse    standard   1910.       50 30.8     pre0_mod04_post0
 8        17 rsq     standard      0.778    50  0.00911 pre0_mod04_post0
 9        19 rmse    standard   1906.       50 30.8     pre0_mod05_post0
10        19 rsq     standard      0.780    50  0.00914 pre0_mod05_post0
# ℹ 14 more rows</code></pre>
</div>
</div>
<p>It’s often helpful to plot these results.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb68" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb68-1">tuning_metrics <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb68-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(.metric <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rmse"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb68-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> neighbors, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> mean)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb68-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_line</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb68-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb68-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>()</span></code></pre></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://equitableequations.com/posts/2026-09-21/index_files/figure-html/unnamed-chunk-23-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Use <code>show_best()</code> to automatically filter out sub-optimal rows from <code>tuning_metrics</code>. By default, the best 5 are shown, though this can be controlled with the optional <code>n</code> argument.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb69" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb69-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">show_best</span>(</span>
<span id="cb69-2">  tune_results,</span>
<span id="cb69-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">metric =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rmse"</span>,</span>
<span id="cb69-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span></span>
<span id="cb69-5">  ) </span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 7 × 7
  neighbors .metric .estimator  mean     n std_err .config         
      &lt;dbl&gt; &lt;chr&gt;   &lt;chr&gt;      &lt;dbl&gt; &lt;int&gt;   &lt;dbl&gt; &lt;chr&gt;           
1        23 rmse    standard   1904.    50    30.7 pre0_mod07_post0
2        21 rmse    standard   1904.    50    30.7 pre0_mod06_post0
3        25 rmse    standard   1905.    50    30.6 pre0_mod08_post0
4        19 rmse    standard   1906.    50    30.8 pre0_mod05_post0
5        27 rmse    standard   1907.    50    30.5 pre0_mod09_post0
6        29 rmse    standard   1909.    50    30.5 pre0_mod10_post0
7        17 rmse    standard   1910.    50    30.8 pre0_mod04_post0</code></pre>
</div>
</div>
<p>To automatically extract the result that minimizes rmse (or any other metric), use <code>select_best()</code>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb71" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb71-1">optimal_k <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select_best</span>(</span>
<span id="cb71-2">  tune_results,</span>
<span id="cb71-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">metric =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rmse"</span></span>
<span id="cb71-4">  )</span>
<span id="cb71-5"></span>
<span id="cb71-6">optimal_k <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 23 neighbors</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 1 × 2
  neighbors .config         
      &lt;dbl&gt; &lt;chr&gt;           
1        23 pre0_mod07_post0</code></pre>
</div>
</div>
<p><code>select_best()</code> has several friends, including <code>select_by_one_std_error()</code>, which chooses the least flexible model with performance comparable to the optimal one.</p>
<p>The output of <code>select_best()</code> can be fed back to the workflow being tuned with <code>finalize_workflow()</code>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb73" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb73-1">knn_wf_final <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">finalize_workflow</span>(</span>
<span id="cb73-2">  knn_wf_cv,</span>
<span id="cb73-3">  optimal_k</span>
<span id="cb73-4">  )</span>
<span id="cb73-5"></span>
<span id="cb73-6">knn_wf_final</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>══ Workflow ════════════════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: nearest_neighbor()

── Preprocessor ────────────────────────────────────────────────────────────────
2 Recipe Steps

• step_dummy()
• step_normalize()

── Model ───────────────────────────────────────────────────────────────────────
K-Nearest Neighbor Model Specification (regression)

Main Arguments:
  neighbors = 23

Computational engine: kknn </code></pre>
</div>
</div>
<p>The model is now fully specified and ready to be fit using the training set.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb75" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb75-1">knn_fit_final <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fit</span>(</span>
<span id="cb75-2">  knn_wf_final, </span>
<span id="cb75-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> train)</span></code></pre></div>
</div>
</section>
<section id="evaluation-using-the-test-set" class="level2">
<h2 class="anchored" data-anchor-id="evaluation-using-the-test-set">Evaluation using the test set</h2>
<p>Once we’ve finalized our model, we can use it to make predictions on new data. The <code>broom::augment()</code> function makes this information readily available in a data frame that includes all the variables relevant to the model.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb76" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb76-1">test_aug <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">augment</span>(</span>
<span id="cb76-2">  knn_fit_final, </span>
<span id="cb76-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">new_data =</span> test</span>
<span id="cb76-4">  )</span>
<span id="cb76-5"></span>
<span id="cb76-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glimpse</span>(test_aug)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Rows: 195
Columns: 20
$ .pred       &lt;dbl&gt; 13403.758, 8653.189, 14218.005, 11708.722, 13200.189, 9714…
$ .resid      &lt;dbl&gt; 2191.2416, 1814.8112, 2861.9951, -2018.7216, -628.1892, 14…
$ Private     &lt;fct&gt; Yes, Yes, Yes, Yes, Yes, Yes, No, No, Yes, Yes, No, Yes, Y…
$ Apps        &lt;dbl&gt; 1038, 582, 2652, 1179, 1267, 619, 12809, 1734, 1879, 2496,…
$ Accept      &lt;dbl&gt; 839, 498, 1900, 780, 1080, 516, 10308, 1729, 1658, 1402, 8…
$ Enroll      &lt;dbl&gt; 227, 172, 484, 290, 385, 219, 3761, 951, 497, 531, 546, 48…
$ Top10perc   &lt;dbl&gt; 30, 21, 44, 38, 44, 20, 24, 12, 36, 53, 12, 37, 11, 15, 20…
$ Top25perc   &lt;dbl&gt; 63, 44, 77, 64, 73, 51, 49, 52, 69, 95, 36, 68, 28, 55, 50…
$ F.Undergrad &lt;dbl&gt; 973, 799, 1707, 1130, 1306, 1251, 22593, 3602, 1950, 2121,…
$ P.Undergrad &lt;dbl&gt; 306, 78, 44, 638, 28, 767, 7585, 939, 38, 69, 824, 49, 74,…
$ Outstate    &lt;dbl&gt; 15595, 10468, 17080, 9690, 12572, 11208, 7434, 3460, 13353…
$ Room.Board  &lt;dbl&gt; 4400, 3380, 4440, 4785, 4552, 4124, 4850, 2650, 4173, 8124…
$ Books       &lt;dbl&gt; 300, 660, 400, 600, 400, 350, 700, 450, 540, 600, 660, 350…
$ Personal    &lt;dbl&gt; 500, 1800, 600, 1000, 400, 1615, 2100, 1000, 821, 850, 180…
$ PhD         &lt;dbl&gt; 79, 40, 73, 60, 79, 55, 88, 57, 78, 83, 57, 80, 63, 66, 76…
$ Terminal    &lt;dbl&gt; 84, 41, 91, 84, 87, 65, 93, 60, 83, 93, 62, 80, 63, 68, 71…
$ S.F.Ratio   &lt;dbl&gt; 11.3, 11.5, 9.9, 13.3, 15.3, 12.7, 18.9, 19.6, 12.7, 10.3,…
$ perc.alumni &lt;dbl&gt; 23, 15, 41, 21, 32, 25, 5, 5, 40, 33, 16, 17, 13, 19, 19, …
$ Expend      &lt;dbl&gt; 11644, 8991, 11711, 7940, 9305, 6584, 4602, 4739, 9220, 12…
$ Grad.Rate   &lt;dbl&gt; 80, 52, 76, 74, 68, 65, 48, 48, 71, 91, 46, 63, 35, 75, 58…</code></pre>
</div>
</div>
<p>The <code>yardstick</code> package, included in <code>tidymodels,</code> consists of functions which compute standard performance metrics, including root mean squared error.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb78" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb78-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rmse</span>(test_aug, </span>
<span id="cb78-2">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">truth =</span> Outstate,</span>
<span id="cb78-3">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">estimate =</span> .pred)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 1 × 3
  .metric .estimator .estimate
  &lt;chr&gt;   &lt;chr&gt;          &lt;dbl&gt;
1 rmse    standard       1904.</code></pre>
</div>
</div>
<p>You can compute multiple performance metrics at once by creating a <em>metric set</em>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb80" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb80-1">my_metrics <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">metric_set</span>(rmse, rsq)</span>
<span id="cb80-2"></span>
<span id="cb80-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">my_metrics</span>(</span>
<span id="cb80-4">  test_aug,</span>
<span id="cb80-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">truth =</span> Outstate, </span>
<span id="cb80-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">estimate =</span> .pred</span>
<span id="cb80-7">  )</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 2 × 3
  .metric .estimator .estimate
  &lt;chr&gt;   &lt;chr&gt;          &lt;dbl&gt;
1 rmse    standard    1904.   
2 rsq     standard       0.767</code></pre>
</div>
</div>
<p>The fact that these outputs are tibbles will be very convenient once we begin comparing various models.</p>
<p>If all you want to do is apply the trained model to the holdout set created with <code>initial_split()</code>, use <code>last_fit()</code>. To extract performance metrics from this object, use <code>collect_metrics()</code>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb82" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb82-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">last_fit</span>(knn_wf_final, split) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span id="cb82-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">collect_metrics</span>()</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 2 × 4
  .metric .estimator .estimate .config        
  &lt;chr&gt;   &lt;chr&gt;          &lt;dbl&gt; &lt;chr&gt;          
1 rmse    standard    1904.    pre0_mod0_post0
2 rsq     standard       0.767 pre0_mod0_post0</code></pre>
</div>
</div>
<p>On average, this model misses the true out-of-state tuition by about $1904.</p>
</section>
<section id="final-thought" class="level2">
<h2 class="anchored" data-anchor-id="final-thought">Final thought</h2>
<p>If you were expecting that learning <code>tidymodels</code> would be like learning <code>tidyverse</code>, you’re probably disappointed right about now. While you can practice <code>dplyr</code> without touching <code>ggplot2</code>, you can’t meaningfully do this with the individual <code>tidymodels</code> packages. This isn’t a design flaw in <code>tidymodels</code> but rather a fundamental challenge of the machine learning process, which is interconnected and complex by its very nature.</p>
<p>Overall, <code>tidymodels</code> is as about as simple as it can be while still doing what it does. Be patient with yourself, take multiple passes at the content, and you’ll get there sooner than you think.</p>
<p>Want to hear me explain all of this? Here’s the vid corresponding to this post:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/fRj8dr-aSsU?si=Sk6hpWQa70A98l6-" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p><button class="btn btn-default downloadthis  " id="dnldts43523"><i class="bi bi-download"></i> Download Quarto </button> <button class="btn btn-default downloadthis  " id="dnldts31328"><i class="bi bi-download"></i> Download html </button></p>


</section>

 ]]></description>
  <category>Machine learning</category>
  <category>tidymodels</category>
  <guid>https://equitableequations.com/posts/2026-09-21/</guid>
  <pubDate>Mon, 21 Sep 2026 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2026-09-21/tidymodels_thumb2.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Working with factors in R</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2026-09-07/</link>
  <description><![CDATA[ 




<p>Categorical variables (or <em>factors</em> as they are referred to when working in R) are variables that assign observations to specific groups. This post will cover some of the most common problems you may encounter while trying to visualize or model such variables.</p>
<p>Throughout, I’ll refer to the <code>scooby</code> data set, originally sourced from <a href="https://www.kaggle.com/datasets/thedevastator/the-unsolved-mysteries-of-scooby-doo">kaggle</a> but modified slightly for use in my vids and in this post. A download link can be found at the end of this tutorial.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Load and prep data</span></span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tidyverse)</span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_set</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>())</span>
<span id="cb1-5"></span>
<span id="cb1-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(readxl)</span>
<span id="cb1-7">scooby <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_excel</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"_internal/scooby.xlsx"</span>) </span>
<span id="cb1-8"></span>
<span id="cb1-9">scooby_sm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> scooby <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb1-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(format <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"TV Series"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span>  </span>
<span id="cb1-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(title,  </span>
<span id="cb1-12">         date_aired,</span>
<span id="cb1-13">         imdb,</span>
<span id="cb1-14">         motive) </span></code></pre></div>
</div>
<section id="factor-character-and-other-vector-types" class="level2">
<h2 class="anchored" data-anchor-id="factor-character-and-other-vector-types">Factor, character, and other vector types</h2>
<p>As a general rule, <code>tidyverse</code> functions treat character vectors as factors. For instance, we can apply <code>dplyr::count</code> to <code>scooby$motive</code>, even though the latter just consists of strings.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glimpse</span>(scooby_sm)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Rows: 374
Columns: 4
$ title      &lt;chr&gt; "What a Night for a Knight", "A Clue for Scooby Doo", "Hass…
$ date_aired &lt;dttm&gt; 1969-09-13, 1969-09-20, 1969-09-27, 1969-10-04, 1969-10-11…
$ imdb       &lt;dbl&gt; 8.1, 8.1, 8.0, 7.8, 7.5, 8.4, 7.6, 8.2, 8.1, 8.0, 8.5, 8.2,…
$ motive     &lt;chr&gt; "Theft", "Theft", "Treasure", "Natural Resource", "Competit…</code></pre>
</div>
<div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">scooby_sm <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb4-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">count</span>(motive)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 17 × 2
   motive               n
   &lt;chr&gt;            &lt;int&gt;
 1 Abduction            3
 2 Assistance           2
 3 Competition        130
 4 Conquer             33
 5 Counterfeit          6
 6 Entertainment        3
 7 Extortion            3
 8 Imagination          1
 9 Inheritance          6
10 Natural Resource    19
11 Preservation        10
12 Safety               2
13 Simulation           2
14 Smuggling           19
15 Theft               93
16 Treasure            40
17 &lt;NA&gt;                 2</code></pre>
</div>
</div>
<p>Use <code>as.factor()</code> to explicitly coerce variables to factors. This is particularly useful when category levels are numeric, like <code>am</code> (automatic/manual transmission) in the built-in <code>mtcars</code> set, since functions like <code>ggplot</code> will otherwise attempt to treat them as continuous variables. For instance, we can’t get directly get a side-by-side boxplot of <code>mpg</code> vs <code>am</code>.</p>
<div class="cell" data-layout-align="center">
<div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glimpse</span>(mtcars)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Rows: 32
Columns: 11
$ mpg  &lt;dbl&gt; 21.0, 21.0, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.8, 19.2, 17.8,…
$ cyl  &lt;dbl&gt; 6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 8,…
$ disp &lt;dbl&gt; 160.0, 160.0, 108.0, 258.0, 360.0, 225.0, 360.0, 146.7, 140.8, 16…
$ hp   &lt;dbl&gt; 110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123, 180, 180, 180…
$ drat &lt;dbl&gt; 3.90, 3.90, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.92, 3.92, 3.92,…
$ wt   &lt;dbl&gt; 2.620, 2.875, 2.320, 3.215, 3.440, 3.460, 3.570, 3.190, 3.150, 3.…
$ qsec &lt;dbl&gt; 16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20.00, 22.90, 18…
$ vs   &lt;dbl&gt; 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,…
$ am   &lt;dbl&gt; 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,…
$ gear &lt;dbl&gt; 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3,…
$ carb &lt;dbl&gt; 4, 4, 1, 1, 2, 1, 4, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 1, 2, 1, 1, 2,…</code></pre>
</div>
<div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(mtcars, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> am, </span>
<span id="cb8-2">                   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> mpg)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb8-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_boxplot</span>() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># not what we want</span></span></code></pre></div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: Orientation is not uniquely specified when both the x and y aesthetics are
continuous. Picking default orientation 'x'.</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: Continuous x aesthetic
ℹ did you forget `aes(group = ...)`?</code></pre>
</div>
<div class="cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://equitableequations.com/posts/2026-09-07/index_files/figure-html/unnamed-chunk-3-1.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:60.0%"></p>
</figure>
</div>
</div>
</div>
<p>While it’s fine to follow the recommendation given in this warning message, it may be better to just convert <code>am</code> to a factor once and for all:</p>
<div class="cell" data-layout-align="center">
<div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1">mtcars2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> mtcars <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb11-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">am =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.factor</span>(am)) </span>
<span id="cb11-3"></span>
<span id="cb11-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(mtcars2, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> am, </span>
<span id="cb11-5">                    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> mpg)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb11-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_boxplot</span>()</span></code></pre></div>
<div class="cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://equitableequations.com/posts/2026-09-07/index_files/figure-html/unnamed-chunk-4-1.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:60.0%"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="relabeling-factors" class="level2">
<h2 class="anchored" data-anchor-id="relabeling-factors">Relabeling factors</h2>
<p>There are many options for changing the text used to label factor levels, but <code>fct_recode()</code> is a solid choice.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">mtcars2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> mtcars2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb12-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">am =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct_recode</span>(am, </span>
<span id="cb12-3">                         <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"automatic"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"0"</span>,</span>
<span id="cb12-4">                         <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"manual"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1"</span>))</span>
<span id="cb12-5">mtcars2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb12-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">count</span>(am)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>         am  n
1 automatic 19
2    manual 13</code></pre>
</div>
</div>
<p>Notice the syntax, “new_name” = “old_name”, which is common in <code>tidyverse</code> R.</p>
<p>When you have a large number of different factor levels, it may be helpful to lump the less common ones into an “other” category. For instance, the next chunk combines all categories with fewer than 20 occurrences.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1">scooby_sm2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> scooby_sm <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb14-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">motive =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct_lump_min</span>(motive,</span>
<span id="cb14-3">                               <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">min =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)) </span>
<span id="cb14-4">scooby_sm2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb14-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">count</span>(motive) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb14-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>n)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 6 × 2
  motive          n
  &lt;fct&gt;       &lt;int&gt;
1 Competition   130
2 Theft          93
3 Other          76
4 Treasure       40
5 Conquer        33
6 &lt;NA&gt;            2</code></pre>
</div>
</div>
<p>Also check out <code>fct_lump_n()</code> to specify the number of levels retained, <code>fct_lump_prop()</code> to lump low-percentage levels, and <code>fct_lump_lowfreq()</code> to try to force the new “Other” level to have lowest frequency.</p>
</section>
<section id="rearranging-levels" class="level2">
<h2 class="anchored" data-anchor-id="rearranging-levels">Rearranging levels</h2>
<p>Sometimes the order of factor levels matters, for instance in a bar chart. The default odering is alphanumeric.</p>
<div class="cell" data-layout-align="center">
<div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(scooby_sm2, </span>
<span id="cb16-2">       <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> motive)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb16-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_bar</span>()</span></code></pre></div>
<div class="cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://equitableequations.com/posts/2026-09-07/index_files/figure-html/unnamed-chunk-7-1.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:60.0%"></p>
</figure>
</div>
</div>
</div>
<p>Use <code>fct_relevel()</code> to shift levels to the front. For instance, the next code chunk places the motives <code>Treasure</code> and <code>Theft</code> before <code>Compitition</code> and others.</p>
<div class="cell" data-layout-align="center">
<div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb17-1">scooby_sm3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> scooby_sm2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb17-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">motive =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct_relevel</span>(motive,</span>
<span id="cb17-3">                              <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Treasure"</span>,</span>
<span id="cb17-4">                              <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Theft"</span>)) </span>
<span id="cb17-5"></span>
<span id="cb17-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(scooby_sm3, </span>
<span id="cb17-7">       <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> motive)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb17-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_bar</span>()</span></code></pre></div>
<div class="cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://equitableequations.com/posts/2026-09-07/index_files/figure-html/unnamed-chunk-8-1.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:60.0%"></p>
</figure>
</div>
</div>
</div>
<p>Often, you just want to put the most common factor levels first. Use <code>fct_infreq()</code> to accomplish this.</p>
<div class="cell" data-layout-align="center">
<div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb18-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(scooby_sm2, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct_infreq</span>(motive))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb18-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_bar</span>()</span></code></pre></div>
<div class="cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://equitableequations.com/posts/2026-09-07/index_files/figure-html/unnamed-chunk-9-1.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:60.0%"></p>
</figure>
</div>
</div>
</div>
<p>You can also reverse the order of the factor levels with <code>fct_rev</code>.</p>
</section>
<section id="reordering-levels-using-a-second-variable" class="level2">
<h2 class="anchored" data-anchor-id="reordering-levels-using-a-second-variable">Reordering levels using a second variable</h2>
<p>For some plots, it can be natural to order a categorical variable using a numeric one. For instance, in the next plot, it would be preferable to show the various motives in increasing order of imdb ratings.</p>
<div class="cell" data-layout-align="center">
<div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb19-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(scooby_sm3, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> motive,</span>
<span id="cb19-2">                       <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> imdb)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb19-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_boxplot</span>()</span></code></pre></div>
<div class="cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://equitableequations.com/posts/2026-09-07/index_files/figure-html/unnamed-chunk-10-1.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:60.0%"></p>
</figure>
</div>
</div>
</div>
<p>Use <code>fct_reorder</code> to accomplish this.</p>
<div class="cell" data-layout-align="center">
<div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb20-1">scooby_sm4 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> scooby_sm3 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb20-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">motive =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fct_reorder</span>(motive,</span>
<span id="cb20-3">                              imdb))</span>
<span id="cb20-4"></span>
<span id="cb20-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(scooby_sm4, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> motive,</span>
<span id="cb20-6">                       <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> imdb)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb20-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_boxplot</span>()</span></code></pre></div>
<div class="cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://equitableequations.com/posts/2026-09-07/index_files/figure-html/unnamed-chunk-11-1.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:60.0%"></p>
</figure>
</div>
</div>
</div>
<p>By default, <code>fct_reorder</code> sorts using the median. You can specify a different function (like mean) by adding a <code>.fun</code> argument.</p>
</section>
<section id="ordered-factors" class="level2">
<h2 class="anchored" data-anchor-id="ordered-factors">Ordered factors</h2>
<p>Occasionally you may encounter ordered factors, ones of class <code>ord</code>. For the most part, you can treat these like regular factors.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb21-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glimpse</span>(diamonds)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>Rows: 53,940
Columns: 10
$ carat   &lt;dbl&gt; 0.23, 0.21, 0.23, 0.29, 0.31, 0.24, 0.24, 0.26, 0.22, 0.23, 0.…
$ cut     &lt;ord&gt; Ideal, Premium, Good, Premium, Good, Very Good, Very Good, Ver…
$ color   &lt;ord&gt; E, E, E, I, J, J, I, H, E, H, J, J, F, J, E, E, I, J, J, J, I,…
$ clarity &lt;ord&gt; SI2, SI1, VS1, VS2, SI2, VVS2, VVS1, SI1, VS2, VS1, SI1, VS1, …
$ depth   &lt;dbl&gt; 61.5, 59.8, 56.9, 62.4, 63.3, 62.8, 62.3, 61.9, 65.1, 59.4, 64…
$ table   &lt;dbl&gt; 55, 61, 65, 58, 58, 57, 57, 55, 61, 61, 55, 56, 61, 54, 62, 58…
$ price   &lt;int&gt; 326, 326, 327, 334, 335, 336, 336, 337, 337, 338, 339, 340, 34…
$ x       &lt;dbl&gt; 3.95, 3.89, 4.05, 4.20, 4.34, 3.94, 3.95, 4.07, 3.87, 4.00, 4.…
$ y       &lt;dbl&gt; 3.98, 3.84, 4.07, 4.23, 4.35, 3.96, 3.98, 4.11, 3.78, 4.05, 4.…
$ z       &lt;dbl&gt; 2.43, 2.31, 2.31, 2.63, 2.75, 2.48, 2.47, 2.53, 2.49, 2.39, 2.…</code></pre>
</div>
<div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb23-1">diamonds <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> </span>
<span id="cb23-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">count</span>(cut) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># several ordered factors</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 5 × 2
  cut           n
  &lt;ord&gt;     &lt;int&gt;
1 Fair       1610
2 Good       4906
3 Very Good 12082
4 Premium   13791
5 Ideal     21551</code></pre>
</div>
</div>
<p>Specifying that a factor is ordered (for instance using <code>ordered</code>) can occasionally matter in modeling applications and certain forms of statistical inference. Other than that, the most visible difference with ordered factors in R is how they’re displayed by <code>ggplot</code>.</p>
<div class="cell" data-layout-align="center">
<div class="sourceCode cell-code" id="cb25" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb25-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(diamonds, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> cut,</span>
<span id="cb25-2">                     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> cut)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb25-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_bar</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">show.legend =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>)</span></code></pre></div>
<div class="cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://equitableequations.com/posts/2026-09-07/index_files/figure-html/unnamed-chunk-13-1.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:60.0%"></p>
</figure>
</div>
</div>
</div>
<p>By default, ordered factors are colored using the <code>viridis</code> palette, which is has a distinct order to it.</p>
</section>
<section id="want-more" class="level2">
<h2 class="anchored" data-anchor-id="want-more">Want more?</h2>
<p>If something here isn’t clear, there’s a good chance you’ll find an explanation in my vid on the subject:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Nkjy6UFKJsc?si=7OCFQeMoxzYjsK_l" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p><button class="btn btn-default downloadthis  " id="dnldts62629"><i class="bi bi-download"></i> Download scooby.xlsx </button> <button class="btn btn-default downloadthis  " id="dnldts54140"><i class="bi bi-download"></i> Download Quarto </button> <button class="btn btn-default downloadthis  " id="dnldts16691"><i class="bi bi-download"></i> Download html </button></p>
<p>This post will be cross-listed on <a href="https://www.r-bloggers.com/">R-bloggers</a>, a site that I totally recommend.</p>


</section>

 ]]></description>
  <category>forcats</category>
  <category>R-bloggers</category>
  <guid>https://equitableequations.com/posts/2026-09-07/</guid>
  <pubDate>Mon, 07 Sep 2026 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2026-09-07/factors thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Regular expressions for R users</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2026-08-24/</link>
  <description><![CDATA[ 




<p>Searching and manipulating strings (those things that make up character vectors) is easy as long as you only need to match specific sequences of letters and numbers. To match patterns rather than specific substrings or to search symbols, you’ll need to use <em>regular expressions</em> (<em>regex</em> for short).</p>
<p>Throughout this post, I’ll make use three <code>stringr</code> functions: <code>str_subset</code>, <code>str_detect</code>, and <code>str_extract</code>, and a subset of the <code>sentences</code> vector.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(stringr)</span>
<span id="cb1-2"></span>
<span id="cb1-3">sentences <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> sentences[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>]</span>
<span id="cb1-4">sentences</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "The birch canoe slid on the smooth planks." 
 [2] "Glue the sheet to the dark blue background."
 [3] "It's easy to tell the depth of a well."     
 [4] "These days a chicken leg is a rare dish."   
 [5] "Rice is often served in round bowls."       
 [6] "The juice of lemons makes fine punch."      
 [7] "The box was thrown beside the parked truck."
 [8] "The hogs were fed chopped corn and garbage."
 [9] "Four hours of steady work faced us."        
[10] "A large size in stockings is hard to sell." </code></pre>
</div>
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_subset</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"of"</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># keep only elements with a match</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "It's easy to tell the depth of a well."
[2] "Rice is often served in round bowls."  
[3] "The juice of lemons makes fine punch." 
[4] "Four hours of steady work faced us."   </code></pre>
</div>
<div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_detect</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"of"</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># TRUE when an element matches, FALSE otherwise</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] FALSE FALSE  TRUE FALSE  TRUE  TRUE FALSE FALSE  TRUE FALSE</code></pre>
</div>
<div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_extract</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"of"</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pull out matching substrings</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] NA   NA   "of" NA   "of" "of" NA   NA   "of" NA  </code></pre>
</div>
</div>
<section id="special-characters" class="level2">
<h2 class="anchored" data-anchor-id="special-characters">Special characters</h2>
<p>The following characters (all of which are explained below) have special meanings and can’t be searched literally.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1">. \ <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> ( ) [ { <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">*</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> ? </span></code></pre></div>
</div>
<p>For instance, a dot matches with <em>any</em> character, which explains the following output.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_extract</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"."</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "T" "G" "I" "T" "R" "T" "T" "T" "F" "A"</code></pre>
</div>
</div>
<p>In order to match these metacharacters, precede them with two slashes, like so:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_extract</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">."</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "." "." "." "." "." "." "." "." "." "."</code></pre>
</div>
</div>
</section>
<section id="position-and-relative-position" class="level2">
<h2 class="anchored" data-anchor-id="position-and-relative-position">Position and relative position</h2>
<p>To specify that a substring comes at the beginning of a string, use “^”. To specify that it comes at the end, use “$”.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_subset</span>(fruit, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"^re"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "redcurrant"</code></pre>
</div>
<div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_subset</span>(fruit, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"er$"</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># note order</span></span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "bell pepper"  "chili pepper" "cucumber"    </code></pre>
</div>
</div>
<p>As mentioned above, a dot indicates that substrings are separated by an arbitrary character.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb18-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_extract</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"s.o"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "smo" NA    NA    NA    "s o" NA    NA    NA    "s o" "sto"</code></pre>
</div>
</div>
</section>
<section id="character-sets" class="level2">
<h2 class="anchored" data-anchor-id="character-sets">Character sets</h2>
<p>Use brackets to allow multiple options for the character to be matched.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb20-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_subset</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[oe]n"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "The birch canoe slid on the smooth planks."
[2] "These days a chicken leg is a rare dish."  
[3] "Rice is often served in round bowls."      
[4] "The juice of lemons makes fine punch."     </code></pre>
</div>
<div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb22-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_extract</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[oe]n"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "on" NA   NA   "en" "en" "on" NA   NA   NA   NA  </code></pre>
</div>
</div>
<p>Ranges of letters and numbers are allowed.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb24-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_subset</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[a-j]o"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "Rice is often served in round bowls."       
[2] "The box was thrown beside the parked truck."
[3] "The hogs were fed chopped corn and garbage."
[4] "Four hours of steady work faced us."        </code></pre>
</div>
<div class="sourceCode cell-code" id="cb26" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb26-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_extract</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[a-j]o"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] NA   NA   NA   NA   "bo" NA   "bo" "ho" "ho" NA  </code></pre>
</div>
</div>
<p>Inside of brackets, “^” represents negation.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb28" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb28-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_extract</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[^a-j]o"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "no" "to" "to" NA   " o" " o" "ro" NA   "Fo" "to"</code></pre>
</div>
</div>
</section>
<section id="character-classes" class="level2">
<h2 class="anchored" data-anchor-id="character-classes">Character classes</h2>
<p>It’s also possible to specify classes of characters. “\d” matches any digit and “\w” matches and word character (a-z, A-Z, 0-9, and underscore), while “\D” and “\W” will match anything <em>except</em> digits and word characters, respectively. Many other classes are available. Enter <code>?regex</code> for a full list.</p>
</section>
<section id="the-role-of-in-quarto" class="level2">
<h2 class="anchored" data-anchor-id="the-role-of-in-quarto">The role of “\” in Quarto</h2>
<p>If you write “\d” in a Quarto document, it won’t render properly. This is because Quarto interprets the slash as an escape character. To actually render this string, use “\\d” instead.</p>
<p>Similarly, to render a slash, use \\.</p>
</section>
<section id="matching-whitespace" class="level2">
<h2 class="anchored" data-anchor-id="matching-whitespace">Matching whitespace</h2>
<p>Use <code>\\s</code> for space, <code>\\t</code> for tab, and <code>\\n</code> for a new line.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb30" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb30-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_subset</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"e</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">sb"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "The birch canoe slid on the smooth planks." 
[2] "Glue the sheet to the dark blue background."
[3] "The box was thrown beside the parked truck."</code></pre>
</div>
</div>
</section>
<section id="repetition" class="level2">
<h2 class="anchored" data-anchor-id="repetition">Repetition</h2>
<p>Use curly braces to indicate how many times in a row a character must appear.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb32" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb32-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_subset</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"e{2}"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "Glue the sheet to the dark blue background."</code></pre>
</div>
</div>
<p>Use “+” to indicate at least one occurrence, possibly more.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb34" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb34-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_subset</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"she+t"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "Glue the sheet to the dark blue background."</code></pre>
</div>
</div>
<p>To indicate a character is optional, use “?”. For instance, the next command detects both “the” and “often”.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb36" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb36-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_extract</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"th?e"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "the" "the" "te"  NA    "te"  NA    "the" NA    "te"  NA   </code></pre>
</div>
</div>
<p>Finally, “*” indicates an optional character that may occur more than once.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb38" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb38-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_extract</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"she*"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] NA     "shee" NA     "sh"   NA     NA     NA     NA     NA     NA    </code></pre>
</div>
</div>
<p>Notice that these symbols come <em>after</em> the characters they refer to, unlike “\” which comes before.</p>
</section>
<section id="combining-substrings-with" class="level2">
<h2 class="anchored" data-anchor-id="combining-substrings-with">Combining substrings with <code>|</code></h2>
<p>Use the pipe to indicate an “or” statement. Expressions on either side are grouped by default.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb40" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb40-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_subset</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"chicken|hog"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "These days a chicken leg is a rare dish."   
[2] "The hogs were fed chopped corn and garbage."</code></pre>
</div>
</div>
<p>You can still group using parentheses, though.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb42" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb42-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str_subset</span>(sentences, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"(chicken|hog)s"</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "The hogs were fed chopped corn and garbage."</code></pre>
</div>
</div>
</section>
<section id="want-more" class="level2">
<h2 class="anchored" data-anchor-id="want-more">Want more?</h2>
<p>If something here isn’t clear, there’s a good chance you’ll find an explanation in my vid on the subject:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/wy0cEKYeaF8?si=RktCufxzNGzK8UEi" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p><button class="btn btn-default downloadthis  " id="dnldts12780"><i class="bi bi-download"></i> Download Quarto </button> <button class="btn btn-default downloadthis  " id="dnldts52094"><i class="bi bi-download"></i> Download html </button></p>
<p>This post will be cross-listed on <a href="https://www.r-bloggers.com/">R-bloggers</a>, a site that I totally recommend.</p>


</section>

 ]]></description>
  <category>regex</category>
  <category>stringr</category>
  <category>R-bloggers</category>
  <guid>https://equitableequations.com/posts/2026-08-24/</guid>
  <pubDate>Mon, 24 Aug 2026 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2026-08-24/regex thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Understanding the grammar of graphics</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2026-01-05/</link>
  <description><![CDATA[ 




<iframe width="560" height="315" src="https://www.youtube.com/embed/JkdBxGQySmM?si=QA2BtCBTXLHtYhy6" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p>The world of data visualization has been revolutionized in recent years with the introduction of the grammar of graphics and its implementation in R, the <code>ggplot2</code> package. While other plotting systems set aside a different function for each sort of visualization (histogram, scatterplot, and so on), the grammar of graphics takes the view that the most fundamental characteristics of a plot are the variables it includes and the roles they play (x-axis, y-axis, color, etc). The specific brand of plot is secondary and can be specified later.</p>
<p>To create a visualization, we need to specify three things:</p>
<ol type="1">
<li><p>what <u><strong>data</strong></u> is being used.</p></li>
<li><p>how the variables are <u><strong>mapped</strong></u> onto the plot (in this case, onto the x- and y-axes).</p></li>
<li><p>which <u><strong>geometry</strong></u> should be used to represent the data (scatter plot, line graph, or something else entirely).</p></li>
</ol>
<p>Design considerations like axis labels, color palette, and font, can be specified separately after the fact</p>
<p>Notice how all of these elements appear, in order, in the following code chunk.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tidyverse)</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(penguins, </span>
<span id="cb1-4">       <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> bill_len, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> body_mass)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb1-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_point</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bill length (mm)"</span>,</span>
<span id="cb1-7">       <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Body mass (g)"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb1-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>()</span></code></pre></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://equitableequations.com/posts/2026-01-05/index_files/figure-html/unnamed-chunk-1-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p><button class="btn btn-default downloadthis  " id="dnldts42901"><i class="bi bi-download"></i> Download slides </button> <button class="btn btn-default downloadthis  " id="dnldts26160"><i class="bi bi-download"></i> Download practice plots </button></p>



 ]]></description>
  <category>Grammar of graphics</category>
  <category>ggplot2</category>
  <guid>https://equitableequations.com/posts/2026-01-05/</guid>
  <pubDate>Mon, 05 Jan 2026 06:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2026-01-05/gog thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Content to support my course, Data Science with R</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-11-10/</link>
  <description><![CDATA[ 




<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://equitableequations.com/posts/2025-11-10/dsr thumb.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:50.0%"></p>
</figure>
</div>
<ul>
<li><p>Data manipulation with R:</p>
<p><button class="btn btn-default downloadthis  " id="dnldts13107"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts24922"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Getting started with ggplot:</p>
<p><button class="btn btn-default downloadthis  " id="dnldts28271"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts31987"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Single-variable plots with ggplot2:</p>
<p><button class="btn btn-default downloadthis  " id="dnldts59734"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts41585"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Quantitative vs categorical plots with ggplot2:</p>
<p><button class="btn btn-default downloadthis  " id="dnldts30602"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts49129"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Introducing the pipe:</p>
<p><button class="btn btn-default downloadthis  " id="dnldts13176"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts54838"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Grouped summaries in R:</p>
<p><button class="btn btn-default downloadthis  " id="dnldts59996"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts46154"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Grouped filters and mutates</p>
<p><button class="btn btn-default downloadthis  " id="dnldts28436"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts31018"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Tidying data with <code>pivot_longer</code>:</p>
<p><button class="btn btn-default downloadthis  " id="dnldts30"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts30975"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Tidying data with <code>pivot_wider</code>:</p>
<p><button class="btn btn-default downloadthis  " id="dnldts55108"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts26687"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Mutating joins:</p>
<p><button class="btn btn-default downloadthis  " id="dnldts56091"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts35924"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Filtering joins</p>
<p><button class="btn btn-default downloadthis  " id="dnldts23950"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts57871"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Working with dates and times</p>
<p><button class="btn btn-default downloadthis  " id="dnldts27009"><i class="bi bi-download"></i> Download optical.csv </button> <button class="btn btn-default downloadthis  " id="dnldts62299"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts8437"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Working with strings</p>
<p><button class="btn btn-default downloadthis  " id="dnldts54697"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts8659"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
<li><p>Working with factors</p>
<p><button class="btn btn-default downloadthis  " id="dnldts12011"><i class="bi bi-download"></i> Download scooby.xlsx </button> <button class="btn btn-default downloadthis  " id="dnldts22942"><i class="bi bi-download"></i> Download html notes </button> <button class="btn btn-default downloadthis  " id="dnldts36352"><i class="bi bi-download"></i> Download quarto notes </button></p></li>
</ul>



 ]]></description>
  <category>dplyr</category>
  <category>ggplot2</category>
  <category>tidyr</category>
  <guid>https://equitableequations.com/posts/2025-11-10/</guid>
  <pubDate>Mon, 10 Nov 2025 06:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-11-10/dsr thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>What is Quarto?</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-10-27/</link>
  <description><![CDATA[ 




<p>Quarto lets you write and save code while also adding text, images, and other content to contextualize what you’re doing. It makes it easy to create attractive public-facing versions of your data work. My advice is to always work inside of a Quarto document when building your R skills.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/w5vBoaN6t-M?si=1HmMNFWiIRoBpCnW" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p><button class="btn btn-default downloadthis  " id="dnldts16612"><i class="bi bi-download"></i> Download erykah.xlsx </button> <button class="btn btn-default downloadthis  " id="dnldts29594"><i class="bi bi-download"></i> Download notes </button></p>



 ]]></description>
  <category>Quarto</category>
  <guid>https://equitableequations.com/posts/2025-10-27/</guid>
  <pubDate>Mon, 27 Oct 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-10-27/quarto thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Getting started with R</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-10-13/</link>
  <description><![CDATA[ 




<p>I’ve decided to start updating my introductory-level content, much of which was recorded early in the 2020 pandemic. When completed, I expect to have a complete course in data science with R, roughly paralleling what you might find in a sophomore-level university course for students with some statistical knowledge but not necessarily and programming experience.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/ftb7u_JuJwg?si=dON-HYvqMeF0Ped6" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p><button class="btn btn-default downloadthis  " id="dnldts45602"><i class="bi bi-download"></i> Download amy.csv </button></p>



 ]]></description>
  <category>RStudio</category>
  <guid>https://equitableequations.com/posts/2025-10-13/</guid>
  <pubDate>Mon, 13 Oct 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-10-13/getting_started_thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>How to set up RStudio for success</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-09-30/</link>
  <description><![CDATA[ 




<p>By making a few changes to the RStuio IDE the first time you open it, you can both improve your quality of life and enforce some important data science best practices right from the start. My three most important recommendations:</p>
<ul>
<li>Put the console pane on the right</li>
<li>Set .RData to automatically clear after every session</li>
<li>Work inside of a project</li>
</ul>
<iframe width="560" height="315" src="https://www.youtube.com/embed/5rF5Ek-OvCE?si=7k6REYEj1BKOUbhQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>



 ]]></description>
  <category>RStudio</category>
  <guid>https://equitableequations.com/posts/2025-09-30/</guid>
  <pubDate>Tue, 30 Sep 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-09-30/setup thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Why haven’t I covered tidymodels?</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-09-22/</link>
  <description><![CDATA[ 




<p>The <code>tidymodels</code> framework for machine learning is powerful and about as user-friendly as we can hope for in that space, bringing consistency and clarity to a process that can continue to feel ad-hoc well into the learning curve. Over time, it’s supplanted the older favorite meta-package, <code>carat</code>, which coincidentally (note sarcasm) was written by one the primary <code>tidymodels</code> architects, Max Kuhn.</p>
<p>I love <code>tidymodels</code> and use it consistently for my machine learning needs. Yet when I’ve done vids on ML techniques, I’ve almost always shied away, opting to use individual packages instead. Why?</p>
<p>The short answer is that I haven’t figured out how to teach it in a YouTube-friendly way yet. Vids on Equitable Equations aim to be short, self-contained, clear expositions of individual topics. While these can (and should!) be chained together to build a comprehensive whole, it’s important to me - and to the Almighty Algorithm, whom we all serve - that they stand on their own. Machine learning is hard to do this way.</p>
<p>One of the wonderful things about the core <code>tidyverse</code> is the degree to which it teaches basic data science concepts. When we learn <code>ggplot2</code>, we learn the grammar of graphics. When we learn <code>tidyr</code>, we learn about tidy data and pivoting. As we move deeper into the era of automated coding, this structure for gaining conceptual knowledge is invaluable.</p>
<p>But <code>tidymodels</code> is different. It’s a higher-order system designed to unify a large number of related tasks, some of which have very little meaning outside of a machine learning workflow.</p>
<p>If you’re sitting down to study logistic regression for the first time, for instance, <code>tidymodels</code> will simultaneously want you to consider a data split, preprocessing steps, and performance metrics, to start. This is wonderful and important, ultimately, but puts a huge burden on the learner, not to mention the YouTuber.</p>
<p>Over time, I’ve covered many components of the ML process in my vids, keeping them as separate and simple as possible. This has often come at the expense of data science best practices, for instance when I build models without first splitting data and conclude without computing performance metrics on an independent set. I’ve always felt that logistic regression (to name one technique) is hard enough to learn on its own without simultaneously tackling cross-validation (to name another). It hasn’t been a perfect choice, but it’s the one I’ve made, and I think my reasons are valid.</p>
<p>So, the TL/DR is that <code>tidymodels</code> is a pedagogical challenge. I’ve spent a lot of time wrestling with it, and though I’m not done yet, I hope to be soon. With any luck, you can expect a <code>tidymodels</code> series some time in the fall of 2026.</p>



 ]]></description>
  <category>tidymodels</category>
  <guid>https://equitableequations.com/posts/2025-09-22/</guid>
  <pubDate>Mon, 22 Sep 2025 05:00:00 GMT</pubDate>
</item>
<item>
  <title>Discrete probability calculations in R</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-09-15/</link>
  <description><![CDATA[ 




<p>In R, functions that perform probabilities calculations follow a consistent structure:</p>
<ul>
<li><p>Probability mass functions (pmfs) start with the letter “d”. Use such a function to compute <img src="https://latex.codecogs.com/png.latex?P(X%20=%20x_0)"> for any <img src="https://latex.codecogs.com/png.latex?x_0"> of interest.</p></li>
<li><p>Cumulative distribution functions (cdfs) start with the letter “p”. Use such a function to compute <img src="https://latex.codecogs.com/png.latex?P(X%20%5Cle%20x_0)">.</p></li>
<li><p>Inverse cdfs start with the letter “q”. For a given probability <img src="https://latex.codecogs.com/png.latex?p">, they determine the least <img src="https://latex.codecogs.com/png.latex?x_0"> such that <img src="https://latex.codecogs.com/png.latex?P(X%20%5Cle%20x_0)%20%5Cge%20p">.</p></li>
<li><p>Functions to generate random values start with the letter “r”.</p></li>
</ul>
<p>The rest of the function name is a shortened version of the distribution name:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 28%">
<col style="width: 20%">
<col style="width: 17%">
<col style="width: 16%">
<col style="width: 16%">
</colgroup>
<thead>
<tr class="header">
<th>Distribution</th>
<th>Probability</th>
<th>Cumulative</th>
<th>Inverse</th>
<th>Random</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Bin<img src="https://latex.codecogs.com/png.latex?(n,%20p)"></td>
<td>dbinom()</td>
<td>pbinom()</td>
<td>qbinom()</td>
<td>rbinom()</td>
</tr>
<tr class="even">
<td>Geom<img src="https://latex.codecogs.com/png.latex?(p)"></td>
<td>dgeom()</td>
<td>pgeom()</td>
<td>qgeom()</td>
<td>rgeom()</td>
</tr>
<tr class="odd">
<td>NB<img src="https://latex.codecogs.com/png.latex?(r,%20p)"></td>
<td>dnbinom()</td>
<td>pnbinom()</td>
<td>qnbinom()</td>
<td>rnbinom()</td>
</tr>
<tr class="even">
<td>Hyp<img src="https://latex.codecogs.com/png.latex?(N_1,%20N_2,%20n)"></td>
<td>dhyper()</td>
<td>phyper()</td>
<td>qhyper()</td>
<td>rhyper()</td>
</tr>
<tr class="odd">
<td>Pois<img src="https://latex.codecogs.com/png.latex?(%5Clambda)"></td>
<td>dpois()</td>
<td>ppois()</td>
<td>qpois()</td>
<td>rpois()</td>
</tr>
</tbody>
</table>
<p>In case some of these distributions aren’t familiar to you:</p>
<ul>
<li><p>The <strong>binomial distribution</strong> models the total number of success in <img src="https://latex.codecogs.com/png.latex?n"> Bernouilli trials (identical and independent trials, each with only two possibly outcomes). The probability of success in each trial is <img src="https://latex.codecogs.com/png.latex?p">.</p></li>
<li><p>The <strong>geometric distribution</strong> models the number of failures in a sequence of Bernouilli trials prior to the first success.</p></li>
<li><p>The <strong>negative binomial distribution</strong> models the number of failures in a sequence of Bernouilli trials prior to the <img src="https://latex.codecogs.com/png.latex?r%5E%7Bth%7D"> success.</p></li>
<li><p>The <strong>hypergeometric distribution</strong> models the number of successes in a sample of size <img src="https://latex.codecogs.com/png.latex?n"> when selection is done without replacement from a pool that includes <img src="https://latex.codecogs.com/png.latex?N_1"> successes and <img src="https://latex.codecogs.com/png.latex?N_2"> failures.</p></li>
</ul>
<p>For instance, imagine a student guessing randomly on a 12-question quiz where each question has 4 possible answers. The probability that they get exactly 3 questions right is computed using <code>dbinom()</code>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dbinom</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 0.2581036</code></pre>
</div>
</div>
<p>Similarly, the probability that they get <em>at most</em> 3 questions right is given by</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pbinom</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 0.6487786</code></pre>
</div>
</div>
<p>If you need the probability that they get <em>at least</em> 3 questions right, add a <code>lower.tail</code> argument, like so:</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pbinom</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lower.tail =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 0.3512214</code></pre>
</div>
</div>
<p><code>qbinom()</code> reverses the logic of <code>pbinom()</code>, finding the number of successes with a specified cumulative probability. Said differently, <code>qbinom()</code> identifies <em>percentiles</em>. For instance, we might wonder how many questions the child would have to get right to do at least as well as 80% of randomly-guessing quiz takers.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">qbinom</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 4</code></pre>
</div>
</div>
<p>Notice how the arguments of these functions follow a common pattern: first the value/percentile of interest, then the parameters, which come in a consistent order. This pattern continues to hold for <code>rbinom()</code>, which generates a specified number of random values</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># For reproducibility</span></span>
<span id="cb9-2"></span>
<span id="cb9-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rbinom</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;">12</span>, .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] 5 2 2 3 5 2 5 5 4 3</code></pre>
</div>
</div>
<p>All of R’s probability functions are <em>vectorized</em>, meaning that they can perform multiple calculations at once. For instance, the next line computes the probability of obtaining exactly <img src="https://latex.codecogs.com/png.latex?x"> Butterfingers when randomly grabbing 5 candy bars from a bowl with 8 Butterfingers and 10 Snickers. Note that <img src="https://latex.codecogs.com/png.latex?x%20%5Cin%20%5C%7B0,%201,%202,%20%5Ccdots,%205%5C%7D">.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dhyper</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</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;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 0.029411765 0.196078431 0.392156863 0.294117647 0.081699346 0.006535948</code></pre>
</div>
</div>
<p>As you’d expect, these probabilities all add up to one.</p>
<p>Some caution is needed when working with the geometric and negative binomial distributions, both of which consider the number of failures occurring before a fixed number of successes. Some textbooks and computational tools define these distributions in terms on the total number of <em>trials</em> needed rather than the total number of <em>failures</em>, so some translation may be needed. Fortunately,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Ctext%7Btrials%7D%5C%20=%5C%20%5Ctext%7Bfailures%7D%20+%20%5Ctext%7Bsuccesses%7D,"> so the two formulations differ only in the addition or subtraction of the parameter <img src="https://latex.codecogs.com/png.latex?r">.</p>
<p><strong>Example.</strong> A basketball player makes 85% of their free throws. If they shoot until they make 5 shots, what is the probability that 7 shots are needed?</p>
<p><strong>Solution.</strong> Making 5 out of 7 shots requires exactly 2 misses, so the probability is</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dnbinom</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;">5</span>, .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">85</span>)</span></code></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 0.1497505</code></pre>
</div>
</div>
<p>You might consider trying the next problem on your own before reading my solution.</p>
<p><strong>Example.</strong> Every day, a new author has a 10% chance of selling a copy of their ebook. Assume that purchases are independent of one another and that there are never multiple sales in a single day.</p>
<ol type="a">
<li><p>Find the probability that the first purchase occurs on the 10<img src="https://latex.codecogs.com/png.latex?%5E%7Bth%7D"> day.</p></li>
<li><p>Find the probability that the second purchase occurs during the second week (days 8-14).</p></li>
</ol>
<p><strong>Solution.</strong> Let <img src="https://latex.codecogs.com/png.latex?X"> be the number of days that pass before the first purchase and let <img src="https://latex.codecogs.com/png.latex?Y"> be the number of purchase-less days before the second. Then <img src="https://latex.codecogs.com/png.latex?X"> has a geometric distribution and <img src="https://latex.codecogs.com/png.latex?Y"> has a negative binomial distribution. In each case, <img src="https://latex.codecogs.com/png.latex?p=.10">.</p>
<ol type="a">
<li><p>If 10 trials are needed for a single success, then 9 failures must have occurred, so we compute <img src="https://latex.codecogs.com/png.latex?P(X%20=%209)%20="> <code>dgeom(9, .10)</code> = 0.038742</p></li>
<li><p>If between 8 and 14 days are needed for 2 sales, then between 6 and 12 days must have occurred without sales. <img src="https://latex.codecogs.com/png.latex?P(6%20%5Cle%20Y%20%5Cle%2012)%20="> <code>pnbinom(12, 2, .10) - pnbinom(5, 2, .10)</code> = 0.2656765</p></li>
</ol>
<p>Prefer to have this all clearly explained in a short vid? I’ve got you covered:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Z_11FDzyn7k?si=6wco1eMthtb-Rskj" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p><button class="btn btn-default downloadthis  " id="dnldts40330"><i class="bi bi-download"></i> Download slides </button></p>
<p>This post will be cross-listed on <a href="https://www.r-bloggers.com/">R-bloggers</a>, a site that I totally recommend.</p>



 ]]></description>
  <category>Probability</category>
  <category>R-bloggers</category>
  <guid>https://equitableequations.com/posts/2025-09-15/</guid>
  <pubDate>Mon, 15 Sep 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-09-15/probs in R thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Writing prompts using interpolate()</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-09-02/</link>
  <description><![CDATA[ 




<p>This week, I’m writing a function that generates a short help file for any stats concept the user specifies. While prompting ChatGPT to do this isn’t particularly hard, the process spotlights some important and interesting aspects of embedding such prompts inside of functions. I had a great time learning about <code>interpolate()</code>, in particular.</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/KrIkDPBg9Zk?si=xemfivqMi38eMHyJ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe></p>
<p><button class="btn btn-default downloadthis  " id="dnldts47886"><i class="bi bi-download"></i> Download script </button></p>



 ]]></description>
  <category>AI</category>
  <category>ellmer</category>
  <category>LLMs</category>
  <guid>https://equitableequations.com/posts/2025-09-02/</guid>
  <pubDate>Tue, 02 Sep 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-09-02/interpolate thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Teaching an AI to webscrape using the ellmer package</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-08-11/</link>
  <description><![CDATA[ 




<iframe width="560" height="315" src="https://www.youtube.com/embed/UPtMr8eOr5U?si=stSeGMamAUtaRC3X" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p><button class="btn btn-default downloadthis  " id="dnldts22598"><i class="bi bi-download"></i> Download script </button></p>



 ]]></description>
  <category>AI</category>
  <category>ellmer</category>
  <category>LLMs</category>
  <guid>https://equitableequations.com/posts/2025-08-11/</guid>
  <pubDate>Mon, 11 Aug 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-08-11/ellmer tools thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>All about system prompts</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-07-28/</link>
  <description><![CDATA[ 




<p>I’m generally ambivalent about large language models, but that doesn’t mean I’m going to bury my head in the sand about them. This week I learned how to assign Chat a specific role, require that it respond in the style (here, <code>tidyverse</code>) that I want, and place limitations on its behavior. All of this isn’t generally possible in a browser-based interface, which sent me even deeper into the ellmer package. It’s actually <em>more</em> fun when you understand how these things work.</p>
<p>As usual, code and other supporting materials are available below the vid.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/RDnRiGupF4U?si=zl7dGXrvsw5mbl2j" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p><button class="btn btn-default downloadthis  " id="dnldts46521"><i class="bi bi-download"></i> Download script </button> <button class="btn btn-default downloadthis  " id="dnldts5359"><i class="bi bi-download"></i> Download slides </button></p>



 ]]></description>
  <category>AI</category>
  <category>ellmer</category>
  <category>LLMs</category>
  <guid>https://equitableequations.com/posts/2025-07-28/</guid>
  <pubDate>Mon, 28 Jul 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-07-28/system prompts thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Advanced counting</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-07-25/</link>
  <description><![CDATA[ 




<p>The phrase “advanced counting” is bringing me an unreasonable amount of joy today. No, I don’t just mean listing really big whole numbers (though actually that could be pretty cool, too). The newest upload to my stats-focused channel, <a href="https://www.youtube.com/@NormalKnowledgeAG">Normal Knowledge</a>, features 4 challenging enumeration problems, including this nugget: how many distinct rolls of 12 dice are possible when the order of the rolls doesn’t matter? Listen, the world is in a state, and I’m finding joy wherever I can.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/btbbLTO4DbM?si=88DHo_-EZ0aj4qI9" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>



 ]]></description>
  <category>Probability</category>
  <guid>https://equitableequations.com/posts/2025-07-25/</guid>
  <pubDate>Fri, 25 Jul 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-07-25/counting thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>How to show a ggplot to an AI assistant</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-07-14/</link>
  <description><![CDATA[ 




<iframe width="560" height="315" src="https://www.youtube.com/embed/-mYInTbBMQ4?si=6vGHu8YvK-vithO6" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>



 ]]></description>
  <category>AI</category>
  <category>ellmer</category>
  <category>LLMs</category>
  <guid>https://equitableequations.com/posts/2025-07-14/</guid>
  <pubDate>Mon, 14 Jul 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-07-14/ggplot_AI thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
<item>
  <title>Can using an LLM for coding be ethical?</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-07-07/</link>
  <description><![CDATA[ 




<p>Arguably, coding assistance is the most ethical (least unethical?) way to use a large language model.</p>
<iframe width="324" height="575.1" src="https://www.youtube.com/embed/UogHVS3SjFg" title="Can using an LLM for coding be ethical? #coding #ai #llms" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>



 ]]></description>
  <category>AI</category>
  <category>LLMs</category>
  <guid>https://equitableequations.com/posts/2025-07-07/</guid>
  <pubDate>Mon, 07 Jul 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-07-07/rnd1.jpg" medium="image" type="image/jpeg"/>
</item>
<item>
  <title>Chatting with Claude AI in RStudio using ellmer</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-06-30/</link>
  <description><![CDATA[ 




<iframe width="560" height="315" src="https://www.youtube.com/embed/v1hYiuh0Q74?si=QXl2wQk5I_Hk4O3Z" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>



 ]]></description>
  <category>AI</category>
  <category>ellmer</category>
  <category>LLMs</category>
  <guid>https://equitableequations.com/posts/2025-06-30/</guid>
  <pubDate>Mon, 30 Jun 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-06-30/ellmer thumb.jpg" medium="image" type="image/jpeg"/>
</item>
<item>
  <title>All about facets</title>
  <dc:creator>Andrew Gard</dc:creator>
  <link>https://equitableequations.com/posts/2025-05-27/</link>
  <description><![CDATA[ 




<iframe width="560" height="315" src="https://www.youtube.com/embed/n6P7eLG80D8?si=mtav1XM23U6JZ991" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="">
</iframe>
<p><button class="btn btn-default downloadthis  " id="dnldts17344"><i class="bi bi-download"></i> Download script </button></p>



 ]]></description>
  <category>ggplot2</category>
  <guid>https://equitableequations.com/posts/2025-05-27/</guid>
  <pubDate>Tue, 27 May 2025 05:00:00 GMT</pubDate>
  <media:content url="https://equitableequations.com/posts/2025-05-27/facets thumb.png" medium="image" type="image/png" height="81" width="144"/>
</item>
</channel>
</rss>
