<?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>Michael Clark</title>
<link>https://m-clark.github.io/</link>
<atom:link href="https://m-clark.github.io/index.xml" rel="self" type="application/rss+xml"/>
<description>&quot;Models Demystified&quot; is a blog about data science and machine learning.
</description>
<generator>quarto-1.10.16</generator>
<lastBuildDate>Sun, 01 Mar 2026 05:00:00 GMT</lastBuildDate>
<item>
  <title>Is Boosting Still All You Need for Tabular Data?</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2026-03-01-dl-for-tabular-foundational/</link>
  <description><![CDATA[ 





<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>It’s been nearly four years since I <a href="../2021-07-15-dl-for-tabular/">first summarized</a> the state of deep learning (DL) for tabular data, and about three years since my <a href="../2022-04-01-more-dl-for-tabular/">follow-up post</a>. Back then, the verdict was clear: for most tabular scenarios, gradient boosting methods like XGBoost, LightGBM, and CatBoost were the pragmatic choice. Complex DL architectures, like TabNet and even the relatively newer transformer-based models, struggled to consistently outperform these boosting approaches, which meant they were impractical for most use cases.</p>
<p>The question now is: has anything fundamentally changed?</p>
<p>Let’s see if the landscape has shifted and tabular DL has finally found its place, or if we’re still in “<a href="https://www.xgblog.ai/p/xgboost-is-all-you-need">XGBoost is all you need</a>” territory.</p>
</section>
<section id="quick-take-if-youre-in-a-hurry" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="quick-take-if-youre-in-a-hurry">Quick Take (if you’re in a hurry)</h2>
<p>Key takeaways:</p>
<ul>
<li>Several new deep learning models show impressive performance compared to boosting, but context still matters.</li>
<li>It’s significantly easier to implement and experiment with modern tabular DL methods.</li>
<li>We now have more rigorous benchmarking environments with standardized datasets and evaluation protocols.</li>
<li>Foundation models for tabular data are emerging and have had success, but it’s a bit early to say how transformative they’ll be in practice.</li>
<li>For most practitioners: boosting remains the pragmatic baseline. However, you should start to consider DL methods if predictive performance is critical and you have the resources to invest in experimentation.</li>
</ul>

<div class="no-row-height column-margin column-container"><div class="margin-aside">
<p>Given the advances discussed here, I plan on adding a chapter devoted to tabular DL to the web edition of my book, <a href="https://m-clark.github.io/book-of-models/">Models Demystified</a>.</p>
</div></div><p>Now, let’s dig into the details.</p>
</section>
<section id="whats-changed-evaluation-and-accessibility" class="level2">
<h2 class="anchored" data-anchor-id="whats-changed-evaluation-and-accessibility">What’s Changed: Evaluation and Accessibility</h2>
<section id="better-evaluation-standards" class="level3">
<h3 class="anchored" data-anchor-id="better-evaluation-standards">Better Evaluation Standards</h3>
<p>One major improvement in tabular data modeling is the emergence of more rigorous benchmarking. <strong>TabArena</strong> (<a href="https://huggingface.co/spaces/TabArena/leaderboard">leaderboard</a>) and <a href="https://github.com/LAMDA-Tabular/TALENT">TALENT</a> provide standardized datasets, consistent evaluation metrics, and transparency in preprocessing, which addresses the apples-to-oranges comparison problems from earlier papers. TabArena, which will be the primary reference here, has set a new standard for evaluating tabular DL models with:</p>
<ul>
<li>A curated set of tabular datasets for binary/multiclass classification and regression tasks</li>
<li>Consistent evaluation metrics across different model types</li>
<li>A public leaderboard tracking model performance</li>
<li>Transparency in preprocessing and hyperparameter choices</li>
<li>Focus on heterogeneous datasets that better reflect real-world tabular data scenarios</li>
<li>Use of Elo-style model ranking for easier model comparisons</li>
</ul>
<p>These new benchmarks address one of the major frustrations from my previous post summaries: papers often used different datasets, preprocessing pipelines, and hyperparameter tuning budgets, which made fair comparisons difficult at best. They also often focused primarily on very homogeneous data, which isn’t representative of typical real-world tabular data, and sometimes focused only classification settings. This is a far better assessment, and gives us more confidence when comparing methods.</p>
</section>
<section id="current-leaderboard-landscape" class="level3">
<h3 class="anchored" data-anchor-id="current-leaderboard-landscape">Current Leaderboard Landscape</h3>
<p>As of March 2026, the TabArena leaderboard shows some interesting patterns. Here are the ELO rankings for tested models using default, tuned and tuned + ensembled versions of each model type:</p>
<div id="fig-TabArena" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-TabArena-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://m-clark.github.io/img/dl-foundational/tuning-impact-elo-2026-03-01.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-TabArena-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: TabArena Leaderboard
</figcaption>
</figure>
</div>
<p>The key insight from this is that some newer DL models are not only competitive with boosting, a few typically win in head-to-head comparisons against boosting models. For example, among the tuned + ensemble models the top 4 DL models win &gt; 50% of the time against LGBM, XGB, and CatBost.</p>
<div id="fig-h2h" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-h2h-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://m-clark.github.io/img/dl-foundational/h2h.png" class="img-fluid figure-img" style="width:80.0%">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-h2h-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Head-to-Head Model Comparisons
</figcaption>
</figure>
</div>
<p>One important side note: performance is typically not going to be statistically different for models that are similarly ranked, and papers will often provide something like a critical difference diagram to show this. So while the top 4 DL models are all ranked above the boosting models, that doesn’t necessarily mean they’re statistically better than boosting models.</p>
<p>Take the following image from the TabArena paper based on all datasets. It shows that the top six models, which includes the big 3 boosting models, are not statistically different from each other<sup>1</sup>.</p>
<div id="fig-cd" class="lightbox quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-cd-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="../../img/dl-foundational/critical_difference_tabarena.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1" title="Figure&nbsp;3: Critical Difference Diagram (Figure A.12 from the TabArena paper (2025))"><img src="https://m-clark.github.io/img/dl-foundational/critical_difference_tabarena.png" class="img-fluid figure-img" style="width:80.0%"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-cd-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: Critical Difference Diagram (Figure A.12 from the TabArena paper (2025))
</figcaption>
</figure>
</div>
</section>
<section id="practical-implementation-tools" class="level3">
<h3 class="anchored" data-anchor-id="practical-implementation-tools">Practical Implementation Tools</h3>
<p>The even bigger story is accessibility. Modern tools make it trivial to use these methods, so let’s try it out for ourselves!</p>
</section>
</section>
<section id="making-tabular-dl-practical" class="level2">
<h2 class="anchored" data-anchor-id="making-tabular-dl-practical">Making Tabular DL Practical</h2>
<section id="using-pytabkit" class="level3">
<h3 class="anchored" data-anchor-id="using-pytabkit">Using pytabkit</h3>
<p><a href="https://github.com/dholzmueller/pytabkit">pytabkit</a> provides implementations of state-of-the-art tabular DL models with:</p>
<ul>
<li>Optimized hyperparameter defaults based on extensive benchmarking</li>
<li>Unified API similar to scikit-learn</li>
<li>Automated preprocessing for heterogeneous data</li>
<li>Support for both classification and regression</li>
</ul>
<p>This is significant because one of the historical barriers to using tabular DL was implementation difficulty. While boosting modules were already easy to add to typical ML pipelines and often worked well out of the box, DL models often required custom code, careful tuning, and extensive experimentation to get good results.</p>
<p>Let’s see it in action with a simple example. We’ll generate a synthetic dataset with mixed numeric and categorical features, then train a RealMLP model and compare it to an XGBoost baseline.</p>
<div class="cell">
<details class="code-fold">
<summary>Show the code: Create Classification Data</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> pytabkit <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> RealMLP_TD_Classifier</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.datasets <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_classification</span>
<span id="cb1-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> accuracy_score, roc_auc_score, log_loss, f1_score</span>
<span id="cb1-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> StratifiedKFold</span>
<span id="cb1-7"></span>
<span id="cb1-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> string</span>
<span id="cb1-11"></span>
<span id="cb1-12"></span>
<span id="cb1-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generate a classification dataset</span></span>
<span id="cb1-14">X, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_classification(</span>
<span id="cb1-15">    n_samples<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5000</span>,</span>
<span id="cb1-16">    n_features<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>,</span>
<span id="cb1-17">    n_informative<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>,</span>
<span id="cb1-18">    n_redundant<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,</span>
<span id="cb1-19">    n_classes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb1-20">    random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>,</span>
<span id="cb1-21">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># make it a more difficult problem</span></span>
<span id="cb1-22">    flip_y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>,</span>
<span id="cb1-23">    class_sep<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>,</span>
<span id="cb1-24">    n_clusters_per_class<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,</span>
<span id="cb1-25">)</span>
<span id="cb1-26"></span>
<span id="cb1-27"></span>
<span id="cb1-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Convert to DataFrame for easier handling</span></span>
<span id="cb1-29">feature_names <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Feature_</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>i<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])]</span>
<span id="cb1-30">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(X, columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>feature_names)</span>
<span id="cb1-31"></span>
<span id="cb1-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add three categorical columns with 3, 5, and 12 categories, using letters as group names</span></span>
<span id="cb1-33">X[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cat_3'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.cut(X[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Feature_0'</span>], bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, labels<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(string.ascii_uppercase[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>])).astype(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'category'</span>)</span>
<span id="cb1-34">X[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cat_5'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.cut(X[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Feature_1'</span>], bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, labels<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(string.ascii_uppercase[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>])).astype(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'category'</span>)</span>
<span id="cb1-35">X[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cat_12'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.cut(X[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Feature_2'</span>], bins<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>, labels<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(string.ascii_uppercase[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>])).astype(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'category'</span>)</span>
<span id="cb1-36"></span>
<span id="cb1-37"></span>
<span id="cb1-38"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use a single train/test split</span></span>
<span id="cb1-39">X_train, X_test, y_train, y_test <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X, y, test_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>, stratify<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y)</span>
<span id="cb1-40"></span>
<span id="cb1-41"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Example CV splitter for pytabkit (if needed)</span></span>
<span id="cb1-42">cv_splitter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StratifiedKFold(n_splits<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, shuffle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>)</span>
<span id="cb1-43"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Get train/validation indices from the splitter</span></span>
<span id="cb1-44"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># X_val, y_val = X_train.iloc[val_idx], y_train[val_idx]</span></span>
<span id="cb1-45"></span>
<span id="cb1-46">val_idxs_list <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [val_idxs <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> train_idxs, val_idxs <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> cv_splitter.split(X_train, y_train)]</span>
<span id="cb1-47"></span>
<span id="cb1-48"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># make sure that each validation set has the same length, so we can exploit vectorization</span></span>
<span id="cb1-49">max_len <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>([<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(val_idxs) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> val_idxs <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> val_idxs_list])</span>
<span id="cb1-50">val_idxs_list <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [val_idxs[:max_len] <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> val_idxs <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> val_idxs_list]</span>
<span id="cb1-51">val_idxs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.asarray(val_idxs_list)</span>
<span id="cb1-52"></span>
<span id="cb1-53"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Train size: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X_train<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, Test size: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>X_test<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">, Baseline rate: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean(y)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
</details>
</div>
<p>With data in hand, we can train a RealMLP model.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">model_realmmlp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> RealMLP_TD_Classifier(</span>
<span id="cb2-2">    device<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mps'</span>,</span>
<span id="cb2-3">    random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb2-4">    n_cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb2-5">    val_metric_name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cross_entropy'</span>,</span>
<span id="cb2-6">    use_ls<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>,</span>
<span id="cb2-7">    verbosity<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># will show per epoch loss</span></span>
<span id="cb2-8">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># example modifications</span></span>
<span id="cb2-9">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># n_refit=1,</span></span>
<span id="cb2-10">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># n_repeats=1,</span></span>
<span id="cb2-11">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># n_epochs=256,</span></span>
<span id="cb2-12">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># batch_size=256,</span></span>
<span id="cb2-13">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># hidden_sizes=[256] * 3,</span></span>
<span id="cb2-14">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># lr=0.04,</span></span>
<span id="cb2-15">)</span>
<span id="cb2-16"></span>
<span id="cb2-17">model_realmmlp.fit(</span>
<span id="cb2-18">    X_train,</span>
<span id="cb2-19">    y_train,</span>
<span id="cb2-20">    val_idxs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>val_idxs,</span>
<span id="cb2-21">    cat_col_names<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cat_3'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cat_5'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cat_12'</span>]</span>
<span id="cb2-22">)</span></code></pre></div></div>
</div>
<p>On an old Macbook M1, this ran just at around one minute with the default 256 epochs, and it doesn’t look like we needed that many (Figure&nbsp;4). We definitely don’t need to sweat that kind of time on a dataset of this size regardless. Now let’s evaluate the model on the test set. Note that inference is near instant for this model.</p>
<div id="fig-RealMLPTraining" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-RealMLPTraining-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://m-clark.github.io/img/dl-foundational/realmmlp_training_plot.png" class="img-fluid figure-img" style="width:66.0%">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-RealMLPTraining-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4: RealMLP Training Log Loss
</figcaption>
</figure>
</div>
<div class="cell">
<details class="code-fold">
<summary>Show the code: Evaluate RealMLP</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_realmmlp.predict(X_test)</span>
<span id="cb3-2">y_proba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_realmmlp.predict_proba(X_test)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb3-3"></span>
<span id="cb3-4">metrics_realmlp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb3-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Accuracy"</span>: accuracy_score(y_test, y_pred),</span>
<span id="cb3-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ROC AUC"</span>: roc_auc_score(y_test, y_proba),</span>
<span id="cb3-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Log Loss"</span>: log_loss(y_test, y_proba),</span>
<span id="cb3-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"F1 Score"</span>: f1_score(y_test, y_pred)</span>
<span id="cb3-9">}</span>
<span id="cb3-10"></span>
<span id="cb3-11">metrics_realmlp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame(metrics_realmlp, index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RealMLP"</span>])</span>
<span id="cb3-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(metrics_realmlp)</span></code></pre></div></div>
</details>
</div>
<div class="cell plain">
<div class="cell-output-display">
<div id="hbnoemvcci" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#hbnoemvcci table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<table class="gt_table caption-top table" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="Accuracy" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">Accuracy</th>
<th id="ROC AUC" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">ROC AUC</th>
<th id="Log Loss" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">Log Loss</th>
<th id="F1 Score" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">F1 Score</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_right">0.772</td>
<td class="gt_row gt_right">0.838</td>
<td class="gt_row gt_right">0.505</td>
<td class="gt_row gt_right">0.767</td>
</tr>
</tbody>
</table>


</div>
</div>
</div>
<p>Now we can compare to XGBoost as the representative of the boosting approach. With pytabkit we can use default parameter settings derived from models used across a variety of data sets (<code>TD</code> = tuned defaults), making it easy to get started very well. Model training with data of this size took just a couple seconds.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> pytabkit <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> XGB_TD_Classifier</span>
<span id="cb4-2"></span>
<span id="cb4-3">model_xgb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> XGB_TD_Classifier(</span>
<span id="cb4-4">    device<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mps'</span>,</span>
<span id="cb4-5">    random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb4-6">    n_cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span></span>
<span id="cb4-7">)</span>
<span id="cb4-8"></span>
<span id="cb4-9">model_xgb.fit(</span>
<span id="cb4-10">    X_train,</span>
<span id="cb4-11">    y_train,</span>
<span id="cb4-12">    val_idxs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>val_idxs,</span>
<span id="cb4-13">    cat_col_names<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cat_3'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cat_5'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Cat_12'</span>]</span>
<span id="cb4-14">)</span></code></pre></div></div>
</div>
<div class="cell">
<details class="code-fold">
<summary>Show the code: Evaluate XGBoost</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_xgb.predict(X_test)</span>
<span id="cb5-2">y_proba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_xgb.predict_proba(X_test)[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb5-3"></span>
<span id="cb5-4">metrics_xgb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb5-5">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Accuracy"</span>: accuracy_score(y_test, y_pred),</span>
<span id="cb5-6">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ROC AUC"</span>: roc_auc_score(y_test, y_proba),</span>
<span id="cb5-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Log Loss"</span>: log_loss(y_test, y_proba),</span>
<span id="cb5-8">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"F1 Score"</span>: f1_score(y_test, y_pred)</span>
<span id="cb5-9">}</span></code></pre></div></div>
</details>
</div>
<div class="cell plain">
<div class="cell-output-display">
<div id="gvyofjttqr" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#gvyofjttqr table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<table class="gt_table caption-top table" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="Model" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Model</th>
<th id="Accuracy" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">Accuracy</th>
<th id="ROC AUC" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">ROC AUC</th>
<th id="Log Loss" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">Log Loss</th>
<th id="F1 Score" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">F1 Score</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left">XGB</td>
<td class="gt_row gt_right">0.752</td>
<td class="gt_row gt_right">0.824</td>
<td class="gt_row gt_right">0.567</td>
<td class="gt_row gt_right">0.750</td>
</tr>
<tr class="even">
<td class="gt_row gt_left">RealMLP</td>
<td class="gt_row gt_right">0.772</td>
<td class="gt_row gt_right">0.838</td>
<td class="gt_row gt_right">0.505</td>
<td class="gt_row gt_right">0.767</td>
</tr>
</tbody>
</table>


</div>
</div>
</div>
<p>While boosting performs well, in very little time we can get not only competitive but even better results with a modern DL approach. Of course, this is just one (simulated) dataset that shows how easy it is, but the TabArena results suggest this generalizes well beyond also. There we see that RealMLP is one of the top performers across a variety of datasets, and beats XGBoost in head-to-head comparisons more than 75% of the time (Figure&nbsp;2).</p>
</section>
<section id="even-easier-autogluon" class="level3">
<h3 class="anchored" data-anchor-id="even-easier-autogluon">Even Easier: AutoGluon</h3>
<p><a href="https://auto.gluon.ai/stable/index.html">AutoGluon</a> is a popular AutoML library that has recently added support for some of the newer tabular DL models, including many of those in pytabkit. This means you can get competitive performance with minimal code and tuning for multiple models, whether boosting, DL, or other approaches. Here we use 3 DL models and 3 boosting models<sup>2</sup>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> autogluon.tabular <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> TabularDataset, TabularPredictor</span>
<span id="cb6-2"></span>
<span id="cb6-3">X_train_ag <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> TabularDataset(X_train.assign(target<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y_train))</span>
<span id="cb6-4">X_test_ag <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> TabularDataset(X_test)</span>
<span id="cb6-5"></span>
<span id="cb6-6">model_ag <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (</span>
<span id="cb6-7">    TabularPredictor(label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'target'</span>, eval_metric<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'log_loss'</span>)</span>
<span id="cb6-8">    .fit(</span>
<span id="cb6-9">        X_train_ag,</span>
<span id="cb6-10">        num_bag_folds<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb6-11">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># num_bag_sets=1,</span></span>
<span id="cb6-12">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># num_stack_levels=0,</span></span>
<span id="cb6-13">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># you can set these and/or let AutoGluon search </span></span>
<span id="cb6-14">        hyperparameters<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{</span>
<span id="cb6-15">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'REALTABPFN-V2.5'</span>: {<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'device'</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mps'</span>},</span>
<span id="cb6-16">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'REALMLP'</span>: {},</span>
<span id="cb6-17">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TABM'</span>: {},</span>
<span id="cb6-18">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'GBM'</span>: {},</span>
<span id="cb6-19">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'XGB'</span>: {},</span>
<span id="cb6-20">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CAT'</span>: {},</span>
<span id="cb6-21">        },</span>
<span id="cb6-22">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># presets='best_quality', # multiple stacking, typically better performance</span></span>
<span id="cb6-23">                                  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># but much longer training time</span></span>
<span id="cb6-24">    )</span>
<span id="cb6-25">)</span></code></pre></div></div>
</div>
<div class="cell">
<details class="code-fold">
<summary>Show the code: AutoGluon Predictions</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_ag.predict(X_test_ag)</span>
<span id="cb7-2">y_proba <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_ag.predict_proba(X_test_ag).loc[:, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span></code></pre></div></div>
</details>
</div>
<p>One very nice aspect of AutoGluon is its easily accesible ‘leaderboard’ so you can compare and contrast your models immediately. The best non-ensemble model was RealTabPFN-v2.5. It also makes very clear just how much more time it took to get the best performance (in seconds), which is a lot. Whether it’s worth it will depend on your context.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">ag_leaderboard <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model_ag.leaderboard(X_test_ag.assign(target<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>y_test))</span></code></pre></div></div>
</div>
<div class="cell plain">
<div class="cell-output-display">
<div id="wrbslumaip" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#wrbslumaip table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<table class="gt_table caption-top table" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="model" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">model</th>
<th id="score_test" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">score_test</th>
<th id="score_val" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">score_val</th>
<th id="eval_metric" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">eval_metric</th>
<th id="pred_time_test" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">pred_time_test</th>
<th id="pred_time_val" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">pred_time_val</th>
<th id="fit_time" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">fit_time</th>
<th id="pred_time_test_marginal" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">pred_time_test_marginal</th>
<th id="pred_time_val_marginal" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">pred_time_val_marginal</th>
<th id="fit_time_marginal" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">fit_time_marginal</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left">WeightedEnsemble_L2</td>
<td class="gt_row gt_right">−0.858</td>
<td class="gt_row gt_right">−0.434</td>
<td class="gt_row gt_left">log_loss</td>
<td class="gt_row gt_right">128.79</td>
<td class="gt_row gt_right">450.09</td>
<td class="gt_row gt_right">451.64</td>
<td class="gt_row gt_right">0.00</td>
<td class="gt_row gt_right">0.00</td>
<td class="gt_row gt_right">0.06</td>
</tr>
<tr class="even">
<td class="gt_row gt_left">RealTabPFN-v2.5</td>
<td class="gt_row gt_right">−0.869</td>
<td class="gt_row gt_right">−0.434</td>
<td class="gt_row gt_left">log_loss</td>
<td class="gt_row gt_right">128.78</td>
<td class="gt_row gt_right">450.09</td>
<td class="gt_row gt_right">451.58</td>
<td class="gt_row gt_right">128.78</td>
<td class="gt_row gt_right">450.09</td>
<td class="gt_row gt_right">451.58</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left">XGBoost</td>
<td class="gt_row gt_right">−0.980</td>
<td class="gt_row gt_right">−0.505</td>
<td class="gt_row gt_left">log_loss</td>
<td class="gt_row gt_right">0.09</td>
<td class="gt_row gt_right">0.03</td>
<td class="gt_row gt_right">0.95</td>
<td class="gt_row gt_right">0.09</td>
<td class="gt_row gt_right">0.03</td>
<td class="gt_row gt_right">0.95</td>
</tr>
<tr class="even">
<td class="gt_row gt_left">LightGBM</td>
<td class="gt_row gt_right">−1.030</td>
<td class="gt_row gt_right">−0.498</td>
<td class="gt_row gt_left">log_loss</td>
<td class="gt_row gt_right">0.04</td>
<td class="gt_row gt_right">0.07</td>
<td class="gt_row gt_right">0.90</td>
<td class="gt_row gt_right">0.04</td>
<td class="gt_row gt_right">0.07</td>
<td class="gt_row gt_right">0.90</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left">CatBoost</td>
<td class="gt_row gt_right">−1.095</td>
<td class="gt_row gt_right">−0.487</td>
<td class="gt_row gt_left">log_loss</td>
<td class="gt_row gt_right">0.06</td>
<td class="gt_row gt_right">0.15</td>
<td class="gt_row gt_right">10.70</td>
<td class="gt_row gt_right">0.06</td>
<td class="gt_row gt_right">0.15</td>
<td class="gt_row gt_right">10.70</td>
</tr>
<tr class="even">
<td class="gt_row gt_left">TabM</td>
<td class="gt_row gt_right">−1.096</td>
<td class="gt_row gt_right">−0.488</td>
<td class="gt_row gt_left">log_loss</td>
<td class="gt_row gt_right">0.46</td>
<td class="gt_row gt_right">0.40</td>
<td class="gt_row gt_right">169.27</td>
<td class="gt_row gt_right">0.46</td>
<td class="gt_row gt_right">0.40</td>
<td class="gt_row gt_right">169.27</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left">RealMLP</td>
<td class="gt_row gt_right">−1.280</td>
<td class="gt_row gt_right">−0.483</td>
<td class="gt_row gt_left">log_loss</td>
<td class="gt_row gt_right">0.20</td>
<td class="gt_row gt_right">0.45</td>
<td class="gt_row gt_right">38.10</td>
<td class="gt_row gt_right">0.20</td>
<td class="gt_row gt_right">0.45</td>
<td class="gt_row gt_right">38.10</td>
</tr>
</tbody>
</table>


</div>
</div>
</div>
<p><br></p>
<p>Now let’s compare all our approaches. Standard XGB with tuned defaults did pretty well, but our RealMLP model did better, and AutoGluon did even better still in terms of loss.</p>
<div class="cell plain">
<div class="cell-output-display">
<div id="ggtvqslamz" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#ggtvqslamz table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<table class="gt_table caption-top table" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="Model" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" scope="col">Model</th>
<th id="Accuracy" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">Accuracy</th>
<th id="ROC AUC" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">ROC AUC</th>
<th id="Log Loss" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">Log Loss</th>
<th id="F1 Score" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" scope="col">F1 Score</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left">XGB</td>
<td class="gt_row gt_right">0.752</td>
<td class="gt_row gt_right">0.824</td>
<td class="gt_row gt_right">0.567</td>
<td class="gt_row gt_right">0.750</td>
</tr>
<tr class="even">
<td class="gt_row gt_left">RealMLP</td>
<td class="gt_row gt_right">0.772</td>
<td class="gt_row gt_right">0.838</td>
<td class="gt_row gt_right">0.505</td>
<td class="gt_row gt_right">0.767</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left">AutoGluon</td>
<td class="gt_row gt_right">0.798</td>
<td class="gt_row gt_right">0.865</td>
<td class="gt_row gt_right">0.464</td>
<td class="gt_row gt_right">0.793</td>
</tr>
</tbody>
</table>


</div>
</div>
</div>
<p>Note that a fairer comparison would be to give the boosting and RealMLP models the same HPO/ensembling treatment, which is just as easy by using the <code>*_HPO_Classifier</code> versions of those models in pytabkit, and would likely improve their performance as well. However, I wanted to show the performance you can get with the viable defaults that would still be quick to train.</p>
</section>
</section>
<section id="performance-factors-and-practical-guidance" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="performance-factors-and-practical-guidance">Performance Factors and Practical Guidance</h2>
<p>Understanding when different models excel requires examining how dataset characteristics relate to performance.</p>
<section id="what-the-data-shows" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="what-the-data-shows">What the Data Shows</h3>
<p>TabArna shows improvability plot showing how models benefit from additional compute, though it conflates dataset characteristics in ways that make it difficult to isolate individual effects. The key insight: <strong>compute investment returns vary dramatically by model type</strong>. Some DL models may start well and plateau quickly (TabPFN-v2.5), others improve consistently with more training (REALMLP, TABM). Boosting methods show more modest gains, which may reflect their already strong performance with default settings, and they take much less time to train<sup>3</sup>.</p>
<div id="fig-improvability-tab-arena" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-improvability-tab-arena-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://m-clark.github.io/img/dl-foundational/pareto_n_configs_imp_2026-03-01.png" class="img-fluid figure-img" style="width:80.0%">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-improvability-tab-arena-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;5: Improvability vs.&nbsp;Train Time (TabArena Early 2026)
</figcaption>
</figure>
</div>
<p>The TabArena paper provides tabled performance metrics across all datasets for the models available when published. Looking more closely at how sample size, features, and categorical density relate to performance we see:</p>
<ul>
<li>Increased sample/feature count correlates with better boosting performance (primarily categorical targets, default parameters)</li>
<li>Categorical feature percentage shows mixed effects across target types</li>
<li>For multiclass targets, increased features particularly benefit DL models</li>
<li>Default settings benefit more from increased data</li>
</ul>
<div id="fig-improvability-sample-size" class="lightbox quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-improvability-sample-size-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="../../img/dl-foundational/improvability_correlation_annotation.png" class="lightbox" data-gallery="quarto-lightbox-gallery-2" title="Figure&nbsp;6: Improvability vs.&nbsp;Data Characteristics"><img src="https://m-clark.github.io/img/dl-foundational/improvability_correlation_annotation.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-improvability-sample-size-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;6: Improvability vs.&nbsp;Data Characteristics
</figcaption>
</figure>
</div>

<div class="no-row-height column-margin column-container"><div class="margin-aside">
<p>There are notable limitations to this analysis. To begin, it’s based on aggregate scores reported in the TabArena paper (averaged across multiple runs), and that uncertainty isn’t reflected. Additionally, the analysis groups models post-hoc (e.g., “DL” vs “boosting”) and focuses on top performers rather than all tested models. The correlations shown are exploratory and shouldn’t be interpreted as causal relationships between data characteristics and model performance. And finally, that paper did not include TabICL-v2 or TabPFN-v2.5.</p>
</div></div><p><strong>Target type considerations:</strong></p>
<ul>
<li>Binary: DL typically edges out boosting, but requires ensembling to do so</li>
<li>Multiclass: DL (mostly TabPFN-v2.5) shows consistent advantages</li>
<li>Numeric: Boosting gains ground, may match/exceed DL for tuned models, but DL still has strong showings, especially with more features</li>
</ul>
<div id="fig-performance-by-target-type" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-performance-by-target-type-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://m-clark.github.io/img/dl-foundational/model_performance_by_target_type.png" class="img-fluid figure-img" style="width:80.0%">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-performance-by-target-type-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;7: Performance by Target Type
</figcaption>
</figure>
</div>
<p>The overall takeaway: <strong>data nuances matter, and empirical testing beats general rules</strong>.</p>
</section>
<section id="making-the-decision" class="level3">
<h3 class="anchored" data-anchor-id="making-the-decision">Making the Decision</h3>
<p>Given these performance patterns, here’s how to approach model selection based on your practical constraints:</p>
<p><strong>Boosting as the baseline:</strong> Tree-based methods (XGBoost, LightGBM, CatBoost) work well across all data sizes, are computationally efficient, and all packages support GPU for even faster training. And when it comes to inference efficiency, they are still the ones to beat (Figure&nbsp;8). As another baseline alternative, statistical models<sup>4</sup> remain viable for millions of samples with interpretability needs.</p>
<p><strong>Consider DL when you have the resources and performance matters:</strong></p>
<ul>
<li><p><strong>Small data (&lt;10k rows)</strong>: Some DL models excel if compute permits. Otherwise boosting/statistical models work fine.</p></li>
<li><p><strong>Small to medium data (~10k-100k rows)</strong>: TabPFN-v2.5, RealMLP, TabICL-v2 frequently outperform boosting. Worth trying if:</p>
<ul>
<li>Performance gains matter more than training time</li>
<li>GPU resources available</li>
<li>Model retraining is infrequent</li>
</ul></li>
<li><p><strong>Medium to large data (~100k-1M rows)</strong>: TabICL-v2 can beat boosting but requires significant compute. Consider it only if:</p>
<ul>
<li>You need the absolute best performance</li>
<li>Computational cost is acceptable</li>
<li>You have infrastructure to support it</li>
</ul></li>
<li><p><strong>Very large data (&gt;1M rows)</strong>: Boosting is your primary choice. Few DL models scale well to this level. But keep an eye on this, particularly with the recent success of TabICL-v2 on larger datasets.</p></li>
</ul>
<p>Tools like pytabkit and AutoGluon make experimentation straightforward enough to test on your own data, especially if you’re already using boosting and want to explore potential performance gains.</p>
</section>
</section>
<section id="looking-ahead-foundation-models-for-tabular-data" class="level2">
<h2 class="anchored" data-anchor-id="looking-ahead-foundation-models-for-tabular-data">Looking Ahead: Foundation Models for Tabular Data</h2>
<section id="the-promise" class="level3">
<h3 class="anchored" data-anchor-id="the-promise">The Promise</h3>
<p>Recent work has explored pre-training models on large collections of tabular datasets and/or synthetic data, then fine-tuning for specific tasks. This is similar to the paradigm that revolutionized NLP and vision. But do they work?</p>
<p>The idea is that just like in other domains, we can leverage large amounts of tabular data to learn generalizable representations that can be fine-tuned for specific tasks. This could potentially allow us to:</p>
<ul>
<li>Achieve better performance with less task-specific data</li>
<li>Handle heterogeneous features more effectively</li>
<li>Enable zero-shot or few-shot learning on new tabular tasks</li>
</ul>
<p>Key models include TabPFN, Mitra (Amazon), TabICL, and others.</p>
</section>
<section id="the-reality" class="level3">
<h3 class="anchored" data-anchor-id="the-reality">The Reality</h3>
<p>Results are hit and miss. Some foundation models obviously do well when we look at the leaderboard… if the data is not large, with some even restricted to smaller sizes. Note that TabArena dataset sizes max out at 150k, which is considered ‘medium’ size. Even then, training and inference time may be prohibitive in many cases. Right now you could use MLP approaches like TabM and RealMLP with faster yet comparable results. But more to the point, it is <em>very</em> common in the tabular domain to see much larger datasets, and boosting models are still working fine even with millions of rows, and can utilize GPUs as well.</p>
</section>
</section>
<section id="what-id-still-like-to-see" class="level2">
<h2 class="anchored" data-anchor-id="what-id-still-like-to-see">What I’d Still Like to See</h2>
<p>Reflecting on my 2022 wishlist what progress has been made and what is still missing:</p>
<p><strong>Progress made:</strong></p>
<ul>
<li>✅ Better implementation tools</li>
<li>✅ Standardized benchmarking</li>
<li>✅ More rigorous/realistic comparisons</li>
</ul>
<p><strong>Would like more:</strong></p>
<ul>
<li>❌ Clearer guidance on when complexity pays off: winning is not enough, especially if not statistically better than several other models, some of which would be faster to train.</li>
<li>❌ Minor: Better/automatic handling of missing data: tool implementation if present at all is pretty basic<sup>5</sup>. Not as much an issue for tree-based models, but still one for DL models.</li>
<li>❌ Very minor: comparisons with better statistical models than simple linear (e.g., GAMM that can model nonlinear relationships)</li>
</ul>
<p>I think the biggest issue is a breakdown of specific data characteristics and how they relate to model performance, if they do consistently. Computational efficiency <em>in general</em> is certainly worth focusing on primarily, but practitioners need to know ‘is my data too large for spending time for this model?’ or ‘is my target/feature combination going to result in less performance’<sup>6</sup>. I can appreciate the difficulty in addressing this in a simple fashion, it may not even be possible. I made an effort to illuminate some of this above, but I had to use secondary sources and aggregation that may not be the most accurate reflection. But if there are trends, a clearer delineation of these relationships would be very helpful for practitioners trying to decide which type of model to use for their context.</p>
</section>
<section id="conclusion" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>Four years ago I concluded that DL wasn’t ready for most tabular tasks. Today, the tabular DL landscape has matured considerably. We have better benchmarks, better tools, and a little bit better understanding of where these methods excel. So today the answer is more nuanced: <strong>DL models now regularly outperform boosting on realistic benchmarks, but the conditions under which they excel aren’t always clearcut.</strong></p>
<p>The TabArena results show that modern DL models (TabPFN-v2.5, RealMLP, TabICL-v2) often win head-to-head comparisons against boosting. However, examining when and why reveals considerable complexity:</p>
<ul>
<li>Performance advantages vary by dataset size, target type, and feature characteristics</li>
<li>The relationships between data properties and model performance are not clear-cut</li>
<li>Computational costs (training time, memory) can be much higher for only modest performance gains</li>
<li>Most benchmark datasets remain &lt;150k rows, while production data is often much larger</li>
</ul>

<div class="no-row-height column-margin column-container"><div class="margin-aside">
<p>Bear in mind, even a linear model still beats even DL models 5-10% of the time, so you just never know.</p>
</div></div><p>In general:</p>
<p><strong>XGBoost and friends remain the pragmatic starting point</strong> for most tabular work. They’re fast, well-understood, GPU-enabled, and work well across diverse problem types and data sizes.</p>
<p><strong>DL methods are now genuinely competitive</strong>. However, as they often require more resources to implement effectively, it will be important to consider the specific context of your problem. For smaller datasets or when chasing that last bit of performance, DL models like TabICL and RealMLP can be a great choice.</p>
<p>The “all you need” framing misses the point. The real question is: <strong>“What trade-offs are acceptable for your specific problem?”</strong> Performance vs.&nbsp;speed? Predictive accuracy vs.&nbsp;interpretability? Computational cost vs.&nbsp;marginal gains?</p>
<p>In 2026, we have better tools to explore those questions. Tools like pytabkit and AutoGluon make it straightforward, and the benchmarks provide valuable guidance. But they can’t tell you whether a 2% performance improvement is worth 10x longer training for your particular use case.</p>
<p>Foundation models represent an exciting direction, but almost all currently remain limited by data size constraints and computational costs. The rapid progress suggests checking back in another year might reveal more practical options. For now, start with boosting, experiment with DL if resources permit, and let your context guide your modeling decision.</p>
</section>
<section id="extra-stuff" class="level2">
<h2 class="anchored" data-anchor-id="extra-stuff">Extra Stuff</h2>
<section id="previous-posts-in-this-series" class="level4">
<h4 class="anchored" data-anchor-id="previous-posts-in-this-series">Previous posts in this series</h4>
<ul>
<li><a href="../2021-07-15-dl-for-tabular/">This is definitely not all you need (2021)</a></li>
<li><a href="../2022-04-01-more-dl-for-tabular/">Deep Learning for Tabular Data (2022)</a></li>
</ul>
</section>
<section id="papers-and-other-resources" class="level4">
<h4 class="anchored" data-anchor-id="papers-and-other-resources">Papers and other resources</h4>
<ul>
<li><a href="https://huggingface.co/spaces/TabArena/leaderboard">TabArena Leaderboard</a></li>
<li><a href="https://arxiv.org/abs/2506.16791">TabArena Paper</a></li>
<li><a href="https://github.com/dholzmueller/pytabkit">pytabkit GitHub</a></li>
<li><a href="https://arxiv.org/abs/2407.00956">TALENT Paper</a></li>
<li><a href="https://mindfulmodeler.substack.com/p/the-state-of-tabular-foundation-models">The State of Tabular Foundation Models</a></li>
</ul>
</section>
<section id="comparison-of-some-current-dl-tabular-models" class="level4">
<h4 class="anchored" data-anchor-id="comparison-of-some-current-dl-tabular-models">Comparison of some current DL Tabular models</h4>
<table class="caption-top table">
<colgroup>
<col style="width: 15%">
<col style="width: 18%">
<col style="width: 18%">
<col style="width: 20%">
<col style="width: 14%">
<col style="width: 13%">
</colgroup>
<thead>
<tr class="header">
<th>Feature</th>
<th>TabPFN v2.5</th>
<th>TabICL-v2</th>
<th>TabDPT</th>
<th>TabM</th>
<th>RealMLP</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Model Type</td>
<td>Foundation (TFM)</td>
<td>Foundation (TFM)</td>
<td>Foundation (TFM)</td>
<td>Ensemble* (MLP)</td>
<td>Enhanced (MLP)</td>
</tr>
<tr class="even">
<td>Paradigm</td>
<td>In-Context Learning</td>
<td>In-Context Learning</td>
<td>In-Context Learning</td>
<td>Supervised</td>
<td>Supervised</td>
</tr>
<tr class="odd">
<td>Pre-training</td>
<td>Synthetic Data</td>
<td>Synthetic Data+</td>
<td>Real Data (SSL)</td>
<td>N/A</td>
<td>N/A</td>
</tr>
<tr class="even">
<td>Max Samples</td>
<td>~50,000</td>
<td>1,024,000+</td>
<td>~2,048 (context length)</td>
<td>Unlimited (batch)</td>
<td>Unlimited (batch)</td>
</tr>
<tr class="odd">
<td>Key Advantage</td>
<td>No tuning required</td>
<td>Speed &amp; Scale</td>
<td>Missing data robustness</td>
<td>Ensemble power</td>
<td>Strong baseline</td>
</tr>
</tbody>
</table>
<ul>
<li>TFM: Tabular Foundation Model</li>
<li>MLP: Multi-Layer Perceptron</li>
<li>Ensemble*: TabM is an efficient imitation of an ensemble of MLPs, but is not itself an ensemble model in the traditional sense.</li>
<li>Synthetic Data+: Pre-trained on synthetic data, but also augmented with real data during training</li>
<li>SSL: Self-Supervised Learning</li>
</ul>
</section>
<section id="elo-vs.-inference-time" class="level4">
<h4 class="anchored" data-anchor-id="elo-vs.-inference-time">Elo vs.&nbsp;Inference Time</h4>
<p>The following shows that when it comes to inference time, boosting holds a clear advantage, but MLP models are also good. This advantage is lessened for ensemble approaches, where DL models also gain more in terms of improvability.</p>
<div id="fig-elo-inf" class="lightbox quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-elo-inf-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="../../img/dl-foundational/elo_vs_inference_time.png" class="lightbox" data-gallery="quarto-lightbox-gallery-3" title="Figure&nbsp;8: Elo vs.&nbsp;Inference Time for Selected Models (TabArena Early 2026)"><img src="https://m-clark.github.io/img/dl-foundational/elo_vs_inference_time.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-elo-inf-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;8: Elo vs.&nbsp;Inference Time for Selected Models (TabArena Early 2026)
</figcaption>
</figure>
</div>
<div id="fig-improve-inf" class="lightbox quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-improve-inf-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="../../img/dl-foundational/inference_vs_improvability.png" class="lightbox" data-gallery="quarto-lightbox-gallery-4" title="Figure&nbsp;9: Improvability vs Inference Time (TabArena Early 2026)"><img src="https://m-clark.github.io/img/dl-foundational/inference_vs_improvability.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-improve-inf-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;9: Improvability vs Inference Time (TabArena Early 2026)
</figcaption>
</figure>
</div>
</section>
</section>
<section id="references" class="level2">




</section>


<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-erickson2025tabarenalivingbenchmarkmachine" class="csl-entry">
Erickson, Nick, Lennart Purucker, Andrej Tschalzev, et al. 2025. <em>TabArena: A Living Benchmark for Machine Learning on Tabular Data</em>. <a href="https://arxiv.org/abs/2506.16791">https://arxiv.org/abs/2506.16791</a>.
</div>
<div id="ref-gorishniy2025tabmadvancingtabulardeep" class="csl-entry">
Gorishniy, Yury, Akim Kotelnikov, and Artem Babenko. 2025. <em>TabM: Advancing Tabular Deep Learning with Parameter-Efficient Ensembling</em>. <a href="https://arxiv.org/abs/2410.24210">https://arxiv.org/abs/2410.24210</a>.
</div>
<div id="ref-TabPFN-2.5" class="csl-entry">
Grinsztajn, Léo, Klemens Flöge, Oscar Key, et al. 2025. <em>TabPFN-2.5: Advancing the State of the Art in Tabular Foundation Models</em>. <a href="http://arxiv.org/abs/2511.08667">http://arxiv.org/abs/2511.08667</a>.
</div>
<div id="ref-holzmüller2025betterdefaultstrongpretuned" class="csl-entry">
Holzmüller, David, Léo Grinsztajn, and Ingo Steinwart. 2025. <em>Better by Default: Strong Pre-Tuned MLPs and Boosted Trees on Tabular Data</em>. <a href="https://arxiv.org/abs/2407.04491">https://arxiv.org/abs/2407.04491</a>.
</div>
<div id="ref-qu2026tabiclv2betterfasterscalable" class="csl-entry">
Qu, Jingang, David Holzmüller, Gaël Varoquaux, and Marine Le Morvan. 2026. <em>TabICLv2: A Better, Faster, Scalable, and Open Tabular Foundation Model</em>. <a href="https://arxiv.org/abs/2602.11139">https://arxiv.org/abs/2602.11139</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>The TabArena paper, which lags the website, does not include TabPFN-v2.5 or TabICL-v2, which are both top performers now. While it did include TabPFN-v2, that model is not applicable to larger datasets, and the image only includes models that were tested on all datasets, so doesn’t include it.↩︎</p></li>
<li id="fn2"><p>Amazon provides its own tabular foundation model Mitra, but it wouldn’t run due to memory issues on my old machine.↩︎</p></li>
<li id="fn3"><p>TabArena also shows inference time vs.&nbsp;improvability, which is important for production use. But if inference time is at all a concern, such as in real-time applications, you likely won’t use any model that can’t deliver nearly that. If it’s not a concern, then the differences among the best DL/boosting models probably won’t matter much to you.↩︎</p></li>
<li id="fn4"><p>By statistical models I mean models from the traditional statistical modeling tradition that emphasize understanding relationships and quantifying uncertainty, like generalized linear, additive, and mixed models, etc. These are often implemented in packages like statsmodels in Python or throughout the R ecosystem. They typically provide interpretable parameters, standard errors, and hypothesis testing frameworks, though they may not always achieve the same predictive performance as more flexible machine learning models.↩︎</p></li>
<li id="fn5"><p>AutoGluon has some support for missing data, but is mostly relying on boosting splits on missing values with ensembled models. For DL models, it appears to be basically mean imputation for numeric features, adding a missing label for categorical features, and just dropping samples with missing data on the target.↩︎</p></li>
<li id="fn6"><p>I think some of the datasets may be overkill with the number of features, and may not be indicative of typical tabular settings. I’ve consulted across dozens of industries and academic disciplines, and the most I’ve ever had for a tabular model where the data was truly heterogeneous was a little over 100. The reason for this, and other times where the number of features was several dozen or so, was mostly due to the client not having the domain knowledge to do initial feature selection (IIRC, the actual useful number was &lt; 10). The problem is that in the tabular domain, adding more features typically adds noise and redundancy rather than value. Needing hundreds for a particular problem with no obvious reduction is likely very domain specific, where features are all of the same type (e.g.&nbsp;biological data). In those cases, I would suspect DL modeling approaches, even those from non-tabular domains, would do well with such data.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2026,
  author = {Clark, Michael},
  title = {Is {Boosting} {Still} {All} {You} {Need} for {Tabular}
    {Data?}},
  date = {2026-03-01},
  url = {https://m-clark.github.io/posts/2026-03-01-dl-for-tabular-foundational/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2026" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2026. <span>“Is Boosting Still All You Need for Tabular
Data?”</span> March 1. <a href="https://m-clark.github.io/posts/2026-03-01-dl-for-tabular-foundational/">https://m-clark.github.io/posts/2026-03-01-dl-for-tabular-foundational/</a>.
</div></div></section></div> ]]></description>
  <category>deep learning</category>
  <category>machine learning</category>
  <category>boosting</category>
  <guid>https://m-clark.github.io/posts/2026-03-01-dl-for-tabular-foundational/</guid>
  <pubDate>Sun, 01 Mar 2026 05:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/dl-foundational/iclv2arch.png" medium="image" type="image/png" height="149" width="144"/>
</item>
<item>
  <title>My Book is Out!</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2025-08-15-models-demystified/</link>
  <description><![CDATA[ 





<p>My book, <em>Models Demystified: A Practical Guide from Linear Regression to Deep Learning</em>, co-authored with Seth Berry, is now published! It was a long journey, but we’re excited to share it with you. We started in mid-2023 with the goal of ending by the end of that year. That naivety was quickly dashed, but we ended up with a much more comprehensive book than we originally planned when all was said and done. Since we started, the AI boom has continued to explode, modeling techniques have advanced, and I also ended up becoming a father - a notably greater accomplishment than this book! 😄 While many things have changed, we hope the book finds you well and helps you understand the models that power the world around you. Have fun!</p>
<ul>
<li><p>📖 Print version: available at <a href="https://www.routledge.com/Models-Demystified-A-Practical-Guide-from-Linear-Regression-to-Deep-Learning/Clark-Berry/p/book/9781032582580">Routledge/CRC Press</a></p></li>
<li><p>🌐 Web version: <a href="https://m-clark.github.io/book-of-models/">https://m-clark.github.io/book-of-models/</a></p></li>
<li><p>🐙 <a href="https://github.com/m-clark/book-of-models">Book GitHub Repo</a></p></li>
<li><p>📖 <a href="https://m-clark.github.io/book-of-models/">Book webpage</a> (I’ll likely update any progression there)</p></li>
</ul>



<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2025,
  author = {Clark, Michael},
  title = {My {Book} Is {Out!}},
  date = {2025-08-15},
  url = {https://m-clark.github.io/posts/2025-08-15-models-demystified/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2025" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2025. <span>“My Book Is Out!”</span> August 15. <a href="https://m-clark.github.io/posts/2025-08-15-models-demystified/">https://m-clark.github.io/posts/2025-08-15-models-demystified/</a>.
</div></div></section></div> ]]></description>
  <category>miscellaneous</category>
  <guid>https://m-clark.github.io/posts/2025-08-15-models-demystified/</guid>
  <pubDate>Fri, 15 Aug 2025 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/gp_bc_for_website_bottom_text.svg" medium="image" type="image/svg+xml"/>
</item>
<item>
  <title>Uncertainty Estimation with Conformal Prediction</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2025-06-01-conformal/</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>As with the <a href="https://m-clark.github.io/posts/2025-04-07-class-imbalance/">last post on class imbalance</a>, this is a resurrection of sorts. I began this post a little after that one had gotten an initial draft completed. Since then, conformal prediction has caught on quite a bit, but there wasn’t much at the time in terms of tools. I was focused on MAPIE as that’s a good package in Python, and as I was writing this, <span class="pack">probably</span> finally offered something more viable in R. I definitely recommend R folks to check it out.</p>
</blockquote>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>Uncertainty estimation is a crucial component of machine learning systems. It is vital to know how precise our model predictions are, and whether we feel confident in taking action based on them. While typical usage of prediction and performance is often done with little consideration of uncertainty, we do so at our own (very predictable) peril. Here we will discuss uncertainty in the context of prediction, and how we can estimate it using several methods. We will focus especially on conformal prediction, a tried but relatively newer approach to uncertainty estimation that has several advantages. This post covers:</p>
<ol type="1">
<li><strong>Why Uncertainty Estimation is Important</strong>: We’ll discuss why uncertainty estimation is important and how it can be used to make better decisions.</li>
<li><strong>Approaches to Uncertainty Estimation</strong>: We’ll discuss different approaches to uncertainty estimation, including statistical prediction intervals, bootstrapping, Bayesian approaches, and conformal prediction.</li>
<li><strong>Example</strong>: We’ll demonstrate how to use conformal prediction to estimate uncertainty in a simple example to help demystify the process.</li>
<li><strong>Pros and Cons</strong>: We’ll discuss the advantages and disadvantages of different approaches to uncertainty estimation.</li>
</ol>
</section>
<section id="why-is-uncertainty-estimation-important" class="level2">
<h2 class="anchored" data-anchor-id="why-is-uncertainty-estimation-important">Why is Uncertainty Estimation Important?</h2>
<p>Uncertainty estimation is an indispensable part of our modeling endeavor, and <em>one of the main reasons is that it allows us to make better decisions from our data</em>. The more we understand our predictions, the more we can feel confident in taking action based on them. Understanding uncertainty can also help us understand the model itself, and especially where its weaknesses are, or at what points we should be more cautious.</p>
<p>For example, if we are building a model to predict the number of sales for a product, we would like to better assess our prediction of future sales in order to take current action. This could be increasing our marketing budget for the months ahead, or possibly assessing whether current marketing strategies have been successful. Our model may predict that we can expect an increase in sales of 150 units with the increased budget of 5%. If the range for the prediction is that the expected sales increase six months from now is between 100 and 200 units, we might make a different decision than if we expect the unit sales to be between -100 and 400 units. In the first case, we might be more willing to increase our budget spend, since it seems we are likely to experience an increase in sales by doing so. In the second case, we might not take any action, since the range encompasses anywhere between lost sales to an even larger boost.</p>
<p>The following illustrates the issue. The prediction on the left suggests less value and has notable uncertainty with that assessment. That might be easy to rule out. But the other two predictions take some thought. One is higher with less uncertainty, while the other prediction is slightly lower, but with more uncertainty that suggests the upside might be greater. Which would you prefer?</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2025-06-01-conformal/index_files/figure-html/uncertainty-plot-1.png" class="img-fluid figure-img" width="768"></p>
</figure>
</div>
</div>
</div>
<p>Many times stakeholders will take action given the prediction alone, and then are disappointed when things don’t turn out as expected, which they definitely will not in practice. In similar fashion, some take action based on rankings of the predictions, which of course themselves have uncertainty that stems from the raw prediction, and even more so. In some situations, we may be able to get away with doing so, but it would be difficult to know this ahead of time. The old adage of not wanting to put all your eggs in one (prediction) basket applies here.</p>
<!-- TODO: generic pointrange type of plot with question marks -->
<section id="contributing-factors" class="level3">
<h3 class="anchored" data-anchor-id="contributing-factors">Contributing Factors</h3>
<p>Several key factors contribute to prediction uncertainty, among them:</p>
<ul>
<li><p><strong>Amount of Data</strong>: While more data can lead us to feel more confident about predictions in a general sense by providing additional learning examples of varying kinds, this is limited. Additional bad or uninformative data will not improve a model or its predictions!</p></li>
<li><p><strong>Model Complexity</strong>: More complex models may capture nuanced relationships leading to better predictions, but can also introduce instability in those predictions if additional steps aren’t taken. Conversely, having too simple a model yields relatively poor predictions in general.</p></li>
<li><p><strong>Precision of Measurement</strong>: The quality of the data collection process definitely impacts any predictions we might ultimately make. For example, if sales are entered with possible error, or a lag for some reporting units and not for others, this can lead to uncertainty in our predictions of future sales. In addition, the precision of measurement can vary across features. For example, if price is a feature, it may be that price fluctuates within a month but sales are recorded for a month, meaning we might have to take an average or other measure of price.</p></li>
</ul>
<p>So any number of things might contribute to the uncertainty in our predictions and, in general, some aspects contributing to prediction uncertainty may be under our control, while others may not be. Different methods produce different results, and some intervals may be too narrow or too wide in some settings, giving false confidence or excessive caution. In what follows, we’ll explore various uncertainty estimation approaches with a focus on <strong>conformal prediction</strong>, demonstrating its implementation and comparing its advantages to alternative methods. We’ll start by discussing the importance of uncertainty estimation and the different approaches to it. Next, we will discuss conformal prediction and show a simple demonstration of how it can be used to estimate uncertainty. Finally, we will discuss the advantages and disadvantages of conformal prediction compared to other approaches to uncertainty estimation.</p>
<div class="callout callout-style-default callout-tip callout-titled" title="Confidence is not Certainty">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Tip</span>Confidence is not Certainty
</div>
</div>
<div class="callout-body-container callout-body">
<p>It’s crucial to understand that <em>confidence</em> in terms of confidence intervals is not the same concept as <em>certainty</em>. The same level of confidence interval, say 95%, can produce different interval widths across models for the same prediction, and across predictions for the same model/data. Certainty reflects our understanding about the range provided by a confidence interval, and, for a given setting, we have less uncertainty with narrower intervals than wider ones.</p>
</div>
</div>
</section>
</section>
<section id="strategies-for-quantifying-uncertainty" class="level2">
<h2 class="anchored" data-anchor-id="strategies-for-quantifying-uncertainty">Strategies for Quantifying Uncertainty</h2>
<p>There are several approaches to uncertainty estimation, and many different things we can calculate uncertainty for. We’ll focus specifically on uncertainty for predictions, and we’ll briefly describe and demonstrate some of the different ways of getting an uncertainty estimate for those.</p>
<section id="statistical-uncertainty" class="level3">
<h3 class="anchored" data-anchor-id="statistical-uncertainty">Statistical Uncertainty</h3>
<p><img src="https://latex.codecogs.com/png.latex?y%20%5Csim%20%5Cmathcal%7BN%7D(%5Cmu,%20%5Csigma%5E2)"></p>
<p>Probably the most common approach to estimate uncertainty is to use a statistical model. Given a statistical distribution and the estimated parameters of the model, we can get a sense of uncertainty in the prediction. For example, let’s say we have a standard linear regression model. In that case, we are assuming the data generating process for the target/outcome is a normal distribution. The mean for that distribution comes from our model via the linear combination of features, and the variance is estimated separately<sup>1</sup>. Given those and other model-specific assumptions hold (e.g.&nbsp;homoscedasticity, independence of observations), we can then obtain an interval estimate for a prediction, typically using a standard formula. This approach extends well beyond both linear regression and the normal distribution, but the basic idea is the same. We assume a distribution for the target, estimate the parameters of that distribution via the data, and then use those estimates to ultimately obtain an interval estimate for our prediction.</p>
<!---
 The following shows how the prediction interval for an unseen observation is constructed:

$$
\hat{y} \pm t_{\alpha/2, n-2} \hat{\sigma} \sqrt{1 + \frac{1}{n} + \frac{(x - \bar{x})^2}{\sum_{i=1}^n (x_i - \bar{x})^2}}
$$ 

where $\hat{y}$ is the predicted value, $t_{\alpha/2, n-2}$ is the critical value of the t-distribution with $n-2$ degrees of freedom, $\hat{\sigma}$ is the standard error of the regression, $x$ is the value of the predictor, and $\bar{x}$ is the mean of the predictor. 
--->
<div class="callout callout-style-default callout-tip callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Tip
</div>
</div>
<div class="callout-body-container callout-body">
<p>We can contrast the <em>prediction interval</em> versus a <a href="https://stats.stackexchange.com/questions/16493/difference-between-confidence-intervals-and-prediction-intervals">confidence interval for a prediction</a>, i.e., for the prediction for an *average response*. The latter will always be smaller, as it reflects the uncertainty in the mean of the distribution of predictions, rather than the uncertainty in the predicted value for a *new* observation, which is what the prediction interval regards.</p>
</div>
</div>
</section>
<section id="bootstrapping" class="level3">
<h3 class="anchored" data-anchor-id="bootstrapping">Bootstrapping</h3>
<div class="cell">
<div class="cell-output-display">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2025-06-01-conformal/index_files/figure-html/boot-r-1.png" class="img-fluid figure-img" style="width:66.0%"></p>
<figcaption>Bootstrap Resampling Visualization</figcaption>
</figure>
</div>
</div>
</div>
<p>Bootstrapping is another technique for estimating uncertainty in machine learning models. By repeatedly resampling our original dataset with replacement, we create multiple versions of our data that capture its inherent variability. This process mirrors what would happen if we could collect many different samples from the population. Each resampled dataset produces slightly different model parameters, and consequently, different predictions for the same input. The variation across these predictions directly quantifies our uncertainty - wider spread indicating higher uncertainty, narrower spread suggesting more confidence.</p>
<p>Think of it this way – we take our data, resample the observations with replacement, and train a new model on the resampled data. We then use the new model to make predictions on the original or new/test data. Now we do that many times, taking the average for our final prediction. We then use the quantiles of the prediction distribution (e.g.&nbsp;corresponding to the 5th and 95th percentiles) across the bootstrap samples to get an interval estimate for our prediction. This is a very powerful technique, as it allows us to estimate the uncertainty in our predictions without making any assumptions about the underlying distribution of the data.</p>
</section>
<section id="bayesian-approaches" class="level3">
<h3 class="anchored" data-anchor-id="bayesian-approaches">Bayesian Approaches</h3>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://m-clark.github.io/img/priorLikePosterior.png" class="img-fluid figure-img" style="width:50.0%"></p>
<figcaption>Prior, Likelihood, Posterior</figcaption>
</figure>
</div>
<p>Bootstrap and Bayesian approaches are kindred spirits in that they both generate a distribution for our predictions. The Bayesian approach does not require resampling the data, but it does have an assumption about the distributions of the parameters, which ultimately means it still makes assumptions similar to those in traditional statistical models. We use the Bayesian approach to provide a distribution for the parameters we’re attempting to estimate. For our predictions, we then take random draws from that parameter distribution, feed it into our model to get a prediction, and then repeat that process many times. Again, we may take the average for our final prediction, and the quantiles of interest for our interval estimate.</p>
</section>
<section id="conformal-prediction" class="level3">
<h3 class="anchored" data-anchor-id="conformal-prediction">Conformal Prediction</h3>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2025-06-01-conformal/index_files/figure-html/conformal-vis-2-1.png" class="img-fluid figure-img" width="768"></p>
</figure>
</div>
</div>
</div>
<p>Conformal prediction is yet another technique for estimating uncertainty in machine learning models, and one of its primary strengths is that it is model agnostic and theoretically can work for any model, from linear regression to deep learning. It is based on the idea that we can estimate the uncertainty in our predictions by looking at the distribution of the predictions from the model, or more specifically, the prediction error. Using the observed error on a calibration set that was not used to train the model, we can order those errors and find the quantile corresponding to the desired uncertainty coverage/error rate<sup>2</sup>. When predicting on new data, we assume it (and its error) comes from a similar distribution as what we’ve seen already in our training/calibration process, with no particular assumption about that distribution. We then use that quantile from our previous distribution to create upper and lower bounds for the new prediction.</p>
<section id="quick-demo" class="level4">
<h4 class="anchored" data-anchor-id="quick-demo">Quick Demo</h4>
<p>While the implementation for various settings can get quite complicated, the conceptual approach is mostly straightforward as we’ve just suggested. The following shows some simplified code demonstrating the <strong>split-conformal</strong> procedure in Python and R. Note that you should use packages like <span class="pack">mapie</span> or fuller implementations for your own work.</p>
<!-- Can't do tabset for doc/blog post upload, so we'll do this instead. -->
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true" href="">Python</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false" href="">R</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<!-- ![](../../img/conformal/py_conformal_code.png){width=66%} -->
<div class="cell">
<details class="code-fold">
<summary>Code</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LinearRegression</span>
<span id="cb1-3"></span>
<span id="cb1-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> split_conformal(X, y, new_data, alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>, seed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>):</span>
<span id="cb1-5">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Set random seed for reproducibility</span></span>
<span id="cb1-6">    np.random.seed(seed)</span>
<span id="cb1-7"></span>
<span id="cb1-8">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Splitting the data into training and calibration sets</span></span>
<span id="cb1-9">    train_data, cal_data, train_y, cal_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(X, y, test_size <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)</span>
<span id="cb1-10">    N <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_data.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb1-11"></span>
<span id="cb1-12">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Train the base model</span></span>
<span id="cb1-13">    model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression()</span>
<span id="cb1-14">    model.fit(train_data, train_y)</span>
<span id="cb1-15">    </span>
<span id="cb1-16">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate residuals on calibration set</span></span>
<span id="cb1-17">    cal_preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.predict(cal_data)</span>
<span id="cb1-18">    residuals <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(cal_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> cal_preds))</span>
<span id="cb1-19">    </span>
<span id="cb1-20">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Sort residuals and find the quantile corresponding to (1-alpha)</span></span>
<span id="cb1-21">    residuals.sort()</span>
<span id="cb1-22">    quantile <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.quantile(residuals, (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> alpha) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (N <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (N <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)))</span>
<span id="cb1-23">    </span>
<span id="cb1-24">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Make predictions on new data and calculate prediction intervals</span></span>
<span id="cb1-25">    preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.predict(new_data)</span>
<span id="cb1-26">    lower_bounds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> quantile</span>
<span id="cb1-27">    upper_bounds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> quantile</span>
<span id="cb1-28">    </span>
<span id="cb1-29">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Return predictions and prediction intervals</span></span>
<span id="cb1-30">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span>(</span>
<span id="cb1-31">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(</span>
<span id="cb1-32">            cp_error <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> quantile, </span>
<span id="cb1-33">            preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> preds, </span>
<span id="cb1-34">            lower_bounds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lower_bounds, </span>
<span id="cb1-35">            upper_bounds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> upper_bounds</span>
<span id="cb1-36">        )</span>
<span id="cb1-37">    )</span>
<span id="cb1-38"></span>
<span id="cb1-39">cp_error_py <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> split_conformal(X_train, y_train, X_test, alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">.1</span>)[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cp_error'</span>]</span></code></pre></div></div>
</details>
</div>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<!-- ![](../../img/conformal/r_conformal_code.png){width=66%} -->
<div class="cell">
<details class="code-fold">
<summary>Code</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">split_conformal <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(X, y, new_data, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">05</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>) {</span>
<span id="cb2-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Set random seed for reproducibility</span></span>
<span id="cb2-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(seed)</span>
<span id="cb2-4"></span>
<span id="cb2-5">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Splitting the data into training and calibration sets</span></span>
<span id="cb2-6">    idx <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(X), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(X) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb2-7">    </span>
<span id="cb2-8">    train_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> X <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;">slice</span>(idx)</span>
<span id="cb2-9">    cal_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> X <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;">slice</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>idx)</span>
<span id="cb2-10">    train_y <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> y[idx]</span>
<span id="cb2-11">    cal_y <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> y[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>idx]</span>
<span id="cb2-12"></span>
<span id="cb2-13">    N <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(train_data)</span>
<span id="cb2-14"></span>
<span id="cb2-15">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Train the base model</span></span>
<span id="cb2-16">    model <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lm</span>(train_y <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_data)</span>
<span id="cb2-17"></span>
<span id="cb2-18">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calculate residuals on calibration set</span></span>
<span id="cb2-19">    cal_preds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(model, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> cal_data)</span>
<span id="cb2-20">    residuals <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abs</span>(cal_y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> cal_preds)</span>
<span id="cb2-21"></span>
<span id="cb2-22">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Sort residuals and find the quantile corresponding to (1-alpha)</span></span>
<span id="cb2-23">    residuals <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span>(residuals)</span>
<span id="cb2-24">    quantile  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">quantile</span>(residuals, (<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> alpha) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (N <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (N <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)))</span>
<span id="cb2-25"></span>
<span id="cb2-26">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Make predictions on new data and calculate prediction intervals</span></span>
<span id="cb2-27">    preds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(model, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> new_data)</span>
<span id="cb2-28">    lower_bounds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> preds <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> quantile</span>
<span id="cb2-29">    upper_bounds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> preds <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> quantile</span>
<span id="cb2-30"></span>
<span id="cb2-31">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Return predictions and prediction intervals</span></span>
<span id="cb2-32">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">return</span>(</span>
<span id="cb2-33">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb2-34">            <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cp_error =</span> quantile, </span>
<span id="cb2-35">            <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">preds =</span> preds, </span>
<span id="cb2-36">            <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lower_bounds =</span> lower_bounds, </span>
<span id="cb2-37">            <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">upper_bounds =</span> upper_bounds</span>
<span id="cb2-38">        )</span>
<span id="cb2-39">    )</span>
<span id="cb2-40">}</span>
<span id="cb2-41"></span>
<span id="cb2-42">cp_error_r <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">split_conformal</span>(X_train, y_train, X_test, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cp_error'</span>]]</span></code></pre></div></div>
</details>
</div>
</div>
</div>
</div>
<p>We can compare our simple approach to <code>mapie</code> in Python, which is a solid package to use for this<sup>3</sup>. The ‘naive’ conformal procedure in <code>mapie</code> implemented is very similar to our split-conformal procedure, and generally you’d want to use one of the better approaches. But this is a bit more comparable, and most of the difference between our R, Python and the <code>mapie</code> results are due to the underlying data split.</p>
<!-- ![](../../img/conformal/py_mapie_conformal_code.png){width=66%} -->
<div class="cell">
<details class="code-fold">
<summary>Code</summary>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> mapie.regression <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> MapieRegressor</span>
<span id="cb3-2"></span>
<span id="cb3-3">initial_fit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression().fit(X_train, y_train)</span>
<span id="cb3-4">model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MapieRegressor(initial_fit, method <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'naive'</span>)</span>
<span id="cb3-5">y_pred, y_pis <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.fit(X_train, y_train).predict(X_test, alpha <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)</span>
<span id="cb3-6"></span>
<span id="cb3-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># take the first difference between upper and lower bounds,</span></span>
<span id="cb3-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># since it's constant for all predictions in this setting</span></span>
<span id="cb3-9">cp_error_mapie <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (y_pis[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> y_pis[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>  </span></code></pre></div></div>
</details>
</div>
<div class="cell">
<div class="cell-output-display">
<div id="ycfngrsiqe" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>#ycfngrsiqe table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#ycfngrsiqe .gt_indent_5 {
  text-indent: 25px;
}
</style>
<table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
  <thead>
    <tr class="gt_col_headings">
      <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Source">Source</th>
      <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="CP Error">CP Error</th>
    </tr>
  </thead>
  <tbody class="gt_table_body">
    <tr><td headers="Source" class="gt_row gt_left">R-by-hand</td>
<td headers="CP Error" class="gt_row gt_right">0.5356</td></tr>
    <tr><td headers="Source" class="gt_row gt_left">Py-by-hand</td>
<td headers="CP Error" class="gt_row gt_right">0.5361</td></tr>
    <tr><td headers="Source" class="gt_row gt_left">Py-mapie</td>
<td headers="CP Error" class="gt_row gt_right">0.5370</td></tr>
  </tbody>
  
  
</table>
</div>
</div>
</div>
<div class="callout callout-style-default callout-note callout-titled" title="Other Methods">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>Other Methods
</div>
</div>
<div class="callout-body-container callout-body">
<p>As we’ve seen, there are numerous methods for estimating uncertainty in our predictions. As another example, some use <em>quantile regression</em> in machine learning models. It is based on the idea that we can estimate the uncertainty in our predictions by modeling the specific quantiles rather than the conditional mean default value, for example, the .05 and .95 values. But those quantiles are predictions with uncertainty themselves, and without incorporating that uncertainty, tend to underestimate the uncertainty in the prediction (Bai et al., 2021). In general, one should be cautious about the method they choose in any particular setting.</p>
</div>
</div>
</section>
</section>
</section>
<section id="practical-comparison-uncertainty-methods-on-housing-data" class="level2">
<h2 class="anchored" data-anchor-id="practical-comparison-uncertainty-methods-on-housing-data">Practical Comparison: Uncertainty Methods on Housing Data</h2>
<p>To see our uncertainty estimation in practice, we’ll use a sample of the classic <a href="https://www.kaggle.com/camnugent/california-housing-prices">California Housing Prices dataset</a> for demonstration. The dataset contains information about housing prices in California, including the median house value in a district, the median income for that district, and the median house age etc. We’ll use all the available features to predict median house value on the log scale. You can find out some basic info for the data at the end of this post. The very rough notebook used to generate the data and results is available <a href="https://github.com/m-clark/m-clark.github.io/tree/master/posts">at my website repo</a>.</p>
<p>In the following we show the 90% prediction interval estimates for a basic linear regression after exponentiating to the original scale. Points are arranged in increasing (median) predicted value. We can see that the prediction intervals are essentially in agreement for all methods we previously discussed – statistical, bootstrapped, Bayesian, and conformal. Highlighted are the points missed by the intervals, which was around 10% for each method (data issues notwithstanding<sup>4</sup>). This should leave us feeling good about using any of these methods for uncertainty estimation in simpler model settings.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://m-clark.github.io/img/conformal/lin-reg-plot.png" class="img-fluid figure-img" style="width:75.0%"></p>
<figcaption>Prediction Intervals (Linear Regression)</figcaption>
</figure>
</div>
<p>The following visualization shows the exact same data context, though now we use an xgboost model to predict the target. With this model, we do not have an underlying statistical distribution or easy Bayesian counterpart<sup>5</sup> with which to estimate uncertainty. So we are left to use a bootstrapped approach or conformal prediction. Furthermore, the nature of the model means that the actual interval widths can vary a bit from point to point, so the lines shown are smoothed boundaries used to make the general pattern more clear, but should not be taken as the actual interval for a given point.</p>
<p>In the visualization, blue represents the bootstrapped prediction interval while red represents the conformal prediction interval. Points that fall outside their respective intervals are highlighted - blue dots show observations missed by bootstrap intervals and red dots show those missed by conformal intervals. Some points may appear in both colors when they’re missed by both approaches (i.e., anything missed by the conformal is also missed by the bootstrap).</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://m-clark.github.io/img/conformal/boost-plot.png" class="img-fluid figure-img" style="width:75.0%"></p>
<figcaption>Prediction Intervals (XGBoost)</figcaption>
</figure>
</div>
<p>The first thing we see is that the naive bootstrap is too optimistic in this situation, with interval estimates that are too narrow, which results in only 70% coverage compared to the target 90%. Complex tree-based models like XGBoost often exhibit this problem with bootstrapping because the resampling approach struggles to capture the full model uncertainty in high-variance models.</p>
<p>In contrast, the conformal interval is more conservative and achieves 92% coverage, close to matching our specified 90% target (though slightly more conservative). This demonstrates conformal prediction’s ability to produce reliable uncertainty estimates even for complex models where traditional methods struggle. As a practical advantage, on an Apple M1 laptop, it took a few seconds to get the conformal prediction intervals, while the bootstrap took over 10 minutes for 500 bootstrap replications.</p>
</section>
<section id="pros-and-cons" class="level2">
<h2 class="anchored" data-anchor-id="pros-and-cons">Pros and Cons</h2>
<p>Nothing comes for free in the modeling world. Here we list some advantages and disadvantages of the different approaches to uncertainty estimation. Note that this is not an exhaustive list nor does it go into specifics, and there may be additional considerations beyond those noted.</p>
<section id="traditional-statistical-prediction-intervals" class="level3">
<h3 class="anchored" data-anchor-id="traditional-statistical-prediction-intervals">Traditional Statistical Prediction Intervals</h3>
<p><strong>Advantages:</strong></p>
<ul>
<li><strong>Ease</strong>: For many models, prediction intervals can be computed easily and are automatically provided by various modeling packages.</li>
<li><strong>Interpretability</strong>: The statistical theory behind the prediction intervals is generally straightforward.</li>
<li><strong>Computational Efficiency</strong>: Unlike bootstrapping or Bayesian approaches that require multiple model fits or MCMC sampling, traditional statistical intervals can typically be calculated directly from the fitted model parameters with minimal computational overhead.</li>
</ul>
<p><strong>Disadvantages:</strong></p>
<ul>
<li><strong>Distribution Assumption</strong>: They typically require (sometimes strong) assumptions about the underlying data distribution.</li>
<li><strong>Model-Specific Estimation</strong>: The intervals depend on a specific statistical model, and different estimation approaches are needed for different models.</li>
<li><strong>Model Complexity</strong>: Even common models, e.g., those using penalty terms, can make prediction uncertainty using distributional assumptions difficult<sup>6</sup>.</li>
</ul>
</section>
<section id="bootstrapping-1" class="level3">
<h3 class="anchored" data-anchor-id="bootstrapping-1">Bootstrapping</h3>
<p><strong>Advantages:</strong></p>
<ul>
<li><strong>Simple</strong>: Bootstrapping is a relatively simple approach to estimating uncertainty.</li>
<li><strong>Less Restrictive Assumptions</strong>: Like conformal prediction, non-parametric bootstrapping doesn’t require assumptions of the underlying data distribution.</li>
<li><strong>Model-Agnostic</strong>: It operates directly on the data irrespective of your model.</li>
</ul>
<p><strong>Disadvantages:</strong></p>
<ul>
<li><strong>Computationally Intensive</strong>: It might require a large number of resamples, which can be computationally intensive for some model-data combinations.</li>
<li><strong>Data issues</strong>: For very small datasets, extreme values/tails, estimates could be problematic, but this is likely true for most approaches.</li>
<li><strong>Naive approach is limited</strong>: The naive resampling approach tends to underestimate uncertainty, so additional steps are required to get a more accurate estimate of uncertainty.</li>
</ul>
</section>
<section id="bayesian-approaches-1" class="level3">
<h3 class="anchored" data-anchor-id="bayesian-approaches-1">Bayesian Approaches</h3>
<p><strong>Advantages:</strong></p>
<ul>
<li><strong>Probabilistic Interpretation</strong>: It provides a full distribution of plausible values for our parameters or predictions.</li>
<li><strong>Incorporates Prior Information</strong>: We can use prior beliefs about parameters we estimate. For example, we can use last year’s data to inform our prior beliefs about the parameters of this year’s model.</li>
<li><strong>Confidence in Uncertainty Estimate</strong>: We can be more confident in our uncertainty estimates than we can with some statistical approaches that often use workarounds to estimate uncertainty (e.g.&nbsp;mixed models), and there are many diagnostic tools available to spot problematic models.</li>
</ul>
<p><strong>Disadvantages:</strong></p>
<ul>
<li><strong>Computationally Intensive</strong>: MCMC sampling for model estimation can be slow, particularly for complex models.</li>
<li><strong>Choice of Prior</strong>: The choice of prior can significantly influence the results, especially with small data.</li>
<li><strong>Statistical Assumptions</strong>: As the Bayesian models are an alternative way to estimate statistical models, they depend on a specific statistical model and its likelihood.</li>
</ul>
</section>
<section id="conformal-prediction-1" class="level3">
<h3 class="anchored" data-anchor-id="conformal-prediction-1">Conformal Prediction</h3>
<p><strong>Advantages:</strong></p>
<ul>
<li><strong>Distribution-Free &amp; Model-Agnostic</strong>: Generates valid prediction intervals regardless of underlying data distribution and works with any model, providing a unified framework.</li>
<li><strong>Theoretical Guarantees</strong>: Given a significance level, conformal prediction provides valid coverage even with misspecified models.</li>
<li><strong>Efficiency</strong>: Conformal prediction is relatively computationally efficient compared to other methods, and nonconformity measures based on residuals are straightforward to compute during the training process.</li>
<li><strong>Generalizable</strong>: Other approaches that might be used for uncertainty prediction, like quantile regression or Bayesian methods, can be ‘conformalized’ to produce appropriate coverage.</li>
</ul>
<p><strong>Disadvantages:</strong></p>
<ul>
<li><strong>Implementation Challenges</strong>: The intervals can be unstable with small data changes, and are sometimes overly conservative when the nonconformity measure isn’t chosen properly.</li>
<li><strong>Data Splitting Requirement</strong>: A portion of the data needs to be held out to estimate the nonconformity scores, which can reduce the data available for model training.</li>
<li><strong>Theoretical Limitations</strong>: While theoretically sound, various practical implementations (like split-conformal) introduce trade-offs between computational efficiency and theoretical guarantees.</li>
<li><strong>Exchangeability Assumption</strong>: Still requires data exchangeability assumption, which must be accounted for in time series or other structured data.</li>
</ul>
<div class="callout callout-style-default callout-note callout-titled" title="Model Complexity Changes the Game">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>Model Complexity Changes the Game
</div>
</div>
<div class="callout-body-container callout-body">
<p>The comparison highlights an important pattern in uncertainty estimation:</p>
<ol type="1">
<li><p><strong>Simple models</strong>: All methods tend to perform similarly when the underlying model is well-behaved (like linear regression).</p></li>
<li><p><strong>Complex models</strong>: Method differences become pronounced - distributional assumptions break down, computational demands diverge, and coverage guarantees can fail.</p></li>
<li><p><strong>Fundamental tradeoff</strong>: As models become more complex to capture nuanced patterns, the uncertainty estimation task becomes correspondingly more challenging.</p></li>
</ol>
<p>This explains why conformal prediction has gained popularity - it maintains validity across the model complexity spectrum without sacrificing computational efficiency.</p>
</div>
</div>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<blockquote class="blockquote">
<p>There’s a lot of uncertainty in uncertainty estimation.</p>
</blockquote>
<p>As we’ve seen, there are many approaches to estimating uncertainty, and each has its own strengths and weaknesses. Among the considerations for selection are computational feasibility, coverage accuracy, and underlying model assumptions. In this article we discussed statistical prediction intervals, bootstrapping, Bayesian estimation, and conformal prediction, as well as their relative advantages and disadvantages. Conformal prediction is a relatively newer approach that has some advantages over other approaches, including its flexibility, distribution-free nature, and theoretical guarantee of coverage probability, even under difficult and complex modeling circumstances. We hope this article has been helpful in understanding the importance of uncertainty estimation and the different approaches to it, and that it has provided a useful demonstration of how to use conformal prediction to estimate uncertainty.</p>
<p>As we’ve seen, there are many approaches to estimating uncertainty, and each has its own strengths and weaknesses. Among the considerations for selection are coverage accuracy, model/technical assumptions, and computational feasibility. These considerations matter because proper uncertainty estimation directly impacts decision quality – as our opening example illustrated, different uncertainty ranges can lead to entirely different actions.</p>
<p>For practitioners looking to implement these methods:</p>
<ul>
<li><strong>For simple models with well-understood distributions</strong>: Traditional statistical intervals typically offer computational efficiency and simplicity.</li>
<li><strong>When prior knowledge is important</strong>: Bayesian approaches provide a natural framework for incorporating this information, while also providing intervals for more complex statistical models.</li>
<li><strong>When working with moderate-sized datasets and statistical software or other model limitations</strong>: Bootstrapping provides flexibility across different model types, particularly for models where analytical intervals aren’t implemented or appropriate.</li>
<li><strong>For complex models or when distribution assumptions are questionable</strong>: Conformal prediction offers reliable coverage with minimal assumptions, while also providing better computational efficiency than bootstrapping approaches.</li>
</ul>
<p>Looking forward, the field of uncertainty estimation continues to evolve. Recent advances include adaptations of conformal prediction for time series data, more efficient implementations that reduce data splitting requirements, and hybrid approaches that combine the strengths of multiple methods. I’d probably recommend first implementing the simplest approach appropriate for your model setting. You could then compare it with conformal prediction to evaluate potential improvements in reliability and coverage.</p>
</section>
<section id="data-details" class="level2">
<h2 class="anchored" data-anchor-id="data-details">Data Details</h2>
<p>The following shows some basic information based on a sample of the data used in this post.</p>
<p><img src="https://m-clark.github.io/img/conformal/data_table.png" class="img-fluid" style="width:75.0%"></p>
</section>
<section id="references" class="level2">



<!-- -->


</section>


<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-angelopoulos2022gentle" class="csl-entry">
Angelopoulos, Anastasios N., and Stephen Bates. 2022. <em>A Gentle Introduction to Conformal Prediction and Distribution-Free Uncertainty Quantification</em>. <a href="https://arxiv.org/abs/2107.07511">https://arxiv.org/abs/2107.07511</a>.
</div>
<div id="ref-va2022" class="csl-entry">
Arel-Bundock, Vincent. 2022. <em>Distribution-Free Prediction Intervals with Conformal Inference Using r</em>. <a href="https://arelbundock.com/posts/conformal/">https://arelbundock.com/posts/conformal/</a>.
</div>
<div id="ref-bai2021understanding" class="csl-entry">
Bai, Yu, Song Mei, Huan Wang, and Caiming Xiong. 2021. <span>“Understanding the Under-Coverage Bias in Uncertainty Estimation.”</span> <em>Advances in Neural Information Processing Systems</em> 34: 18307–19.
</div>
<div id="ref-brownlee2019" class="csl-entry">
Brownlee, J. 2019. <em>A Gentle Introduction to Uncertainty in Machine Learning</em>. <a href="https://machinelearningmastery.com/uncertainty-in-machine-learning/">https://machinelearningmastery.com/uncertainty-in-machine-learning/</a>.
</div>
<div id="ref-tidymodels2023" class="csl-entry">
Group, Tidymodels. 2023. <em>Conformal Inference for Regression Models</em>. <a href="https://arelbundock.com/posts/conformal/">https://arelbundock.com/posts/conformal/</a>.
</div>
<div id="ref-lei2018distribution" class="csl-entry">
Lei, Jing, Max G’Sell, Alessandro Rinaldo, Ryan J Tibshirani, and Larry Wasserman. 2018. <span>“Distribution-Free Predictive Inference for Regression.”</span> <em>Journal of the American Statistical Association</em> 113 (523): 1094–111. <a href="https://www.stat.cmu.edu/~ryantibs/papers/conformal.pdf">https://www.stat.cmu.edu/~ryantibs/papers/conformal.pdf</a>.
</div>
<div id="ref-molnar2023" class="csl-entry">
Molnar, Christopher. 2023. <em>Understanding Different Uncertainty Mindsets</em>. <a href="https://mindfulmodeler.substack.com/p/understanding-different-uncertainty">https://mindfulmodeler.substack.com/p/understanding-different-uncertainty</a>.
</div>
<div id="ref-SOBoot" class="csl-entry">
StackExchange. 2023. <em>Bootstrap Prediction Interval</em>. <a href="https://stats.stackexchange.com/questions/226565/bootstrap-prediction-interval">https://stats.stackexchange.com/questions/226565/bootstrap-prediction-interval</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>Technically we can model the variance with the features as well, but we’ll keep it simple here.↩︎</p></li>
<li id="fn2"><p>The error rate (<img src="https://latex.codecogs.com/png.latex?%5Calpha">) is the proportion of the data that would fall outside the prediction interval, while the coverage rate/interval is 1 - <img src="https://latex.codecogs.com/png.latex?%5Calpha">.↩︎</p></li>
<li id="fn3"><p>When I first started this post, there wasn’t much in the way of packages for conformal prediction in R. One <a href="https://github.com/ryantibs/conformal">was the conformal package</a>, but it is not very user friendly in the least. Others seem like one offs or have other limitations (e.g.&nbsp;only being for classification, working only in the tidymodels framework, etc.). More recently <span class="pack">probably</span> has add functionality that works nicely with the tidymodels framework, but I haven’t had a chance to try it out yet.↩︎</p></li>
<li id="fn4"><p>Interestingly all but the bootstrap appeared slightly narrow, but I think this has more to do with data issues, particularly the preponderance of house prices censored to ~500,000, about 5% of the data. No preprocessing was done except to put the home price on the log scale.↩︎</p></li>
<li id="fn5"><p>There are methods like Bayesian Additive Regression Trees, but that’s a rabbit hole I didn’t think necessary to investigate for our purposes. Likewise we could also have done a very complicated linear model that incorporates interactions and nonlinearities.↩︎</p></li>
<li id="fn6"><p>One of the more popular statistical packages in R is <code>lme4</code>, and the developers don’t provide prediction intervals for mixed models because “it is difficult to define an efficient method that incorporates uncertainty in the variance parameters”. They suggest to use bootstrapping instead.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2025,
  author = {Clark, Michael},
  title = {Uncertainty {Estimation} with {Conformal} {Prediction}},
  date = {2025-06-01},
  url = {https://m-clark.github.io/posts/2025-06-01-conformal/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2025" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2025. <span>“Uncertainty Estimation with Conformal
Prediction.”</span> June 1. <a href="https://m-clark.github.io/posts/2025-06-01-conformal/">https://m-clark.github.io/posts/2025-06-01-conformal/</a>.
</div></div></section></div> ]]></description>
  <category>machine learning</category>
  <category>regression</category>
  <category>boosting</category>
  <category>bayesian</category>
  <guid>https://m-clark.github.io/posts/2025-06-01-conformal/</guid>
  <pubDate>Sun, 01 Jun 2025 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/conformal/boost-plot.png" medium="image" type="image/png" height="108" width="144"/>
</item>
<item>
  <title>Imbalanced Outcomes</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2025-04-07-class-imbalance/</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>This post began around two years ago and was initially intended for the Strong Analytics blog, but for various reasons never came to fruition. We still thought the spirit of the content was valuable, so we did what we could to get it out one way or another. Both the intended audience and focus have changed over time, but hopefully the end result is cohesive enough to be useful to a wide audience. Much gratitude is owed to Elizabeth Li for her contributions to the initial drafts, and editorial help beyond.</p>
</blockquote>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>Imagine you’re working on a fraud detection system for a bank. Out of millions of financial transactions, only a tiny fraction are fraudulent. This is a classic example of <em>class imbalance</em>, where one class we are trying to predict (fraudulent transactions) is much rarer than the other (legitimate transactions). Depending on your modeling approach, ignoring the imbalance can lead to the predictions missing most of the fraudulent transactions, as well as other issues we’d like to avoid. Here we’ll explore various issues regarding class imbalance, as well as techniques to address it. As we’ll see, the problem is nuanced and, very often, simple approaches to deal with it can work very well.</p>
<section id="goals" class="level3">
<h3 class="anchored" data-anchor-id="goals">Goals</h3>
<p>To guide our exploration, we have the following goals:</p>
<ul>
<li>Explain class imbalance generally</li>
<li>Review examples and consequences of class imbalance</li>
<li>Cover some common techniques for addressing the problem</li>
<li>Investigate the effects of classification thresholds on performance metrics</li>
<li>Explore a Case Study to see these concepts in action</li>
</ul>
<p>By the end, you should have a good understanding of the challenges posed by imbalanced data, and how to address them in your own work.</p>
</section>
</section>
<section id="understanding-imbalanced-data" class="level2">
<h2 class="anchored" data-anchor-id="understanding-imbalanced-data">Understanding Imbalanced Data</h2>
<p>The basic idea underpinning class imbalance is that one class is significantly less prevalent than the other, and this can happen for a variety of reasons, including the inherent nature of the data, or something about the way it was collected. For simplicity, we focus on the binary case, as it’s easier to get an intuitive understanding of what ‘imbalance’ would mean in that setting. However, the concepts discussed here can extend to multiclass settings also. Check out the supplemental section for a brief overview of the multiclass case.</p>
<p>In a typical classification task, we would use a default threshold of 0.5 to classify predicted probabilities into binary outcomes, with anything above the threshold going to one class and the rest to the other class. This approach works well when the classes are balanced or nearly so, but it can fail in imbalanced settings where the minority class is underrepresented. For example, if less than 1% of the target data belongs to the minority class, a model trained without accounting for this imbalance may struggle to identify minority class instances effectively, if at all, and fall short for the task at hand.</p>
<section id="real-world-examples" class="level3">
<h3 class="anchored" data-anchor-id="real-world-examples">Real-world Examples</h3>
<p>Class imbalance is common in many real-world scenarios, such as:</p>
<ul>
<li>Fraud detection: As in our opening example, the vast majority of transactions are legitimate, but a small percentage are fraudulent.</li>
<li>Click-through rate: Most users on a website do not click on ads, but a small percentage do.</li>
<li>Disease detection: Consider classifying medical images for a rare disease. The vast majority of images may represent normal tissue, while only a small fraction show signs of the disease.</li>
<li>Spam detection: In email datasets, the majority of emails are legitimate (non-spam), while only a small fraction are spam emails.</li>
</ul>
<p>As one can see, it’s quite common and natural to have imbalanced data in many real-world applications. So how does it affect our modeling?</p>
</section>
<section id="is-imbalance-a-problem" class="level3">
<h3 class="anchored" data-anchor-id="is-imbalance-a-problem">Is imbalance a problem?</h3>
<p>Is imbalance a problem? Well, not exactly, at least not inherently. The real challenge often arises from its implications, such as the sample size (of the minority class), model limitations, and the metrics we use to evaluate the model.</p>
<p>For example, let’s say you had 10 million observations and 1% of them were in the minority class. Despite the imbalanced classes, you would likely have enough to work with to discover the feature-target relationships, and obtain good estimates of a variety of metrics even after test and validation splits. But with a smaller total sample or even rarer class prevalence, the problems of imbalance can be exacerbated due to the lack of data to work with, making it difficult to learn meaningful patterns or evaluate the model reliably.</p>
<p>In other cases, our model may not produce good predictions for the minority class, even if we have enough data. Maybe the model is not well suited to the problem, or the features aren’t strong enough to make good classifications. In this case, even if your data was balanced you’d potentially still have poor performance, and it will likely be worse with imbalance.</p>
<p>And finally, some metrics, even common ones such as accuracy, can be deceptive in the imbalanced setting. As an example, they may reflect the majority class performance while ignoring the minority class.</p>
<p>Addressing these challenges requires a thoughtful modeling approach and use of performance metrics, which we will explore in the following sections.</p>
</section>
</section>
<section id="techniques-for-dealing-with-imbalanced-data" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="techniques-for-dealing-with-imbalanced-data">Techniques for Dealing with Imbalanced Data</h2>
<p>There are a number of techniques one can use for handling imbalanced data to help meet modeling goals. Here, we will discuss a few commonly used methods, categorized into sampling-based techniques, algorithmic adjustments, and specialized approaches. Then we’ll see some in action later with our case study.</p>
<section id="sampling-based-techniques" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="sampling-based-techniques">Sampling-based Techniques</h3>
<p>Sampling-based techniques involve modifying the original dataset to balance the class distribution. These techniques can be broadly grouped into oversampling, undersampling, and hybrid sampling.</p>
<section id="oversampling" class="level4 page-columns page-full">
<h4 class="anchored" data-anchor-id="oversampling">Oversampling</h4>
<p><em>Oversampling</em> is a technique where we increase the number of observations in the minority class. Most commonly this is done by duplicating observations in the minority class or by generating synthetic observations.</p>
<p><em>Random over-sampling</em> (ROS) is akin to a bootstrap approach where we duplicate observations by sampling with replacement from the minority class, and this in turn increases the total number of observations. This is the simplest oversampling approach, and is often enough to potentially improve model performance on metrics that may be of interest. Other more complicated oversampling techniques could be used, but in practice are rarely going to do much better. However, while effective, oversampling can lead to overfitting, as the model may learn to memorize the duplicated observations rather than generalize from them.</p>
<p>There are also several methods for generating synthetic observations. Popular techniques include <em>SMOTE</em> (Synthetic Minority Over-sampling Technique), along with SMOTE variants such as Borderline-SMOTE and <em>ADASYN</em> (Adaptive Synthetic Sampling). SMOTE generates synthetic observations by creating interpolations of nearest neighbors of the minority class observations. It can be useful if using a ‘weak learner’ for the model (e.g.&nbsp;a simple logistic regression), but generally does not lead to improvement for modeling techniques common in machine learning, such as tree-based methods.</p>

<div class="no-row-height column-margin column-container"><div class="">
<p>A good package for implementing these techniques is the <code>imbalanced-learn</code> package in Python. The package is well-documented and easy to use, and is a good starting point for practitioners.</p>
</div></div></section>
<section id="undersampling" class="level4">
<h4 class="anchored" data-anchor-id="undersampling">Undersampling</h4>
<p>In contrast to oversampling, <em>undersampling</em> takes the opposite approach, reducing the number of observations in the majority class to make the target more balanced.</p>
<p><em>Random under-sampling</em> (RUS) is a technique where we decrease the number of observations in the majority class by randomly selecting observations in the majority class to remove. The goal is again to create a more balanced dataset. While it can be effective in that regard, it can also lead to loss of important information, especially if the sample size is not very large to begin with.</p>
<p>Other techniques look at nearest neighbors of the majority class, i.e.&nbsp;observations that are very similar, and remove some of them assuming they are not adding useful information. Variations include approaches, e.g., <em>NearMiss</em>, that are similar to ‘matched samples’ techniques long employed in statistical settings.</p>
</section>
<section id="hybrid-sampling" class="level4">
<h4 class="anchored" data-anchor-id="hybrid-sampling">Hybrid Sampling</h4>
<p>Hybrid sampling is a technique where we combine oversampling and undersampling to create a (more) balanced dataset. This is often done by oversampling the minority class and undersampling the majority class, and as before this could be done in a random fashion. An alternative hybrid sampling approach could also involve removing some observations from both classes that would be nearest neighbors (<em>TOMEK</em> links), which would hopefully improve the model’s ability to classify the observations among those that remain, as they are more clearly delineated among the features.</p>
</section>
</section>
<section id="algorithmic-techniques" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="algorithmic-techniques">Algorithmic Techniques</h3>
<p>We use the term ‘algorithmic techniques’ to refer to those that involve adjusting some aspect of the model estimation. Unlike sampling-based techniques, we do not manipulate the data directly.</p>
<section id="weighting" class="level4 page-columns page-full">
<h4 class="anchored" data-anchor-id="weighting">Weighting</h4>
<p>In some modeling contexts, we can adjust the importance of each example to handle the imbalance. The loss function is adjusted so that losses from the minority class contribute more than losses from the majority class. This is often done in the context of <em>cost-sensitive learning</em>, where the cost of misclassifying an observation in the minority class is higher than the cost of misclassifying an observation in the majority class.</p>

<div class="no-row-height column-margin column-container"><div class="">
<p>For some models, like logistic regression, weighting would essentially be equivalent to what is done with simple resampling techniques, negating the need to employ the latter. For example, doubling the weight of an observation would be equivalent to having two copies of the observation in the dataset. However, for other models, like tree-based methods, weighting and resampling are not equivalent. For example, in a random forest, resampling changes the composition of the bootstrap samples used to build the trees, while weighting changes the importance of each observation in the calculation of splits within each tree. As such, the difference in how the data is used can lead to different model behaviors and outcomes.</p>
</div></div></section>
<section id="thresholding" class="level4">
<h4 class="anchored" data-anchor-id="thresholding">Thresholding</h4>
<p>Thresholding regards changing the classification cutoff to account for the imbalance in the data. The default threshold of 0.5 is an intuitive choice (<span class="citation" data-cites="van_den_goorbergh_harm_2022">Goorbergh et al. (2022)</span>), but is often not effective for imbalanced data. When modifying the threshold, we can use a lower threshold to potentially increase the number of positive classifications, or raise it to ensure we are only classifying the most confident observations as positive.</p>
<p>Identifying an optimal threshold can significantly improve certain metrics we may be interested in, especially when we want to avoid certain types of errors. And though this is a simple approach, it can actually be quite effective at achieving our goals in the context of imbalanced data, and there are a number of different techniques that can be used to identify the optimal threshold for our modeling purposes. Some of these are outlined in the supplemental section.</p>
</section>
</section>
<section id="other-techniques" class="level3">
<h3 class="anchored" data-anchor-id="other-techniques">Other Techniques</h3>
<p>You can find other techniques that are used to handle imbalanced data for specific model settings. For example, in uplift modeling, the goal is to predict the difference in outcomes between two groups, and the data is often imbalanced. Some will use a <em>class variable transformation</em> to predict differences in outcomes between treatment and control groups.</p>
<p>In addition, some approaches have been used in the context of deep learning models. For example, some focus on using different loss functions like <em>focal loss</em> (<span class="citation" data-cites="lin_focal_2018">Lin et al. (2018)</span>) and <em>label smoothing</em>. Others try different optimization approaches like <em>sharpness-aware minimization</em> (SAM, see <span class="citation" data-cites="foret_sharpness-aware_2021">Foret et al. (2021)</span>), data augmentation, and more<sup>1</sup>. At this time, it’s still difficult to know in advance whether deep learning models and associated methods for imbalance will work well for a typical tabular data setting, but they may be worth trying if you have the time and resources, and especially if your data is homogenous in nature<sup>2</sup>. In general, you may need to try a few different approaches to see what works best for your data and your model.</p>
</section>
</section>
<section id="performance-metrics-with-imbalanced-data" class="level2">
<h2 class="anchored" data-anchor-id="performance-metrics-with-imbalanced-data">Performance Metrics with Imbalanced Data</h2>
<p>When evaluating classification models, performance metrics are essential for understanding how well a model is performing and for identifying areas for improvement. However, in the context of imbalanced data, these metrics can be misleading if not used with care. This is because many metrics are sensitive to the classification threshold, so it’s important to consider how thresholds impact both classifications and the metrics derived from them.</p>
<section id="the-role-of-thresholds-in-balancing-trade-offs" class="level3">
<h3 class="anchored" data-anchor-id="the-role-of-thresholds-in-balancing-trade-offs">The Role of Thresholds in Balancing Trade-offs</h3>
<p>As noted previously, when creating a classification label, we use a threshold, or cutoff point, to determine which class to assign to the observation based on predicted probability for that observation. Anything beyond the threshold is classified as the positive class, and anything below is classified as the negative class. So, the choice of threshold directly affects the resulting classifications, and the performance metrics derived from them.</p>
<p>It’s important to note that there is not an inherently right or wrong choice here. For example:</p>
<ul>
<li>A lower threshold, which would lead to more positive classifications, may be appropriate when missing positive cases (false negatives) is costly, such as in disease detection<sup>3</sup>.</li>
<li>A higher threshold, leading to fewer positive classifications, may be better when false positives are more problematic, such as in fraud detection.</li>
</ul>
<p>The impact of thresholds highlights the trade-offs inherent in classification tasks, and selecting a threshold that aligns with the specific goals and constraints of your application is critical. Now let’s take a closer look at how thresholds can affect performance metrics. If you feel you already have the gist, you can skip ahead to the case study to see how this plays out in practice.</p>
</section>
<section id="sec-confusion-matrix" class="level3">
<h3 class="anchored" data-anchor-id="sec-confusion-matrix">The Confusion Matrix</h3>
<p>Many commonly used metrics such as accuracy, precision, recall, and F1 score, are derived from the <em>confusion matrix</em>. The confusion matrix is the initial summary of the relationship between the predicted and observed classes. However, any metric derived in this way will be sensitive to the classification threshold.</p>
<p>On the other hand, many other metrics derived from predicted probabilities. Examples include the area under a receiver operating curve (AUROC) and Brier score, and these metrics are independent of the classification threshold, and so can provide an additional view of model performance. These metrics are particularly valuable in imbalanced settings, where the threshold-dependent metrics may fail to capture the nuances of model behavior. Let’s now see how this works.</p>
</section>
<section id="sec-example-thresh-05" class="level3">
<h3 class="anchored" data-anchor-id="sec-example-thresh-05">Example: Classification with a .5 Threshold</h3>
<p>In the following hypothetical example, the positive rate for the binary target is low - the true average underlying probability of the positive outcome is less than 0.1. Though in practice we’d not know the true probabilities, here we can visualize what their distribution might look like in the following density plot, where the mean probability of the positive class is marked by the line.</p>
<div id="fig-dens-true-prob" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-dens-true-prob-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://m-clark.github.io/img/class-imbalance/density.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-dens-true-prob-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Density plot of underlying true probabilities, imbalanced setting
</figcaption>
</figure>
</div>
<p>Now assume we have a model that predicts probabilities for the target outcome. It may even produce probabilities that correspond well to the true probabilities, as shown in the following plot.</p>
<div id="fig-dens-pred-vs-true-prob" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-dens-pred-vs-true-prob-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://m-clark.github.io/img/class-imbalance/density_pred_vs_true.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-dens-pred-vs-true-prob-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Predicted vs.&nbsp;True Probabilities
</figcaption>
</figure>
</div>
<p>Now, what might a confusion matrix for such data look like with a standard threshold of 0.5? In our hypothetical dataset, we have 100 total for the sample, but there are only five positive observations. Using the default threshold leads to ineffective classification of the minority class, as we only classified two observations as positive, and only one was correct. In this case our precision is 50%, meaning that half of the positive classifications were correct, but our recall is only 20%, meaning we only classified one out of five possible positive observations correctly.</p>
<div class="cell" data-execution_count="4">
<div id="tbl-confusion-matrix-1" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="4">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-confusion-matrix-1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Confusion Matrix 1: Standard Threshold
</figcaption>
<div aria-describedby="tbl-confusion-matrix-1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display" data-execution_count="4">
<div id="xfggvycmyk" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#xfggvycmyk table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<tr class="gt_col_headings">
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id=""></th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Observed -">Observed -</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Observed +">Observed +</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Metrics">Metrics</th>
</tr>
</thead>
<tbody class="gt_table_body">
  <tr>
    <td class="gt_row gt_left">Predicted -</td>
    <td class="gt_row gt_left">94</td>
    <td class="gt_row gt_left">4</td>
    <td class="gt_row gt_left">NPV: .96</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">Predicted +</td>
    <td class="gt_row gt_left">1</td>
    <td class="gt_row gt_left">1</td>
    <td class="gt_row gt_left">PPV: .50</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">Metrics</td>
    <td class="gt_row gt_left">TNR: .99</td>
    <td class="gt_row gt_left">TPR: .20</td>
    <td class="gt_row gt_left">ACC: .95</td>
  </tr>
</tbody>


</table>

</div>
        
</div>
</div>
</figure>
</div>
</div>
<p><span style="font-size: 0.9em">Abbreviations:</span></p>
<ul>
<li><span style="font-size: 0.8em"><em>ACC</em>: Accuracy</span></li>
<li><span style="font-size: 0.8em"><em>TPR</em>: True Positive Rate/Sensitivity/Recall</span></li>
<li><span style="font-size: 0.8em"><em>TNR</em>: True Negative Rate/Specificity</span></li>
<li><span style="font-size: 0.8em"><em>PPV</em>: Positive Predictive Value/Precision</span></li>
<li><span style="font-size: 0.8em"><em>NPV</em>: Negative Predictive Value</span></li>
</ul>
<p>Although classifying one observation out of five true positive cases is not something we’d probably be satisfied with, the accuracy score is 95% because almost all the negative observations were correctly classified (true negative rate = 99%). Without any additional context, someone might think 95% accuracy was a good result, but it’s actually no better than guessing, or just labeling all observations as the most common (negative) class, which would have also resulted in 95% accuracy. The other metrics in the confusion matrix like precision (PPV) and recall (TPR) provide the additional context that we need to understand the model’s performance - namely, that we are not doing so well with the positive class, which is typically not a desirable outcome.</p>
</section>
<section id="example-classification-with-a-lower-threshold" class="level3">
<h3 class="anchored" data-anchor-id="example-classification-with-a-lower-threshold">Example: Classification with a Lower Threshold</h3>
<p>The next plot shows different possible threshold values we could use for the predicted probabilities. With each threshold, we’d potentially create different classifications, resulting in a new confusion matrix and different metrics based on those predicted classes.</p>
<div id="fig-dens-thresholds" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-dens-thresholds-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://m-clark.github.io/img/class-imbalance/density_threshold.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-dens-thresholds-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: Predicted vs.&nbsp;true probabilities with different thresholds
</figcaption>
</figure>
</div>
<p>Now let’s see what happens to the performance metrics if we try using a lower classification threshold than 0.5, say something closer to ~.1. Here is what the resulting table might look like.</p>
<p>In this setting, the accuracy score has dropped from 95% to 84%, but we really shouldn’t too be concerned with this, as accuracy isn’t usually our focus in the imbalanced setting. Again, we could have guessed and gotten 95% correct. One new result is that the true positive rate (recall) has notably increased - from 20% to 80% - there are now four out of five possible correct positive classifications. This is much better! But looking further, it did come at the cost of a higher false positive rate - ~16% for this result vs.&nbsp;1% previously<sup>4</sup>. The positive predictive value (PPV) has also dropped from 50% to 21%, meaning that only about one in five of the positive classifications were correct. This is a common trade-off in imbalanced settings, where increasing recall often comes at the cost of precision, and vice versa. In general, this result suggests that the model is now doing a better job of capturing the positive class. But while we gain in some metrics, we’ve lost ground in others. Again, it’s a trade-off.</p>
<div class="cell" data-execution_count="6">
<div id="tbl-confusion-matrix-2" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="6">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-confusion-matrix-2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;2: Confusion Matrix 2: Lower Threshold
</figcaption>
<div aria-describedby="tbl-confusion-matrix-2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display" data-execution_count="6">
<div id="kjykvyjjrr" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#kjykvyjjrr table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<tr class="gt_col_headings">
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id=""></th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Observed -">Observed -</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Observed +">Observed +</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Metrics">Metrics</th>
</tr>
</thead>
<tbody class="gt_table_body">
  <tr>
    <td class="gt_row gt_left">Predicted -</td>
    <td class="gt_row gt_left">80</td>
    <td class="gt_row gt_left">1</td>
    <td class="gt_row gt_left">NPV: .99</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">Predicted +</td>
    <td class="gt_row gt_left">15</td>
    <td class="gt_row gt_left">4</td>
    <td class="gt_row gt_left">PPV: .21</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">Metrics</td>
    <td class="gt_row gt_left">TNR: .84</td>
    <td class="gt_row gt_left">TPR: .80</td>
    <td class="gt_row gt_left">ACC: .84</td>
  </tr>
</tbody>


</table>

</div>
        
</div>
</div>
</figure>
</div>
</div>
<p>The following table provides some additional metrics to consider for the two confusion matrices. In particular, we see the <em>F1 score</em>, the <em>balanced accuracy</em> score, the area under a receiver operating curve (<em>AUROC</em>) score. These are common alternatives used in the imbalanced setting.</p>
<div class="cell" data-execution_count="7">
<div id="tbl-add-metrics" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="7">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-add-metrics-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;3: Additional Metrics
</figcaption>
<div aria-describedby="tbl-add-metrics-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display" data-execution_count="7">
<div id="mldcnjegev" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#mldcnjegev table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<tr class="gt_col_headings">
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Metric">Metric</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="Conf. Matrix 1">Conf. Matrix 1</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_center" rowspan="1" colspan="1" scope="col" id="Conf. Matrix 2">Conf. Matrix 2</th>
</tr>
</thead>
<tbody class="gt_table_body">
  <tr>
    <td class="gt_row gt_left">F1</td>
    <td class="gt_row gt_center">.29</td>
    <td class="gt_row gt_center">.33</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">Bal. Acc.</td>
    <td class="gt_row gt_center">.59</td>
    <td class="gt_row gt_center">.82</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">AUROC</td>
    <td class="gt_row gt_center">.70</td>
    <td class="gt_row gt_center">.70</td>
  </tr>
</tbody>
  <tfoot class="gt_sourcenotes">
  
  <tr>
    <td class="gt_sourcenote" colspan="3" style="color: gray25;font-size: 0.8em;">Confusion Matrix 1: Standard Threshold; Confusion Matrix 2: Lower Threshold</td>
  </tr>

</tfoot>

</table>

</div>
        
</div>
</div>
</figure>
</div>
</div>
<!-- Note to self, though we have the simulated data that produced the plots, the actual data that produced the confusion matrices has been lost. All metrics are accurate for these matrices, but the AUROC is based on the simulated probabilities and test set observed y that are much larger in number than the confusion matrix. -->
<p>The F1 score is the harmonic mean of precision (positive predictive value) and recall (true positive rate), and balanced accuracy is the average of the true positive rate and true negative rate, or the average recall for both positive and negative classes. These are less sensitive to the class imbalance than accuracy, but they are still sensitive to the threshold used to create the classifications. In this case, both improve with a lower threshold, though the F1 score only changes slightly.</p>
<p>In contrast, the AUROC score is based on the predicted probabilities, and so is independent of the threshold, which is why it is constant in Table&nbsp;3<sup>5</sup>. It is a useful metric in this context to consider because it considers the relationship between the true positive rate and true negative rate at many different thresholds, not just the single threshold you happened to select (<span class="citation" data-cites="google_classification_2025">Google (2025)</span>). As such, this score is often a preferred metric, even in the balanced classification setting.</p>
<p>We’ve now seen a few performance metrics, but there are many available, and we’ll see even more later. Each provides a different facet with which to view your model’s performance. With this in mind, you should decide which aspects of your model’s performance are most important to your use case, and choose your metrics accordingly.</p>
</section>
</section>
<section id="sec-case-study" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="sec-case-study">Case Study: Wine Quality Data</h2>
<p>At this point, we have covered a lot of ground regarding imbalanced data. We have an idea of the concept generally, the different techniques we might use in the imbalanced setting, as well as the metrics we might use to evaluate our models. We’ve also seen how the choice of classification threshold can affect our model’s performance metrics. To illustrate the concepts discussed in practice, we will demonstrate the application of various techniques for approaching imbalanced data. For the full notebook that produced these, see <a href="https://github.com/m-clark/m-clark.github.io/blob/master/posts/2025-01-28-class-imbalance/wine_quality.ipynb">this repo link</a> and play around with it yourself.</p>
<section id="data-setup" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="data-setup">Data Setup</h3>
<p>We will be using the popular wine quality data. The raw data and more detail is available at the <a href="https://archive.ics.uci.edu/ml/datasets/wine+quality">UCI Repository</a>. Our data combines two datasets, one for red wine and one for white wine. There are 6497 total observations and 17 features that regard different aspects of the wine, like acidity, pH, and alcohol content. We also include a binary feature for whether the color of the wine is red.</p>
<p>The original target is numeric, but for our purposes we are attempting to classify wines with a rating of 8 or 9 as ‘high quality’. This represents 198 high quality wines, about 3.0% of the data. Data was randomly split into a 75% training set and a 25% test set. The test set has 50 high quality wines.</p>

<div class="no-row-height column-margin column-container"><div class="">
<p>This is a good example of how imbalanced data can really make your data feel even smaller. We start with a decent amount of data, but only a small fraction of it is high quality wine, and our test set used for evaluation will only have 50 high quality wines. This is not a lot to work with, and results in noisy metrics based on classification, where just a slight change in the predictions could lead to a noticeable change in the metric. For example, if we had an accuracy of say, 80%, the lower and upper bound estimate would be 66% and 90%, respectively, which is a wide range.</p>
</div></div></section>
<section id="models" class="level3">
<h3 class="anchored" data-anchor-id="models">Models</h3>
<p>We use two base models, a standard logistic regression model via <span class="pack">sklearn</span> and a boosting model via <span class="pack">LightGBM</span>. Both use all non-target columns as features. We will compare the performance of the following models:</p>
<ul>
<li>Basic approach that does nothing for imbalance and uses a threshold of 0.5</li>
<li>Basic approach that uses an ‘optimal’ threshold for classification</li>
<li>A weighted model (using <code>class_weight='balanced'</code> for the logistic and <code>is_unbalance=True</code> for the LGBM)<sup>6</sup></li>
<li>A random oversampling approach (oversampling) <sup>7</sup></li>
</ul>
<p>The optimal threshold can be determined in a variety of ways, and one can look at the supplemental section for more details on choosing the optimal threshold. Here we used a threshold that maximizes the F-beta score on test, with beta = 2. This means we are giving more weight to recall than precision, which is often the case in imbalanced settings<sup>8</sup>.</p>
<p>In addition, LGBM models were compared both with and without tuning. The latter case makes a more straightforward comparison since the parameters are identical in each case. But realistically, we would tune this type of model, so we include models tuned for number of estimators/trees, learning rate, and max depth<sup>9</sup>.</p>
<p>Metrics and other exploration that follows focuses on the test set. We will also look at the calibration curves for some models, which can help us understand how well the predicted probabilities align with the observed class proportions.</p>
</section>
<section id="metrics" class="level3">
<h3 class="anchored" data-anchor-id="metrics">Metrics</h3>
<p>Now let’s get to some results. Along with several metrics we’ve already discussed, we’ve added a few others including:</p>
<ul>
<li><em>Brier Score</em>: A measure of the mean squared difference between predicted probabilities and the true outcome. This is equivalent to the MSE for a binary target. Lower is better <span class="citation" data-cites="harrell_damage_2017">(see Harrell 2017 for additional perspective)</span>.</li>
<li><em>Adaptive Calibration Error</em>: A measure of the calibration of the model. Lower is better <span class="citation" data-cites="nixon_measuring_2020">(see Nixon et al. 2020)</span>.</li>
<li><em>FPR</em>: False Positive Rate.</li>
<li><em>FNR</em>: False Negative Rate.</li>
</ul>
<p>These metrics help us shift focus to the calibration of the model and penalties for misclassification. For each of these we’d prefer lower values. In addition, we looked at the <em>F2 Score</em>, a variant of the F-score that gives more weight to recall than precision. This is useful when false negatives are more costly than false positives, such as in fraud detection or disease diagnosis. As with F1, higher is better.</p>
</section>
<section id="logistic-model-results" class="level3">
<h3 class="anchored" data-anchor-id="logistic-model-results">Logistic Model Results</h3>
<p>With these in mind, let’s look at the logistic model results. We’ll first focus on metrics that are based on the predicted classes. For metric definitions used in all the tables, see the supplemental section. Best values are bolded/blue.</p>
<div class="cell" data-execution_count="10">
<div id="tbl-class-metrics-logistic" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="10">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-class-metrics-logistic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;4: Test Set Model Classification Metrics for Logistic Regression
</figcaption>
<div aria-describedby="tbl-class-metrics-logistic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display" data-execution_count="10">
<div id="qatnmwsoug" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#qatnmwsoug table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<tr class="gt_col_headings">
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Model">Model</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Threshold">Threshold</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Mean Pred">Mean Pred</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Precision">Precision</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Recall">Recall</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="F1 Score">F1 Score</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="F2 Score">F2 Score</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="FPR">FPR</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="FNR">FNR</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Total Pos Pred">Total Pos Pred</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Threshold Method">Threshold Method</th>
</tr>
</thead>
<tbody class="gt_table_body">
  <tr>
    <td class="gt_row gt_left">Logistic Basic</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.031</td>
    <td class="gt_row gt_right">0.000</td>
    <td class="gt_row gt_right">0.000</td>
    <td class="gt_row gt_right">0.000</td>
    <td class="gt_row gt_right">0.000</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.001</td>
    <td class="gt_row gt_right">1.000</td>
    <td class="gt_row gt_right">1</td>
    <td class="gt_row gt_left">Default</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">Logistic Basic (T)</td>
    <td class="gt_row gt_right">0.063</td>
    <td class="gt_row gt_right">0.031</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.105</td>
    <td class="gt_row gt_right">0.500</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.174</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.286</td>
    <td class="gt_row gt_right">0.135</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">237</td>
    <td class="gt_row gt_left">F2</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">Logistic Over</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.350</td>
    <td class="gt_row gt_right">0.062</td>
    <td class="gt_row gt_right">0.580</td>
    <td class="gt_row gt_right">0.112</td>
    <td class="gt_row gt_right">0.217</td>
    <td class="gt_row gt_right">0.279</td>
    <td class="gt_row gt_right">0.420</td>
    <td class="gt_row gt_right">468</td>
    <td class="gt_row gt_left">Default</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">Logistic Weighted</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.350</td>
    <td class="gt_row gt_right">0.066</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.600</td>
    <td class="gt_row gt_right">0.119</td>
    <td class="gt_row gt_right">0.229</td>
    <td class="gt_row gt_right">0.270</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.400</td>
    <td class="gt_row gt_right">456</td>
    <td class="gt_row gt_left">Default</td>
  </tr>
</tbody>
  <tfoot class="gt_sourcenotes">
  
  <tr>
    <td class="gt_sourcenote" colspan="11">(T) means that classification is based on an optimal threshold, but the model is the same as the corresponding "Basic" model. See the supplemental section for details.</td>
  </tr>

</tfoot>

</table>

</div>
        
</div>
</div>
</figure>
</div>
</div>
<p>The basic logistic with default threshold of 0.5 does very poorly, predicting only 1 positive case, and it doesn’t even get that right! Shifting to a lower threshold for this model (~0.063) improves most metrics, and it’s better than the weighted and resampling approaches on several metrics. However, the threshold improvement is no free lunch - we now classify 237 cases as positive, which is probably too many. As a result, the FPR is increased.</p>
<p>The sampling and weighted approaches come to the same conclusions, which is expected for logistic regression. While both would be better than doing nothing at all, both predict far too many positive cases, ~9 times what’s observed in the data! The mean predicted probability is also high (~0.35), which is a sign that the model is overpredicting the minority class. However, this makes sense when considering the fact that the training data was resampled to a balanced state, or the model was estimated as if it were via weighting.</p>
<p>Now let’s look at the metrics that are based on the predicted probabilities. Again, consult the supplemental section for brief definitions of these metrics. Since thresholding doesn’t matter here, we exclude it from the table, as it’s identical to the basic model.</p>
<div class="cell" data-execution_count="11">
<div id="tbl-prob-metrics-logistic" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="11">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-prob-metrics-logistic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;5: Test Set Model Probability Metrics for Logistic Regression
</figcaption>
<div aria-describedby="tbl-prob-metrics-logistic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display" data-execution_count="11">
<div id="wbsfbfxyvd" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#wbsfbfxyvd table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<tr class="gt_col_headings">
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Model">Model</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Threshold">Threshold</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Mean Pred">Mean Pred</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="AUROC">AUROC</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Avg Prec">Avg Prec</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Brier Score">Brier Score</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="ACE">ACE</th>
</tr>
</thead>
<tbody class="gt_table_body">
  <tr>
    <td class="gt_row gt_left">Logistic Basic</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.031</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.752</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.093</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.030</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.015</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">Logistic Over</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.350</td>
    <td class="gt_row gt_right">0.744</td>
    <td class="gt_row gt_right">0.084</td>
    <td class="gt_row gt_right">0.186</td>
    <td class="gt_row gt_right">0.319</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">Logistic Weighted</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.350</td>
    <td class="gt_row gt_right">0.752</td>
    <td class="gt_row gt_right">0.084</td>
    <td class="gt_row gt_right">0.183</td>
    <td class="gt_row gt_right">0.318</td>
  </tr>
</tbody>
  <tfoot class="gt_sourcenotes">
  
  <tr>
    <td class="gt_sourcenote" colspan="7">(T) means that classification is based on an optimal threshold, but the model is the same as the corresponding "Basic" model. See the supplemental section for details.</td>
  </tr>

</tfoot>

</table>

</div>
        
</div>
</div>
</figure>
</div>
</div>
<p>While AUROC and average precision aren’t too different among the models, note how the Brier score and ACE are notably lower for the basic model. This suggests better calibration. Let’s see what this looks like in the <a href="https://scikit-learn.org/stable/auto_examples/calibration/plot_calibration_curve.html">calibration curves</a> and the predicted probabilities.</p>
<div id="cell-fig-calibration-logistic" class="cell" data-execution_count="12">
<div class="cell-output cell-output-display">
<div id="fig-calibration-logistic" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-calibration-logistic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://m-clark.github.io/posts/2025-04-07-class-imbalance/index_files/figure-html/fig-calibration-logistic-output-1.png" width="768" height="576" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-calibration-logistic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4: Calibration Curves for Logistic Regression
</figcaption>
</figure>
</div>
</div>
</div>
<p><br></p>
<p>We can see in Figure&nbsp;4 that the basic model predicted probabilities are well-calibrated, which is also reflected in the notably lower Brier and ACE scores. Weighting and resampling lead to over-prediction of the minority class. We can see this by also examining the predicted probabilities directly, as in Figure&nbsp;5. Their mean prediction is well beyond the observed rate<sup>10</sup>.</p>
<div id="cell-fig-predicted-probs-logistic" class="cell" data-execution_count="13">
<div class="cell-output cell-output-display">
<div id="fig-predicted-probs-logistic" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-predicted-probs-logistic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://m-clark.github.io/posts/2025-04-07-class-imbalance/index_files/figure-html/fig-predicted-probs-logistic-output-1.png" width="768" height="576" class="figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-predicted-probs-logistic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;5: Predicted Probabilities for Logistic Regression
</figcaption>
</figure>
</div>
</div>
</div>
</section>
<section id="lgbm-model-results" class="level3">
<h3 class="anchored" data-anchor-id="lgbm-model-results">LGBM Model Results</h3>
<p>Now let’s look at the LGBM model results, starting with the classification metrics.</p>
<div class="cell" data-execution_count="15">
<div id="tbl-class-metrics-lgbm" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="15">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-class-metrics-lgbm-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;6: Test Set Model Classification Metrics for LGBM MOdel
</figcaption>
<div aria-describedby="tbl-class-metrics-lgbm-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display" data-execution_count="15">
<div id="nallcdadis" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#nallcdadis table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<tr class="gt_col_headings">
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Model">Model</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Tuned">Tuned</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Threshold">Threshold</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Mean Pred">Mean Pred</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Precision">Precision</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Recall">Recall</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="F1 Score">F1 Score</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="F2 Score">F2 Score</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="FPR">FPR</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="FNR">FNR</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Total Pos Pred">Total Pos Pred</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Threshold Method">Threshold Method</th>
</tr>
</thead>
<tbody class="gt_table_body">
  <tr>
    <td class="gt_row gt_left">LGBM Basic</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.022</td>
    <td class="gt_row gt_right">0.840</td>
    <td class="gt_row gt_right">0.420</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.560</td>
    <td class="gt_row gt_right">0.467</td>
    <td class="gt_row gt_right">0.003</td>
    <td class="gt_row gt_right">0.580</td>
    <td class="gt_row gt_right">25</td>
    <td class="gt_row gt_left">Default</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Basic</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.028</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">1.000</td>
    <td class="gt_row gt_right">0.320</td>
    <td class="gt_row gt_right">0.485</td>
    <td class="gt_row gt_right">0.370</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.000</td>
    <td class="gt_row gt_right">0.680</td>
    <td class="gt_row gt_right">16</td>
    <td class="gt_row gt_left">Default</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Basic (T)</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_right">0.028</td>
    <td class="gt_row gt_right">0.022</td>
    <td class="gt_row gt_right">0.256</td>
    <td class="gt_row gt_right">0.620</td>
    <td class="gt_row gt_right">0.363</td>
    <td class="gt_row gt_right">0.483</td>
    <td class="gt_row gt_right">0.057</td>
    <td class="gt_row gt_right">0.380</td>
    <td class="gt_row gt_right">121</td>
    <td class="gt_row gt_left">F2</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Basic (T)</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_right">0.061</td>
    <td class="gt_row gt_right">0.028</td>
    <td class="gt_row gt_right">0.228</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.660</td>
    <td class="gt_row gt_right">0.338</td>
    <td class="gt_row gt_right">0.478</td>
    <td class="gt_row gt_right">0.071</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.340</td>
    <td class="gt_row gt_right">145</td>
    <td class="gt_row gt_left">F2</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Over</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.041</td>
    <td class="gt_row gt_right">0.522</td>
    <td class="gt_row gt_right">0.480</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.488</td>
    <td class="gt_row gt_right">0.014</td>
    <td class="gt_row gt_right">0.520</td>
    <td class="gt_row gt_right">46</td>
    <td class="gt_row gt_left">Default</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Over</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.020</td>
    <td class="gt_row gt_right">0.759</td>
    <td class="gt_row gt_right">0.440</td>
    <td class="gt_row gt_right">0.557</td>
    <td class="gt_row gt_right">0.480</td>
    <td class="gt_row gt_right">0.004</td>
    <td class="gt_row gt_right">0.560</td>
    <td class="gt_row gt_right">29</td>
    <td class="gt_row gt_left">Default</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Weighted</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.045</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.500</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.016</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">50</td>
    <td class="gt_row gt_left">Default</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Weighted</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.051</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.460</td>
    <td class="gt_row gt_right">0.479</td>
    <td class="gt_row gt_right">0.467</td>
    <td class="gt_row gt_right">0.015</td>
    <td class="gt_row gt_right">0.540</td>
    <td class="gt_row gt_right">46</td>
    <td class="gt_row gt_left">Default</td>
  </tr>
</tbody>
  <tfoot class="gt_sourcenotes">
  
  <tr>
    <td class="gt_sourcenote" colspan="12">(T) means that classification is based on an optimal threshold, but the model is the same as the corresponding "Basic" model. See the supplemental section for details.</td>
  </tr>

</tfoot>

</table>

</div>
        
</div>
</div>
</figure>
</div>
</div>
<p>There’s more to digest here, but in general we see the following:</p>
<ul>
<li>Unsurprisingly, these models did better than the logistic model approaches.</li>
<li>The basic model with or without thresholding/tuning did better on several metrics than the weighted and resampling approaches.</li>
<li>The issues with weighting and resampling were far less pronounced in the LGBM models, but were still present. For example, the mean predictions are higher than the basic models, and higher than the base rate, except for the over-sampled with tuning model.</li>
<li>We also saw that the thresholding approach still led to far more predicted positives than would be expected, and with it, a higher false positive rate.</li>
</ul>
<p>A couple other things to note. One model has perfect precision! However it comes at the cost of the highest false negative rate/lowest recall. In addition, our optimal threshold was chosen based on the value that maximized F2, but that model did not have the highest F2 score of all models. They did have the highest recall however, which is what F2 puts more weight on.</p>
<p>Now let’s look at the probability-based metrics. Again the thresholding results are removed as they aren’t applicable and duplicate the basic models.</p>
<div class="cell" data-execution_count="16">
<div id="tbl-prob-metrics-lgbm" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="16">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-prob-metrics-lgbm-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;7: Test Set Model Probability Metrics for LGBM Model
</figcaption>
<div aria-describedby="tbl-prob-metrics-lgbm-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display" data-execution_count="16">
<div id="gtdzqasuoe" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#gtdzqasuoe table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<tr class="gt_col_headings">
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Model">Model</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Tuned">Tuned</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Threshold">Threshold</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Mean Pred">Mean Pred</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="AUROC">AUROC</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Avg Prec">Avg Prec</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Brier Score">Brier Score</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="ACE">ACE</th>
</tr>
</thead>
<tbody class="gt_table_body">
  <tr>
    <td class="gt_row gt_left">LGBM Basic</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.022</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.878</td>
    <td class="gt_row gt_right">0.521</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.019</td>
    <td class="gt_row gt_right">0.011</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Basic</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.028</td>
    <td class="gt_row gt_right">0.876</td>
    <td class="gt_row gt_right">0.510</td>
    <td class="gt_row gt_right">0.020</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.008</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Over</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.041</td>
    <td class="gt_row gt_right">0.849</td>
    <td class="gt_row gt_right">0.515</td>
    <td class="gt_row gt_right">0.026</td>
    <td class="gt_row gt_right">0.031</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Over</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.020</td>
    <td class="gt_row gt_right">0.850</td>
    <td style="color: #0072B2;font-weight: 800;" class="gt_row gt_right">0.526</td>
    <td class="gt_row gt_right">0.020</td>
    <td class="gt_row gt_right">0.014</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Weighted</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.045</td>
    <td class="gt_row gt_right">0.852</td>
    <td class="gt_row gt_right">0.519</td>
    <td class="gt_row gt_right">0.027</td>
    <td class="gt_row gt_right">0.029</td>
  </tr>
  <tr>
    <td class="gt_row gt_left">LGBM Weighted</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_right">0.500</td>
    <td class="gt_row gt_right">0.051</td>
    <td class="gt_row gt_right">0.850</td>
    <td class="gt_row gt_right">0.518</td>
    <td class="gt_row gt_right">0.027</td>
    <td class="gt_row gt_right">0.034</td>
  </tr>
</tbody>
  <tfoot class="gt_sourcenotes">
  
  <tr>
    <td class="gt_sourcenote" colspan="8">(T) means that classification is based on an optimal threshold, but the model is the same as the corresponding "Basic" model. See the supplemental section for details.</td>
  </tr>

</tfoot>

</table>

</div>
        
</div>
</div>
</figure>
</div>
</div>
<p>Much the same story - neither weighting nor over-sampling helped much here. In general, all models performed pretty similarly on these metrics, though we might think the basic models did a bit better on AUROC.</p>
</section>
</section>
<section id="discussion" class="level2">
<h2 class="anchored" data-anchor-id="discussion">Discussion</h2>
<p>In general, any of these model approaches might be viable, as the choice may depend mostly on your tolerance for certain types of classification errors. For example, if you are more concerned with false positives, i.e.&nbsp;you really don’t want to classify a wine as good if it’s not, you might *not* prefer the thresholding models, or maybe use a thresholding approach that emphasizes precision. On the other hand, if you are more concerned with correctly judging a good wine as good, you might prefer the thresholding LGBM models that did better on recall.</p>
<p>It’s worth pointing out that many metrics are very correlated with, or even directly dependent, upon one another. For example, if positive predictions are increased with a lower threshold, then the true positive rate will potentially increase, but the false positive rate might increase as well. Any metrics that are based on these rates will also necessarily change. This is why it’s important to consider the actual classifications and the trade-offs that come with them. Choosing a model based on one metric may be essentially equivalent to choosing one based on another metric.</p>
<p>Note again that several of the metrics are based on the predicted probabilities, not the classifications, so the reported value will not change with the classification threshold. For model selection, you might be better off using these, or the standard loss function for the model, rather than the classification metrics that can be easily manipulated. This would be more the case in smaller data settings or very rare positive rates, where metric values could swing wildly with only slightly different classifications.</p>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>In this post, we explored various techniques for handling imbalanced data, including sampling-based and algorithmic methods. We demonstrated the impact of different classification thresholds on performance metrics, and discussed the importance of selecting appropriate metrics for the situation. Our case study on wine quality data highlighted the practical application of these techniques and their effect on model performance. In general, we saw that simple approaches often work well.</p>
<p>Key takeaways:</p>
<ul>
<li>Imbalanced data is common in real-world settings, and can lead to issues with various model performance metrics.</li>
<li>There are a number of ways to approach imbalanced data, including sampling-based and algorithmic techniques.</li>
<li>Using the default classification threshold of 0.5 may not be appropriate for classification with imbalanced data, and selecting an optimal threshold may prove beneficial.</li>
<li>Depending on the setting, <em>you can do nothing and possibly be just fine</em>. But if you need to do something, simple approaches often do the job.</li>
<li>With metrics that depend on classification, you need to carefully consider the trade-offs that come with them.</li>
<li>Focusing on metrics that don’t rely on classification threshold can potentially help you avoid the pitfalls associated with class imbalance.</li>
</ul>
<p>In conclusion, while class imbalance may present challenges for model development and evaluation, the solutions need not be complex. The key is to understand your specific use case—what types of errors are most costly, what metrics align with your goals, and what trade-offs you’re willing to make. Hopefully this exploration has provided you with practical insights and a clear framework for tackling imbalanced data in your own work.</p>
</section>
<section id="sec-supplemental" class="level2">
<h2 class="anchored" data-anchor-id="sec-supplemental">Supplemental</h2>
<section id="sec-supp-metrics" class="level3">
<h3 class="anchored" data-anchor-id="sec-supp-metrics">Table Metrics</h3>
<p>The first table for logistic and LGBM models shows the following metrics. An arrow (↑ or ↓) indicates whether a higher or lower value is better for the metric.</p>
<ul>
<li><em>Threshold</em>: the threshold value used for classification.</li>
<li><em>Mean Pred</em>: the mean predicted probability for the positive class. Ideally this should be close to the observed proportion of positive cases.</li>
<li><em>Precision</em>: the proportion of correctly predicted positive cases among all predicted positive cases. ↑</li>
<li><em>Recall</em>: the proportion of correctly predicted positive cases among all actual positive cases. ↑</li>
<li><em>F1 Score</em>: the harmonic mean of precision and recall. ↑</li>
<li><em>F2 Score</em>: a variant of the F1 score that gives more weight to recall. ↑</li>
<li><em>FPR</em>: False Positive Rate, the proportion of incorrectly predicted positive cases among all actual negative cases. ↓</li>
<li><em>FNR</em>: False Negative Rate, the proportion of incorrectly predicted negative cases among all actual positive cases. ↓</li>
<li><em>Total Pos Pred</em>: the total number of positive predictions.</li>
<li><em>Threshold Method</em>: the method used to select the classification threshold.</li>
</ul>
<p>The second table shows the following metrics:</p>
<ul>
<li><em>Threshold</em>: the threshold/cutoff value used for classification.</li>
<li><em>Mean Pred</em>: the mean predicted probability for the positive class.</li>
<li><em>AUROC</em>: the area under the receiver operating characteristic curve. ↑</li>
<li><em>Avg Prec</em>: the average precision (area under the precision-recall curve). ↑</li>
<li><em>Brier Score</em>: a measure of the mean squared difference between predicted probabilities and the true outcome. ↓</li>
<li><em>ACE</em>: the adaptive calibration error (<span class="citation" data-cites="nixon_measuring_2020">Nixon et al. (2020)</span>). ↓</li>
</ul>
</section>
<section id="sec-supp-multiclass" class="level3">
<h3 class="anchored" data-anchor-id="sec-supp-multiclass">Brief Discussion of the Multiclass Setting</h3>
<p>While we’ve focused on binary classification, many real-world problems involve more than two classes. Multiclass settings can present additional challenges with imbalanced data, as the relationships between classes become more complex and the interpretation of performance metrics needs adjustment.</p>
<p>In multiclass settings, we often use the same core metrics as in binary classification (precision, recall, F1, etc.), but we need to consider how to aggregate these metrics across classes. Two common approaches are:</p>
<p><strong>Weighted Average</strong>: This approach takes into account the number of instances in each class. Each class’s metric is weighted by the proportion of instances in that class. It may be useful when you want to account for class imbalance to ensure that metrics from larger classes have a greater impact on the overall score.</p>
<p><strong>Macro Average</strong>: This approach calculates the metric independently for each class and then takes the average of these metrics. Each class is treated equally, regardless of its size. It is useful when you want to ensure that the model performance assessment is consistent across all classes, rather than being dominated by the performance on the more frequent classes.</p>
<p>As in the binary case, the choice between these approaches depends on your specific goals. Use weighted averaging when you want metrics to reflect the natural class distribution, and macro averaging when you want to ensure consistent performance across all classes.</p>
</section>
<section id="sec-supp-thresh" class="level3">
<h3 class="anchored" data-anchor-id="sec-supp-thresh">Choosing a Classification Threshold</h3>
<p>As we have noted, the default threshold of 0.5 is often used as a classification threshold, but it may not be optimal in many cases, particularly in the imbalanced setting. Each of these and other similar methods have their own advantages and may be suitable for different scenarios. Here are some common methods for selecting a classification threshold:</p>
<ol type="1">
<li><p><strong>Metric Optimization</strong>: Choose a threshold that maximizes or minimizes a specific metric:</p>
<ul>
<li><strong>F-Beta Scores</strong>: Adjust the β parameter to weight the relative importance of precision vs.&nbsp;recall. <img src="https://latex.codecogs.com/png.latex?F_1"> gives equal weight, <img src="https://latex.codecogs.com/png.latex?F_2"> favors recall, and <img src="https://latex.codecogs.com/png.latex?F_%7B.5%7D"> favors precision.</li>
<li><strong>Precision-Recall Trade-off</strong>: Select a threshold based on the precision-recall curve to achieve desired balance between these metrics.</li>
<li><strong>ROC-based</strong>: Choose the threshold that maximizes the geometric mean of sensitivity and specificity.</li>
</ul></li>
<li><p><strong>Cost-Sensitive Thresholding</strong>: This involves selecting a threshold that minimizes the overall cost of misclassification. This can be done by assigning different weights to false positives and false negatives and choosing the threshold that results in the lowest weighted error. This does not require an algorithmic approach though, as you can just select a threshold based on domain knowledge.</p></li>
<li><p><strong>Other Statistical Approaches</strong>:</p>
<ul>
<li><strong>Youden’s J Statistic</strong>: Youden’s J is defined as sensitivity + specificity - 1. This approach maximizes the sum of sensitivity and specificity, and is equivalent to maximizing vertical distance from ROC curve to diagonal.</li>
<li><strong>Equal Error Rate (EER)</strong>: Sets threshold where false positive rate equals false negative rate.</li>
</ul></li>
<li><p><strong>Data-driven</strong>: Use the observed class proportion (base rate) as the threshold, which may be appropriate when you want predictions to reflect the natural class distribution. This is simple and good for a quick baseline, but may not be optimal in all cases.</p></li>
</ol>
<p>For this post, we explored using different thresholds out of curiosity, and here are the results for the LGBM (Basic) models, and only those metrics that are actually affected by the threshold. The different methods explored included optimizing AUROC (<code>ROC</code>), AUPRC (<code>PRC</code>), F.5, F1, and F2 (<code>F*</code>), and simply using the base rate/observed proportion as a cutoff (<code>Obs. Prop.</code>). In the following, the untuned model parameters are identical, and the tuned models are also identical. Within each of those groups, the only difference is the threshold method used. All metrics regard the test set.</p>
<div class="cell" data-execution_count="18">
<div id="tbl-threshold-methods" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="18">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-threshold-methods-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;8: Comparison of Threshold Methods for the LGBM Models
</figcaption>
<div aria-describedby="tbl-threshold-methods-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display" data-execution_count="18">
<div id="zayyrdudda" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>
#zayyrdudda table {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', 'Fira Sans', 'Droid Sans', Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

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

<tr class="gt_col_headings">
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Threshold">Threshold</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Precision">Precision</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Recall">Recall</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="F.5 Score">F.5 Score</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="F1 Score">F1 Score</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="F2 Score">F2 Score</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="FPR">FPR</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="FNR">FNR</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="Total Pos Pred">Total Pos Pred</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Tuned">Tuned</th>
  <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="Optimization Method">Optimization Method</th>
</tr>
</thead>
<tbody class="gt_table_body">
  <tr>
    <td class="gt_row gt_right">0.00</td>
    <td class="gt_row gt_right">0.09</td>
    <td class="gt_row gt_right">0.82</td>
    <td class="gt_row gt_right">0.12</td>
    <td class="gt_row gt_right">0.17</td>
    <td class="gt_row gt_right">0.32</td>
    <td class="gt_row gt_right">0.25</td>
    <td class="gt_row gt_right">0.18</td>
    <td class="gt_row gt_right">433</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_left">ROC</td>
  </tr>
  <tr>
    <td class="gt_row gt_right">0.72</td>
    <td class="gt_row gt_right">1.00</td>
    <td class="gt_row gt_right">0.40</td>
    <td class="gt_row gt_right">0.77</td>
    <td class="gt_row gt_right">0.57</td>
    <td class="gt_row gt_right">0.45</td>
    <td class="gt_row gt_right">0.00</td>
    <td class="gt_row gt_right">0.60</td>
    <td class="gt_row gt_right">20</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_left">F.5</td>
  </tr>
  <tr>
    <td class="gt_row gt_right">0.58</td>
    <td class="gt_row gt_right">0.91</td>
    <td class="gt_row gt_right">0.42</td>
    <td class="gt_row gt_right">0.74</td>
    <td class="gt_row gt_right">0.58</td>
    <td class="gt_row gt_right">0.47</td>
    <td class="gt_row gt_right">0.00</td>
    <td class="gt_row gt_right">0.58</td>
    <td class="gt_row gt_right">23</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_left">F1</td>
  </tr>
  <tr>
    <td class="gt_row gt_right">0.03</td>
    <td class="gt_row gt_right">0.26</td>
    <td class="gt_row gt_right">0.62</td>
    <td class="gt_row gt_right">0.29</td>
    <td class="gt_row gt_right">0.36</td>
    <td class="gt_row gt_right">0.48</td>
    <td class="gt_row gt_right">0.06</td>
    <td class="gt_row gt_right">0.38</td>
    <td class="gt_row gt_right">121</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_left">F2</td>
  </tr>
  <tr>
    <td class="gt_row gt_right">0.72</td>
    <td class="gt_row gt_right">1.00</td>
    <td class="gt_row gt_right">0.40</td>
    <td class="gt_row gt_right">0.77</td>
    <td class="gt_row gt_right">0.57</td>
    <td class="gt_row gt_right">0.45</td>
    <td class="gt_row gt_right">0.00</td>
    <td class="gt_row gt_right">0.60</td>
    <td class="gt_row gt_right">20</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_left">PRC</td>
  </tr>
  <tr>
    <td class="gt_row gt_right">0.03</td>
    <td class="gt_row gt_right">0.26</td>
    <td class="gt_row gt_right">0.60</td>
    <td class="gt_row gt_right">0.29</td>
    <td class="gt_row gt_right">0.36</td>
    <td class="gt_row gt_right">0.48</td>
    <td class="gt_row gt_right">0.05</td>
    <td class="gt_row gt_right">0.40</td>
    <td class="gt_row gt_right">115</td>
    <td class="gt_row gt_left">Not</td>
    <td class="gt_row gt_left">Obs. Prop.</td>
  </tr>
  <tr>
    <td class="gt_row gt_right">0.06</td>
    <td class="gt_row gt_right">0.23</td>
    <td class="gt_row gt_right">0.66</td>
    <td class="gt_row gt_right">0.26</td>
    <td class="gt_row gt_right">0.34</td>
    <td class="gt_row gt_right">0.48</td>
    <td class="gt_row gt_right">0.07</td>
    <td class="gt_row gt_right">0.34</td>
    <td class="gt_row gt_right">145</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_left">ROC</td>
  </tr>
  <tr>
    <td class="gt_row gt_right">0.45</td>
    <td class="gt_row gt_right">0.95</td>
    <td class="gt_row gt_right">0.36</td>
    <td class="gt_row gt_right">0.71</td>
    <td class="gt_row gt_right">0.52</td>
    <td class="gt_row gt_right">0.41</td>
    <td class="gt_row gt_right">0.00</td>
    <td class="gt_row gt_right">0.64</td>
    <td class="gt_row gt_right">19</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_left">F.5</td>
  </tr>
  <tr>
    <td class="gt_row gt_right">0.34</td>
    <td class="gt_row gt_right">0.75</td>
    <td class="gt_row gt_right">0.42</td>
    <td class="gt_row gt_right">0.65</td>
    <td class="gt_row gt_right">0.54</td>
    <td class="gt_row gt_right">0.46</td>
    <td class="gt_row gt_right">0.00</td>
    <td class="gt_row gt_right">0.58</td>
    <td class="gt_row gt_right">28</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_left">F1</td>
  </tr>
  <tr>
    <td class="gt_row gt_right">0.06</td>
    <td class="gt_row gt_right">0.23</td>
    <td class="gt_row gt_right">0.66</td>
    <td class="gt_row gt_right">0.26</td>
    <td class="gt_row gt_right">0.34</td>
    <td class="gt_row gt_right">0.48</td>
    <td class="gt_row gt_right">0.07</td>
    <td class="gt_row gt_right">0.34</td>
    <td class="gt_row gt_right">145</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_left">F2</td>
  </tr>
  <tr>
    <td class="gt_row gt_right">0.40</td>
    <td class="gt_row gt_right">0.90</td>
    <td class="gt_row gt_right">0.38</td>
    <td class="gt_row gt_right">0.71</td>
    <td class="gt_row gt_right">0.54</td>
    <td class="gt_row gt_right">0.43</td>
    <td class="gt_row gt_right">0.00</td>
    <td class="gt_row gt_right">0.62</td>
    <td class="gt_row gt_right">21</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_left">PRC</td>
  </tr>
  <tr>
    <td class="gt_row gt_right">0.03</td>
    <td class="gt_row gt_right">0.13</td>
    <td class="gt_row gt_right">0.68</td>
    <td class="gt_row gt_right">0.15</td>
    <td class="gt_row gt_right">0.21</td>
    <td class="gt_row gt_right">0.36</td>
    <td class="gt_row gt_right">0.15</td>
    <td class="gt_row gt_right">0.32</td>
    <td class="gt_row gt_right">270</td>
    <td class="gt_row gt_left">Tuned</td>
    <td class="gt_row gt_left">Obs. Prop.</td>
  </tr>
</tbody>


</table>

</div>
        
</div>
</div>
</figure>
</div>
</div>
<p>In our case study, thresholding that was relatively more focused on precision (F.5/AUPRC) led to a high threshold, few positive predictions, and a low false positive rate. Thresholding that was relatively more focused on recall (F2) led to a notably lower threshold than .5, more positive predictions, and a higher false positive rate. The geometric mean/ROC approach led to the most positive predictions, and thus a notably high false positive rate, but also a lower false negative rate. By coincidence, the ROC and F2 approaches led to the same classification for the tuned model.</p>
<p>We ultimately chose the F2 threshold approach for the reported tables because we were interested in recall, and the ROC approach led to too many positives for the untuned model. However, there’s no reason for this choice other than our personal preference, and the other approaches could be just as valid depending on your own goals for wine classification. Cheers! 🍷</p>



</section>
</section>


<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-brownlee_how_2018" class="csl-entry">
Brownlee, Jason. 2018. <span>“How to <span>Use</span> <span>ROC</span> <span>Curves</span> and <span>Precision</span>-<span>Recall</span> <span>Curves</span> for <span>Classification</span> in <span>Python</span>.”</span> In <em>MachineLearningMastery.com</em>. <a href="https://www.machinelearningmastery.com/roc-curves-and-precision-recall-curves-for-classification-in-python/">https://www.machinelearningmastery.com/roc-curves-and-precision-recall-curves-for-classification-in-python/</a>.
</div>
<div id="ref-elor_smote_2022" class="csl-entry">
Elor, Yotam, and Hadar Averbuch-Elor. 2022. <em>To <span>SMOTE</span>, or Not to <span>SMOTE</span>?</em> arXiv. <a href="https://doi.org/10.48550/arXiv.2201.08528">https://doi.org/10.48550/arXiv.2201.08528</a>.
</div>
<div id="ref-foret_sharpness-aware_2021" class="csl-entry">
Foret, Pierre, Ariel Kleiner, Hossein Mobahi, and Behnam Neyshabur. 2021. <em>Sharpness-<span>Aware</span> <span>Minimization</span> for <span>Efficiently</span> <span>Improving</span> <span>Generalization</span></em>. arXiv. <a href="https://doi.org/10.48550/arXiv.2010.01412">https://doi.org/10.48550/arXiv.2010.01412</a>.
</div>
<div id="ref-google_classification_2025" class="csl-entry">
Google. 2025. <span>“Classification: <span>ROC</span> and <span>AUC</span> <span></span> <span>Machine</span> <span>Learning</span>.”</span> In <em>Google for Developers</em>. <a href="https://developers.google.com/machine-learning/crash-course/classification/roc-and-auc">https://developers.google.com/machine-learning/crash-course/classification/roc-and-auc</a>.
</div>
<div id="ref-van_den_goorbergh_harm_2022" class="csl-entry">
Goorbergh, Ruben van den, Maarten van Smeden, Dirk Timmerman, and Ben Van Calster. 2022. <span>“The Harm of Class Imbalance Corrections for Risk Prediction Models: Illustration and Simulation Using Logistic Regression.”</span> <em>Journal of the American Medical Informatics Association: JAMIA</em> 29 (9): 1525–34. <a href="https://doi.org/10.1093/jamia/ocac093">https://doi.org/10.1093/jamia/ocac093</a>.
</div>
<div id="ref-harrell_damage_2017" class="csl-entry">
Harrell, Frank. 2017. <span>“Damage <span>Caused</span> by <span>Classification</span> <span>Accuracy</span> and <span>Other</span> <span>Discontinuous</span> <span>Improper</span> <span>Accuracy</span> <span>Scoring</span> <span>Rules</span>.”</span> In <em>Statistical Thinking</em>. <a href="https://www.fharrell.com/post/class-damage/">https://www.fharrell.com/post/class-damage/</a>.
</div>
<div id="ref-kuhn_optimizing_2014" class="csl-entry">
Kuhn, Max. 2014. <span>“Optimizing <span>Probability</span> <span>Thresholds</span> for <span>Class</span> <span>Imbalances</span>.”</span> In <em>Applied Predictive Modeling</em>. <a href="http://appliedpredictivemodeling.com/blog/2014/2/1/lw6har9oewknvus176q4o41alqw2ow">http://appliedpredictivemodeling.com/blog/2014/2/1/lw6har9oewknvus176q4o41alqw2ow</a>.
</div>
<div id="ref-lin_focal_2018" class="csl-entry">
Lin, Tsung-Yi, Priya Goyal, Ross Girshick, Kaiming He, and Piotr Dollár. 2018. <em>Focal <span>Loss</span> for <span>Dense</span> <span>Object</span> <span>Detection</span></em>. arXiv. <a href="https://doi.org/10.48550/arXiv.1708.02002">https://doi.org/10.48550/arXiv.1708.02002</a>.
</div>
<div id="ref-molnar_dont_2023" class="csl-entry">
Molnar, Christoph. 2023. <span>“Don’t "Fix" Your Imbalanced Data.”</span> Substack newsletter. In <em>Mindful Modeler</em>. <a href="https://mindfulmodeler.substack.com/p/dont-fix-your-imbalanced-data">https://mindfulmodeler.substack.com/p/dont-fix-your-imbalanced-data</a>.
</div>
<div id="ref-nixon_measuring_2020" class="csl-entry">
Nixon, Jeremy, Michael W Dusenberry, Linchuan Zhang, Ghassen Jerfel, and Dustin Tran. 2020. <em>Measuring <span>Calibration</span> in <span>Deep</span> <span>Learning</span></em>. <a href="https://arxiv.org/abs/1904.01685">https://arxiv.org/abs/1904.01685</a>.
</div>
<div id="ref-shwartz-ziv_simplifying_2022" class="csl-entry">
Shwartz-Ziv, Ravid, Micah Goldblum, Yucen Lily Li, C Bayan Bruss, and Andrew Gordon Wilson. 2022. <em>Simplifying <span>Neural</span> <span>Network</span> <span>Training</span> <span>Under</span> <span>Class</span> <span>Imbalance</span></em>. <a href="https://arxiv.org/abs/2312.02517">https://arxiv.org/abs/2312.02517</a>.
</div>
<div id="ref-thomas_problem_2020" class="csl-entry">
Thomas, Rachel, and David Uminsky. 2020. <em>The <span>Problem</span> with <span>Metrics</span> Is a <span>Fundamental</span> <span>Problem</span> for <span>AI</span></em>. arXiv. <a href="https://doi.org/10.48550/arXiv.2002.08512">https://doi.org/10.48550/arXiv.2002.08512</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p><span class="citation" data-cites="shwartz-ziv_simplifying_2022">Shwartz-Ziv et al. (2022)</span> provides a nice overview.↩︎</p></li>
<li id="fn2"><p>Homogenous data has features that are generally from the same source and/or are the same type. For example, a dataset of images would be homogenous, as would a dataset of text. In those settings we likely would only be considering deep learning models, and so the techniques mentioned would be more applicable. In contrast, tabular data is often heterogeneous, with different types of features, and so the techniques mentioned <a href="https://m-clark.github.io/posts/2022-04-01-more-dl-for-tabular/">may not be as performant</a>.↩︎</p></li>
<li id="fn3"><p>It could also go the other way for disease detection, where the cost of a false positive would result in costly or invasive procedures, and so a higher threshold would be preferred. But typically it would likely just result in more testing to confirm the diagnosis, which is not ideal but not as costly.↩︎</p></li>
<li id="fn4"><p>The false positive rate is the complement of the true negative rate, so it is 1 - TNR from the table.↩︎</p></li>
<li id="fn5"><p>There is a way to approximate AUROC from the confusion matrix, but it is not exact, and would change with the threshold.↩︎</p></li>
<li id="fn6"><p>For the weighted models, these default weights are inversely proportional to the class frequencies, meaning the minority class is weighted more heavily while the majority class is weighted less heavily. This is a common default, but it can be adjusted as needed.↩︎</p></li>
<li id="fn7"><p>We don’t look at SMOTE and related techniques, both to keep things simple, and because they rarely outperform simple resampling, especially with models that are typically strong to begin with, like boosting approaches. See <span class="citation" data-cites="molnar_dont_2023">Molnar (2023)</span> or <span class="citation" data-cites="elor_smote_2022">Elor and Averbuch-Elor (2022)</span> for example.↩︎</p></li>
<li id="fn8"><p>Ideally, if we didn’t just choose a metric to optimize for our threshold ahead of time based on the domain setting, the choice could be made via a separate validation process. For our data, this would have been a very noisy result anyway, so for simplicity we just went with using the test set as the thresholding validation.↩︎</p></li>
<li id="fn9"><p>In our exploratory phase we saw that increasing depth appeared to help oversample/weighting approaches (decreased mean prediction, lower brier, ACE, FPR), while less depth and fewer iterations appeared better for the thresholding approach (higher ROC, fewer total positive predictions for thresholding approach).↩︎</p></li>
<li id="fn10"><p>The oversampling and weighting approaches are overpredicting and producing nearly identical results, so are not easily distinguished in the visualization. Again this is expected for logistic regression, as weighting and oversampling are essentially equivalent in this case.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2025,
  author = {Clark, Michael and Clark, Michael},
  title = {Imbalanced {Outcomes}},
  date = {2025-04-07},
  url = {https://m-clark.github.io/posts/2025-04-07-class-imbalance/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2025" class="csl-entry quarto-appendix-citeas">
Clark, Michael, and Michael Clark. 2025. <span>“Imbalanced
Outcomes.”</span> April 7. <a href="https://m-clark.github.io/posts/2025-04-07-class-imbalance/">https://m-clark.github.io/posts/2025-04-07-class-imbalance/</a>.
</div></div></section></div> ]]></description>
  <category>machine learning</category>
  <category>regression</category>
  <category>boosting</category>
  <guid>https://m-clark.github.io/posts/2025-04-07-class-imbalance/</guid>
  <pubDate>Mon, 07 Apr 2025 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/class-imbalance/roc_curve.png" medium="image" type="image/png" height="108" width="144"/>
</item>
<item>
  <title>Some News for the New Year</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2025-01-01-news/</link>
  <description><![CDATA[ 





<section id="update" class="level2">
<h2 class="anchored" data-anchor-id="update">Update</h2>
<p>Among many things that have happened recently, I’ve become a father to a beautiful baby girl, and <a href="https://m-clark.github.io/book-of-models">written a book</a> to come out this year (2025). Fun stuff!</p>
<p>Elsewhere, my employer <a href="https://www.strong.io/">Strong Analytics</a> merged with <a href="https://www.onesixsolutions.com/">OneSix</a> last summer, which has gone well so far. It’s been great to expand our capabilities and personnel, and I’m excited to see what we can do in the future.</p>
<p>Not so fun - I’ve migrated my distill-based website to quarto, something I actually started about a year and a half ago but never completed. I love using Quarto, and highly recommend it, including if you never created a website before, but this particular aspect was not straightforward. So, while my website looks a little better, and hopefully will be easier to maintain moving forward, some minor content may have gotten lost in the shuffle, or may not match up exactly with the previous version. Feel free to post <a href="https://github.com/m-clark/m-clark.github.io/issues">an issue</a> if you notice anything amiss.</p>
</section>
<section id="goals" class="level2">
<h2 class="anchored" data-anchor-id="goals">Goals</h2>
<p>For this website in 2025, there are a couple posts I hope to do:</p>
<ul>
<li>A post on class imbalance Elizabeth and I intended for out work blog, and was mostly complete, but which never was published.</li>
<li>A post I had on conformal prediction that was likewise intended for the work blog, and which was also mostly complete.</li>
<li>A copy of the post I did on media mix modeling, which was <a href="https://www.strong.io/blog/marketing-optimization-media-mix-modeling">posted at strong.io</a> before the merger.</li>
<li>Something new that is of interest</li>
</ul>
<p>I might also orient toward general thoughts on various topics as opposed to code-based demos.</p>
</section>
<section id="migration-issues" class="level2">
<h2 class="anchored" data-anchor-id="migration-issues">Migration Issues</h2>
<p>After a lot of effort, it looks like I finally got my quarto website going. In the end I may have lost some of the previous code content, but my quick assessment is that it likely wasn’t much.</p>
<p>Issues I came across in case it’s useful to others:</p>
<ul>
<li>Getting a specific python environment to work for quarto, possibly per post</li>
<li><a href="https://github.com/quarto-dev/quarto-cli/issues/10276">issue 10276</a></li>
<li><a href="https://github.com/quarto-dev/quarto-cli/issues/5220">issue 5220</a></li>
<li>Deployment error (had to ‘rerun all’ from github repo website itself)</li>
<li>Default radian pointing to wrong python environment, which would then automatically load that environment and ignore any other env setting.</li>
<li><a href="https://github.com/quarto-dev/quarto-cli/issues/9929">issue 9929</a> (I think this was because I was in the gh-pages branch when publishing and not the main branch)</li>
</ul>
<p>What my ultimate solution was:</p>
<p>For Python:</p>
<ul>
<li>The only env I could get things to recognize was a conda env in a default location for conda envs. Not sure why my other approaches didn’t work (my preference is to use an venv via <code>uv</code>), and there have been reticulate issues about using specific environments for years. But maybe it was due to other things (like the radian issue).
<ul>
<li>As an example, the quarto rendering would not use a virtual env in the project directory. It’s <a href="https://quarto.org/docs/projects/code-execution.html#freeze-virtual-environments">implied</a> that you can use venvs in the directory of the quarto doc (i.e.&nbsp;folder specific), but I had issues, and at a minimum you’d have to do another step or two to render specifically from that directory venv. It also still begs the question of why you can’t just name the env in the python execute argument of the doc to use whatever environment you need when rendering it in the first place.</li>
</ul></li>
<li>In <code>.Rprofile</code> (not <code>.Renviron</code>, not <code>_environment</code>) put <code>Sys.setenv(RETICULATE_PYTHON = '~/myenvlocation')</code> followed by <code>library(reticulate)</code>. The default VS Code venv was not ever used unless I did this. I would literally <code>source activate</code>, do a sanity check <code>which python</code>, and then it would render with a default system env. I’ll revisit this in case this was still mixed in with the Radian issue.</li>
<li>I feel like maybe relatively little is tested with VS Code/Python for website/blogs, and even less for mixing it with R. So be prepared for some work in that regard. My conclusion at this point is it’s just the same reticulate (not quarto specific) stuff that’s been ongoing for a long time.</li>
</ul>
<p>For R/General:</p>
<ul>
<li>Quarto does not adhere to the VS code project directory for posts by default, so directories are relative to the post file location, rather than the project. I eventually found there is an <code>execute_dir</code> option that can be set to <code>project</code>, but this doesn’t seem to work for yml in the file itself, which still need to refer to the file location for, e.g.&nbsp;the preview image or a bibliography. Also, Python code was relative to the project directory by default, so it was inconsistent with R until I set the <code>execute_dir</code> option.</li>
</ul>
<p>For publishing:</p>
<ul>
<li>A notable issue was the inability to use the top-level directory as the output_dir as I had before.
<ul>
<li>As a result, I had to change every post file from its previous name to ‘index.qmd’ within the date-named directory in order for previous links to work. I could add an <a href="https://quarto.org/docs/websites/website-navigation.html#redirects">alias</a> to every one of the files and let them redirect, but I prefer the cleaner address, and it’s easier to rename the files collectively than to add aliases to every post.</li>
</ul></li>
<li>I had to discover that you can’t be in the gh-pages branch. It’s mentioned in the doc, but not stressed or highlighted at all.</li>
</ul>
<p>Once I was able to get quarto to render the pages in the first place, it published pretty easily via <code>quarto publish gh-pages</code>. I very rarely can still can get a 404 or something else, but that has thus far has been remedied by just re-publishing.</p>
<p>Honestly they could use more documentation as to exactly what the workflow is for a website blog with actual (python) code, and a useful demo website demonstrating it for GH pages. That sounds specific, but I would imagine not uncommon for python (and a notable amount of R) users. A reproducible example that demonstrates most of the salient features would be nice (jjallaire.github.io is not enough). Thankfully a lot of my distill and previous book setup carried over, and at least part of my issues were probably due to unreasonable expectations.</p>
<p><strong>Setup Summarized</strong></p>
<p>(If you never had a website before, you can ignore this and just follow the Quarto docs)</p>
<ul>
<li>Realize that you’ll have to probably come across a diverse smattering of Quarto documentation over time to know how much and what you’ll likely need to tweak to get things to work. Just reading the website-specific docs will not be enough, and general issues with projects, computations, documents will all potentially affect your website.</li>
<li>I started with a separate repo to ensure that things were working as I expected, even with my old posts within. I assumed I could essentially copy these to my actual website repo, but there was still a lot to do and I ultimately had to rerender everything. I’d suggest that if you do this, maybe only include an old post or two.</li>
<li>Set your execute (and output_dir) if desired to whatever you had or now want.
<ul>
<li>If you link to other files in subdirectories, you likely need to change the link format. For example, I previously linked to <code>../folder/x.html</code> to link to <code>m-clark.github.io/folder/x.html</code>, but I had to change these to <code>/folder/x.html</code>.</li>
</ul></li>
<li>If you use Radian for your R console in VS Code, you’ll need to install in your chosen environment and point your workspace rterminal option to use that env for your terminal. You have to do this anyway, which is a real annoyance for using Radian in general.</li>
<li>Create a project specific python environment.
<ul>
<li>You may have to use conda to get reticulate stuff to work smoothly, but I’m not entirely certain of this. You may not need to do this if you don’t plan on mixing R and Python in the same doc.</li>
<li>If you do explicitly use reticulate, I suggest setting the python environment in your <code>.Rprofile</code> file.</li>
</ul></li>
</ul>
<p>So, after setup, it seems the workflow is something like this if you have a blog and use VS Code, python and R:</p>
<ul>
<li>Make change on main</li>
<li>Push to main</li>
<li>Publish</li>
<li>Cross fingers, I still have had a bit of quirkiness from time to time, but usually just publishing/re-rendering again works things out.</li>
</ul>


</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section></div> ]]></description>
  <category>miscellaneous</category>
  <guid>https://m-clark.github.io/posts/2025-01-01-news/</guid>
  <pubDate>Wed, 01 Jan 2025 05:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/mc_logo.png" medium="image" type="image/png" height="43" width="144"/>
</item>
<item>
  <title>Long time no see…</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2024-05-20/</link>
  <description><![CDATA[ 





<section id="book-in-progess" class="level2">
<h2 class="anchored" data-anchor-id="book-in-progess">Book in progess</h2>
<p>TLDR: <a href="https://m-clark.github.io/book-of-models">https://m-clark.github.io/book-of-models</a></p>
<p>Been a long time since I posted. Part of this was due to the fact that I had almost completely transferred my site to quarto, but then never got around to finishing it. That will happen eventually, and I will hopefully start posting again at that point.</p>
<p>But the real news is that I am working on a new book. It is a book on exploring models in data science, currently titled <em>Models Demystified</em>. In it, Seth Berry and I attempt to cover a wide range of models, from the simple to the complex, in a way that is accessible to those who are not experts in statistics or machine learning, or might be coming from one area and would like the basics in the other. It covers quite a bit of ground, but tries to stick to the core what’s necessary to get started doing <em>good enough</em> modeling. We’re excited about it, and hope to have it out by the end of the year on CRC press in print, but you can <a href="https://m-clark.github.io/book-of-models">check it out now while it’s in progress</a>. Hope you enjoy it!</p>


</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2024,
  author = {Clark, Michael},
  title = {Long Time No See...},
  date = {2024-05-20},
  url = {https://m-clark.github.io/posts/2024-05-20/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2024" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2024. <span>“Long Time No See...”</span> May 20. <a href="https://m-clark.github.io/posts/2024-05-20/">https://m-clark.github.io/posts/2024-05-20/</a>.
</div></div></section></div> ]]></description>
  <category>miscellaneous</category>
  <guid>https://m-clark.github.io/posts/2024-05-20/</guid>
  <pubDate>Mon, 20 May 2024 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/book_gp.svg" medium="image" type="image/svg+xml"/>
</item>
<item>
  <title>Stuff Going On</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2023-03-misc/</link>
  <description><![CDATA[ 





<p>It’s been a bit so thought I’d force myself to post a couple things I’ve played around with, or that aren’t ready yet for a full post, or won’t be one.</p>
<section id="football-players-still-dont-know-penalty-kick-basics" class="level2">
<h2 class="anchored" data-anchor-id="football-players-still-dont-know-penalty-kick-basics">Football players still don’t know penalty kick basics</h2>
<p>Did a quick and dirty Bayesian analysis to get posterior probabilities for location, controlling for various factors. As a side note, I won the office world cup challenge with a fancy model of which I will never reveal the details, but may or may not have included lots of guessing and luck.</p>
<p><img src="https://m-clark.github.io/img/world_cup_penalty_bayes.jpg" class="img-fluid"></p>
</section>
<section id="tabular-data-post" class="level2">
<h2 class="anchored" data-anchor-id="tabular-data-post">Tabular data post</h2>
<p>I finally did my first post at the <a href="https://www.strong.io/blog/">Strong blog</a>! It’s a <a href="https://www.strong.io/blog/deep-learning-for-tabular-data-an-overview">high-level overview of tabular data and deep learning</a> that summarizes some of my previous posts <a href="https://m-clark.github.io/posts/2022-04-01-more-dl-for-tabular/">here</a> and <a href="https://m-clark.github.io/posts/2021-07-15-dl-for-tabular/">here</a>.</p>
</section>
<section id="class-imbalance" class="level2">
<h2 class="anchored" data-anchor-id="class-imbalance">Class Imbalance</h2>
<p>For my next post at the Strong blog, Elizabeth Monroe and I are working on a similarly high-level overview of issues with class imbalance we’ve been coming across. I will probably provide even more details and simulation results in a post on this site eventually, but here is a preview plot showing (mis)calibration plots at varying degrees of imbalance and different sample sizes.</p>
<p><img src="https://m-clark.github.io/img/calibration_plot_default_avg.png" class="img-fluid"></p>
</section>
<section id="two-years-at-strong" class="level2">
<h2 class="anchored" data-anchor-id="two-years-at-strong">Two years at Strong</h2>
<p>Hard to believe for me anyway, but I’ve been out of academia for two years now, after previously spending my professional lifetime there. Aside from some of the obvious differences, one of the more satisfying changes for me has been that the skills I’ve acquired are utilized on a daily basis, and something I need to continuously develop for the job. At Strong our clients want good results in a timely fashion, and though the results might be notably complex, they still need to be sufficiently interpretable as well as reproducible/production-ready. I also have come across more desire for causal explanations from clients, which might be surprising to what is typically assumed for academia vs.&nbsp;industry. Clients obviously require buy-in for what we do, but they ultimately defer to us for the expertise we provide.</p>
<p><a href="https://www.strong.io/">Strong Analytics</a> was a great move for me, because they clearly value the strong academic background of its employees, but are practically minded, and focus on skills that allow one to be nimble enough to get the clients what they need. Just like I was in academia, I am surrounded by a diverse group of smart folks I respect a lot, and am happy to solve some tough problems with. I feel I’ve learned how to get things done in a more efficient manner, and do a better job of explaining what I’ve done to wider audience.</p>
<p>Among some things I miss with academia, one was working with faculty and grad students who were just starting with an idea, and continuing a relationship with them until ultimately getting to publication or a successful dissertation defense after a very long journey. Another was giving workshops regularly where you could help people with their initial baby steps into the large world of data science. In general, it was easy to feel personally invested in the individuals you were working with, and their successes felt like your own.</p>
<p>However, in academia it was often a struggle to get buy-in for more complicated methods or new techniques, because the stakes were typically lower and people knew the minimum required to get them published, defended or whatever, and mostly just wanted help getting to that point. There’s nothing wrong with that necessarily, that’s just the practical reality, and a reflection of what’s valued in academia. Despite that, I can say I definitely had some good partnerships with people involved in challenging research that was very rewarding, and those projects made it generally very satisfying to work in academia.</p>
<p>Ultimately though, I’m happy to have made the jump. It’s a bit weird to me how much drama there is on this topic on twitter and elsewhere. It’s really not that big of a deal which route you go, and in the grand scheme of things, almost no one will care if you work in academia or industry but you. There are pros and cons to both, and people should just pick what will make them happier.</p>
</section>
<section id="coming-up" class="level2">
<h2 class="anchored" data-anchor-id="coming-up">Coming up</h2>
<p>Whenever I can get around to it, I’ll try and post on those class imbalance simulations mentioned above, conformal prediction, and some other fun stuff. Stay tuned!</p>


</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2023,
  author = {Clark, Michael},
  title = {Stuff {Going} {On}},
  date = {2023-03-10},
  url = {https://m-clark.github.io/posts/2023-03-misc/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2023" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2023. <span>“Stuff Going On.”</span> March 10. <a href="https://m-clark.github.io/posts/2023-03-misc/">https://m-clark.github.io/posts/2023-03-misc/</a>.
</div></div></section></div> ]]></description>
  <category>miscellaneous</category>
  <guid>https://m-clark.github.io/posts/2023-03-misc/</guid>
  <pubDate>Fri, 10 Mar 2023 05:00:00 GMT</pubDate>
</item>
<item>
  <title>Deep Linear Models</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2022-09-deep-linear-models/</link>
  <description><![CDATA[ 





<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<blockquote class="blockquote">
<p>NB: This post was revisited when updating the website early 2025, and some changes were required. Attempts to keep things consistent were made, but if you feel you’ve found an issue, please post it at <a href="http://github.com/m-clark/m-clark.github.io/issues">GitHub</a>.</p>
</blockquote>
<p>This post gives a by-hand example of a linear model using <span class="pack">pytorch</span>. A good question to ask right off the bat would be- why would anyone do this? We use deep learning typically because linear regression isn’t up to the task! Well, for one thing, it serves as a stepping stone for those who know basic statistical methodology like linear regression, but want to get into deep learning in a conceptual manner. Another is to just see some <span class="pack">pytorch</span> basics in a simple setting. And one last reason is that maybe you want to incorporate a more standard statistical modeling approach into some other deep learning endeavor. Everyone can join the party!</p>
<p>For this demo we’ll use <a href="https://www.kaggle.com/code/jhoward/linear-model-and-neural-net-from-scratch">an example by <span class="pack">fastai</span></a>, which is a great resource for <a href="https://course.fast.ai/">getting started with deep learning</a>. While their example serves as a basis, I will generalize the functionality so that you can play around with the settings and try other data examples<sup>1</sup>. In addition, this post will assume you know things like why you would dummy code features and linear regression basics, and will use some other naming conventions<sup>2</sup>.</p>
</section>
<section id="getting-started" class="level2">
<h2 class="anchored" data-anchor-id="getting-started">Getting Started</h2>
<p>Let’s get the primary packages loaded first.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb1-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> lightgbm <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> lgb</span>
<span id="cb1-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> torch</span></code></pre></div></div>
</div>
<p>Next, we’ll use the well-known <a href="https://www.kaggle.com/code/jhoward/linear-model-and-neural-net-from-scratch/data">titanic dataset</a>, and to start things off, we’ll need to get a sense of what we’re dealing with. The basic idea is that we’d like to predict survival based on key features like sex, age, ticket class and more.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># non-kaggle-requiring url here: https://raw.githubusercontent.com/m-clark/m-clark.github.io/master/data/dl-linear-regression/titanic/train.csv</span></span>
<span id="cb2-2">df_titanic_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'data/dl-linear-regression/titanic/train.csv'</span>)</span>
<span id="cb2-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># df_titanic_train</span></span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">df_titanic_train.describe()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>       PassengerId    Survived      Pclass  ...       SibSp       Parch        Fare
count   891.000000  891.000000  891.000000  ...  891.000000  891.000000  891.000000
mean    446.000000    0.383838    2.308642  ...    0.523008    0.381594   32.204208
std     257.353842    0.486592    0.836071  ...    1.102743    0.806057   49.693429
min       1.000000    0.000000    1.000000  ...    0.000000    0.000000    0.000000
25%     223.500000    0.000000    2.000000  ...    0.000000    0.000000    7.910400
50%     446.000000    0.000000    3.000000  ...    0.000000    0.000000   14.454200
75%     668.500000    1.000000    3.000000  ...    1.000000    0.000000   31.000000
max     891.000000    1.000000    3.000000  ...    8.000000    6.000000  512.329200

[8 rows x 7 columns]</code></pre>
</div>
</div>
</section>
<section id="initial-data-processing" class="level2">
<h2 class="anchored" data-anchor-id="initial-data-processing">Initial Data Processing</h2>
<p>The data is not ready for modeling as is, so we’ll do some additional processing to get it ready. We’ll check out the missing values and replace them with modes<sup>3</sup>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">df_titanic_train.isna().<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1">modes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_titanic_train.mode().iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb7-2"></span>
<span id="cb7-3">df_titanic_train.fillna(modes, inplace <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb7-4"></span>
<span id="cb7-5">df_titanic_train.describe(include <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (np.number))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>       PassengerId    Survived      Pclass  ...       SibSp       Parch        Fare
count   891.000000  891.000000  891.000000  ...  891.000000  891.000000  891.000000
mean    446.000000    0.383838    2.308642  ...    0.523008    0.381594   32.204208
std     257.353842    0.486592    0.836071  ...    1.102743    0.806057   49.693429
min       1.000000    0.000000    1.000000  ...    0.000000    0.000000    0.000000
25%     223.500000    0.000000    2.000000  ...    0.000000    0.000000    7.910400
50%     446.000000    0.000000    3.000000  ...    0.000000    0.000000   14.454200
75%     668.500000    1.000000    3.000000  ...    1.000000    0.000000   31.000000
max     891.000000    1.000000    3.000000  ...    8.000000    6.000000  512.329200

[8 rows x 7 columns]</code></pre>
</div>
</div>
<p>With features, sometimes it is worthwhile to log transform data for potentially more efficient optimization search. Since we have zeros, we add 1 before taking the log.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1">df_titanic_train[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Fare'</span>].hist()</span></code></pre></div></div>
</div>
<p><img src="https://m-clark.github.io/img/dl-linreg/fare-hist.png" class="img-fluid" style="width:50.0%"></p>
<p>Now the transformed data looks a little more manageable. More to the point, we won’t potentially have huge coefficients relative to other covariates because of the range of the data.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">df_titanic_train[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LogFare'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.log1p(df_titanic_train[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Fare'</span>])</span>
<span id="cb10-2"></span>
<span id="cb10-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># df_titanic_train['LogFare'].hist()</span></span></code></pre></div></div>
</div>
<p><img src="https://m-clark.github.io/img/dl-linreg/fare-hist-log.png" class="img-fluid" style="width:50.0%"></p>
<p>The <code>Pclass</code> (passenger class) feature is actually categorical.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1">pclasses <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(df_titanic_train.Pclass.unique())</span>
<span id="cb11-2">pclasses</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[np.int64(1), np.int64(2), np.int64(3)]</code></pre>
</div>
</div>
<p>Here are the other categorical features.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1">df_titanic_train.describe(include <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">object</span>])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>                           Name   Sex  Ticket    Cabin Embarked
count                       891   891     891      891      891
unique                      891     2     681      147        3
top     Braund, Mr. Owen Harris  male  347082  B96 B98        S
freq                          1   577       7      691      646</code></pre>
</div>
</div>
<p>In order to use categorical variables, they need to be changed to numbers<sup>4</sup>, so we dummy code them here. There are other coding schemes, and for most deep learning approaches people will often use <em>embeddings</em><sup>5</sup>, particularly for things that have lots of unique categories.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1">df_titanic_train <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.get_dummies(df_titanic_train, columns <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sex"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Pclass"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Embarked"</span>])</span></code></pre></div></div>
</div>
<p>Let’s take a look at our data now.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">df_titanic_train.columns</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Index(['PassengerId', 'Survived', 'Name', 'Age', 'SibSp', 'Parch', 'Ticket',
       'Fare', 'Cabin', 'LogFare', 'Sex_female', 'Sex_male', 'Pclass_1',
       'Pclass_2', 'Pclass_3', 'Embarked_C', 'Embarked_Q', 'Embarked_S'],
      dtype='object')</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1">df_titanic_train.head()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>   PassengerId  Survived  ... Embarked_Q  Embarked_S
0            1         0  ...      False        True
1            2         1  ...      False       False
2            3         1  ...      False        True
3            4         1  ...      False        True
4            5         0  ...      False        True

[5 rows x 18 columns]</code></pre>
</div>
</div>
</section>
<section id="getting-started-with-pytorch" class="level2">
<h2 class="anchored" data-anchor-id="getting-started-with-pytorch">Getting Started with pytorch</h2>
<section id="setup" class="level3">
<h3 class="anchored" data-anchor-id="setup">Setup</h3>
<p>Now we are ready to prep things for specific use with <span class="pack">pytorch</span>. I will not use the same terminology as in Jeremy’s original post, so for us, <code>target</code> = ‘dependent variable’ and <code>X</code> is our feature matrix<sup>6</sup>. Both of these will be <span class="pack">pytorch</span> <em>tensors</em>, which for our purposes is just another word for an array of arbitrary size.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> torch <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> tensor</span>
<span id="cb20-2">device <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.device(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cpu'</span>)</span>
<span id="cb20-3">target <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tensor(df_titanic_train.Survived)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1">dummies <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Sex_male'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Sex_female'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Pclass_1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Pclass_2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Pclass_3'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Embarked_C'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Embarked_Q'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Embarked_S'</span>]</span>
<span id="cb21-2">all_features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Age'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SibSp'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Parch'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'LogFare'</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> dummies </span>
<span id="cb21-3"></span>
<span id="cb21-4">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df_titanic_train[all_features].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">apply</span>(pd.to_numeric).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb21-5">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> tensor(X.values, dtype <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>)</span>
<span id="cb21-6"></span>
<span id="cb21-7">X.shape</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>torch.Size([891, 12])</code></pre>
</div>
</div>
</section>
</section>
<section id="setting-up-a-linear-model" class="level2">
<h2 class="anchored" data-anchor-id="setting-up-a-linear-model">Setting up a linear model</h2>
<p>We have our feature matrix and target variable prepped. The next step is to map the features to the target by means of predicted values. In linear regression, we typically call the weights that produce the predictions <em>coefficients</em>, but in standard deep/machine learning terminology, they are usually called <em>weights</em>, or more generally, <em>parameters</em>. Here, we generate some random values between -.5 and .5 to get started<sup>7</sup>:.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1">torch.manual_seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">442</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>&lt;torch._C.Generator object at 0x162e724b0&gt;</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb25" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb25-1">n_coeff <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb25-2">coeffs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.rand(n_coeff) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># default would produce values from 0 to 1</span></span>
<span id="cb25-3">coeffs</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>tensor([-0.4629,  0.1386,  0.2409, -0.2262, -0.2632, -0.3147,  0.4876,  0.3136,
         0.2799, -0.4392,  0.2103,  0.3625])</code></pre>
</div>
</div>
<p>The original post did a form of min-max scaling to the features, basically putting everything on a potentially [0, 1] scale. Here we’ll use standardization as an alternative, giving each feature a mean of zero and standard deviation of 1.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb27-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># vals,indices = X.max(dim=0)</span></span>
<span id="cb27-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># X = X / vals</span></span>
<span id="cb27-3">X_means <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.mean(dim <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, keepdim <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb27-4">X_sds   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X.std(dim <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb27-5"></span>
<span id="cb27-6">X_sc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> X_means) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> X_sds</span>
<span id="cb27-7"></span>
<span id="cb27-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># X_sc.mean(dim = 0)  # all means = 0 </span></span>
<span id="cb27-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># X_sc.std(dim = 0)   # all sd = 1</span></span></code></pre></div></div>
</div>
<p>As noted in the original post and worth iterating here for our statistical modeling crowd, we don’t estimate an intercept for this model and keep all the dummy coded features. The following takes our coefficients, multiplies them by their respective feature, and sums them.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb28" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb28-1">preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (X_sc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> coeffs).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(axis <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb28-2">preds[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>]</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>tensor([ 0.6000, -1.9341,  0.2080,  0.1723, -0.0032,  0.3088, -0.5066,  1.6219,
         0.6990, -1.2584])</code></pre>
</div>
</div>
<p>We can calculate our <em>loss</em>, the difference in our predictions versus the target values, in many ways. Here we get the mean squared error.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb30" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb30-1">loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.square(preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> target).mean()</span>
<span id="cb30-2">loss</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>tensor(1.3960)</code></pre>
</div>
</div>
<p>Now we’ll create functions that do the previous steps, and finally, give it a test run! In the original <span class="pack">fastai</span> formulation, they use mean absolute error for the loss, which actually is just the <code>L1loss</code> that is available in torch. For a change of pace, we’ll keep our mean squared error, which is sometimes called <em>L2</em> loss (this will create different results from the original notebook). I create the option within the function for you to do either. Also note that the functions we create here will take inputs generally, rather than being specific to the objects we create, so you can try this stuff out with other data.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb32" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb32-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> calc_preds(X, weights):</span>
<span id="cb32-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span>((X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> weights).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(axis <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb32-3"></span>
<span id="cb32-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> calc_loss(X, weights, target, which <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'l2'</span>):</span>
<span id="cb32-5">    preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> calc_preds(X, weights)</span>
<span id="cb32-6">    </span>
<span id="cb32-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># torch.abs(calc_preds(X, coeffs)-target).mean()  # original</span></span>
<span id="cb32-8"></span>
<span id="cb32-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> which <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'l2'</span>:</span>
<span id="cb32-10">      loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.nn.MSELoss()</span>
<span id="cb32-11">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>: </span>
<span id="cb32-12">      loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.nn.L1Loss()</span>
<span id="cb32-13">      </span>
<span id="cb32-14">    L <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> loss(preds, target.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>())</span>
<span id="cb32-15">      </span>
<span id="cb32-16">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span>(L)</span>
<span id="cb32-17"></span>
<span id="cb32-18">calc_loss(X_sc, coeffs, target), calc_loss(X_sc, coeffs, target, which <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'l1'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>(tensor(1.3960), tensor(0.8891))</code></pre>
</div>
</div>
<section id="doing-a-gradient-descent-step" class="level3">
<h3 class="anchored" data-anchor-id="doing-a-gradient-descent-step">Doing a Gradient Descent Step</h3>
<p>We can continue our journey onward to actually estimating the weights rather than specifying them directly, since we definitely don’t want to just keep guessing! This is an iterative process where we still start with an initial (random) guess, then, at each step, refine our guess in a way that lowers our loss. For neural networks we call these steps <em>epochs</em>, and getting our next guess requires calculating what’s called a <em>gradient</em>. Here are some resources for more detail:</p>
<ul>
<li><a href="https://www.kaggle.com/code/jhoward/how-does-a-neural-net-really-work">How Does a Neural Net Really Work?</a>: great intro by Jeremy Howard</li>
<li><a href="https://m-clark.github.io/models-by-example/stochastic-gradient-descent.html">Some by-hand code using gradient descent for linear regression, R</a>, <a href="https://m-clark.github.io/models-by-example/supplemental.html#python-sgd">Python</a>: By yours truly</li>
</ul>
<p>In any case, this is basic functionality within <span class="pack">pytorch</span>, and it will keep track of each step taken.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb34" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb34-1">coeffs.requires_grad_()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>tensor([-0.4629,  0.1386,  0.2409, -0.2262, -0.2632, -0.3147,  0.4876,  0.3136,
         0.2799, -0.4392,  0.2103,  0.3625], requires_grad=True)</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb36" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb36-1">loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> calc_loss(X_sc, coeffs, target)</span>
<span id="cb36-2">loss</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>tensor(1.3960, grad_fn=&lt;MseLossBackward0&gt;)</code></pre>
</div>
</div>
<p>We use <span class="func">backward</span> to calculate the gradients and inspect them.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb38" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb38-1">loss.backward()</span>
<span id="cb38-2"></span>
<span id="cb38-3">coeffs.grad</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>tensor([-0.9311,  0.6245,  0.4957, -0.7423,  0.6008, -0.6008, -0.9158,  0.0938,
         0.7127, -1.7183,  0.1715,  1.3974])</code></pre>
</div>
</div>
<p>Each time backward is called, the gradients are added to the previous values. We can see here that they’ve now doubled.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb40" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb40-1">loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> calc_loss(X_sc, coeffs, target)</span>
<span id="cb40-2"></span>
<span id="cb40-3">loss.backward()</span>
<span id="cb40-4"></span>
<span id="cb40-5">coeffs.grad</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>tensor([-1.8621,  1.2491,  0.9914, -1.4847,  1.2015, -1.2015, -1.8317,  0.1877,
         1.4254, -3.4366,  0.3431,  2.7947])</code></pre>
</div>
</div>
<p>What we want instead is to set them back to zero after they are used for our estimation step. The following does this.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb42" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb42-1">loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> calc_loss(X_sc, coeffs, target)</span>
<span id="cb42-2"></span>
<span id="cb42-3">loss.backward()</span>
<span id="cb42-4"></span>
<span id="cb42-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">with</span> torch.no_grad():</span>
<span id="cb42-6">    coeffs.sub_(coeffs.grad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)     <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># sub subtracts in place</span></span>
<span id="cb42-7">    coeffs.grad.zero_()                <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># zeros out in place</span></span>
<span id="cb42-8">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(calc_loss(X, coeffs, target))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>tensor([-0.1836, -0.0488,  0.0922, -0.0035, -0.4435, -0.1345,  0.7624,  0.2854,
         0.0661,  0.0763,  0.1588, -0.0567], requires_grad=True)
tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
tensor(37.9424)</code></pre>
</div>
</div>
</section>
<section id="training-the-linear-model" class="level3">
<h3 class="anchored" data-anchor-id="training-the-linear-model">Training the Linear Model</h3>
<p>We typically would split our data into training and test. We can do so here, or keep this data as training and import <code>test.csv</code> for the test set. The latter is actually used for the Kaggle submission, but that’s not a goal here. We’ll use <span class="pack">scikit-learn</span> for the splitting.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb44" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb44-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.model_selection <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> train_test_split</span>
<span id="cb44-2"></span>
<span id="cb44-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># test size .2 in keeping with fastai RandomSplitter default</span></span>
<span id="cb44-4">train_x, valid_x, train_y, valid_y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_test_split(</span>
<span id="cb44-5">  X_sc, </span>
<span id="cb44-6">  target.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>(), </span>
<span id="cb44-7">  test_size <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>, </span>
<span id="cb44-8">  random_state <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">808</span></span>
<span id="cb44-9">)</span>
<span id="cb44-10">  </span>
<span id="cb44-11"></span>
<span id="cb44-12"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(train_x), <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(valid_x) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># might be one off of the original notebook</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>(712, 179)</code></pre>
</div>
</div>
<p>As before, we’ll create functions to help automate our steps:</p>
<ul>
<li>one to initialize the weights</li>
<li>a function to update weights</li>
<li>one to do a full epoch (using weights to calculate loss, updating weights)</li>
<li>one to train the entire model (run multiple times/epochs)</li>
</ul>
<p>As mentioned, the approach here is to create functions that are general enough to take any X or target, so they look a little different from the original notebook. I also add in a verbosity option so you can see the loss at each <code>verbose</code> value epoch (e.g.&nbsp;<code>verbose = 10</code> means you’ll see the latest loss value every 10 epochs), so you can watch the iterations for as long as you like without it printing constantly (possibly not too big a deal depending on your IDE).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb46" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb46-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> init_weights(n_wts): </span>
<span id="cb46-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (torch.rand(n_wts) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>).requires_grad_()</span>
<span id="cb46-3"></span>
<span id="cb46-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> update_weights(weights, lr):</span>
<span id="cb46-5">    weights.sub_(weights.grad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> lr)</span>
<span id="cb46-6">    weights.grad.zero_()</span>
<span id="cb46-7"></span>
<span id="cb46-8"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> one_epoch(X, weights, target, lr, verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>):</span>
<span id="cb46-9">    loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> calc_loss(X, weights, target)</span>
<span id="cb46-10">    loss.backward()</span>
<span id="cb46-11">    </span>
<span id="cb46-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">with</span> torch.no_grad(): update_weights(weights, lr)</span>
<span id="cb46-13">    </span>
<span id="cb46-14">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb46-15">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb46-16">            <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>loss<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">: 3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>, end <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> '</span>)</span>
<span id="cb46-17"></span>
<span id="cb46-18"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> train_model(X, target, epochs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-3</span>, verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>):</span>
<span id="cb46-19">    torch.manual_seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">442</span>)</span>
<span id="cb46-20">    coeffs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> init_weights(X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb46-21">    </span>
<span id="cb46-22">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(epochs): </span>
<span id="cb46-23">        one_epoch(X, coeffs, target, lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lr, i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> i, verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> verbose)</span>
<span id="cb46-24">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> coeffs</span></code></pre></div></div>
</div>
<p>Try out the functions if you like (not shown).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb47" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb47-1">calc_loss(X_sc, init_weights(X_sc.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]), target).backward()</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb48" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb48-1">one_epoch(train_x, init_weights(train_x.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]), train_y, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">.01</span>)</span></code></pre></div></div>
</div>
<p>Now train the model for multiple epochs. The loss drops very quickly before becoming more steady.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb49" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb49-1">coeffs_est <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_model(train_x, train_y, epochs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">.2</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> 1.375618
  0.296216
  0.284019
  0.281221
  0.280271
  0.279923
  0.279794
  0.279746
  0.279728
  0.279721
 </code></pre>
</div>
</div>
<p>Let’s create a function to show our estimated parameters/weights/coefficients in a pretty fashion.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb51" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb51-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> show_coeffs(estimates): </span>
<span id="cb51-2">  coef_dict <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(all_features, estimates.requires_grad_(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>).numpy()))</span>
<span id="cb51-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> pd.DataFrame(coef_dict, index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'value'</span>]).T</span>
<span id="cb51-4"></span>
<span id="cb51-5">show_coeffs(coeffs_est)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>               value
Age        -0.090825
SibSp      -0.054449
Parch      -0.016111
LogFare     0.046320
Sex_male   -0.406538
Sex_female -0.171426
Pclass_1    0.408707
Pclass_2    0.335766
Pclass_3    0.329800
Embarked_C  0.057091
Embarked_Q  0.032813
Embarked_S  0.039464</code></pre>
</div>
</div>
</section>
<section id="measuring-accuracy" class="level3">
<h3 class="anchored" data-anchor-id="measuring-accuracy">Measuring Accuracy</h3>
<p>It’s one thing to get accuracy on the trained data, but a better estimate of model performance is to measure it on our test/validation data. The following function will convert our estimates to a binary value like our target, and compares them to the target. Depending on how you did your training setup, it might be pretty bad or at least better than guessing.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb53" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb53-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> acc(X, weights, target): </span>
<span id="cb53-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (target.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">bool</span>() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> (calc_preds(X, weights) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>().mean()</span>
<span id="cb53-3"></span>
<span id="cb53-4">acc(train_x, coeffs_est, train_y), acc(valid_x, coeffs_est, valid_y)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>(tensor(0.7051), tensor(0.6425))</code></pre>
</div>
</div>
</section>
<section id="using-sigmoid" class="level3">
<h3 class="anchored" data-anchor-id="using-sigmoid">Using sigmoid</h3>
<p>Nothing about the previous setup actually produces a result on the probability scale, so basing a cutoff of .5 is meaningless. you can inspect them and might see values are above 1 or below zero, which we generally don’t want<sup>8</sup>. However we do have a solution. The <em>sigmoid function</em><sup>9</sup> allows us to transform our predictions to values between 0 and 1, i.e.&nbsp;probabilities in this context, and in particular, the probability of survival. Then our <span class="func">acc</span> function will be more appropriate, where any probability &gt; .5 will be given a value of 1 (or <code>True</code> technically), while others will be 0/<code>False</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb55" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb55-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> calc_preds(X, weights):</span>
<span id="cb55-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> torch.sigmoid((X<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>weights).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(axis <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span></code></pre></div></div>
</div>
<p>We also will do more iterations, and fiddle with the learning rate (a.k.a. step size)</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb56" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb56-1">coeffs_est <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_model(</span>
<span id="cb56-2">  train_x,</span>
<span id="cb56-3">  train_y,</span>
<span id="cb56-4">  epochs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>,</span>
<span id="cb56-5">  lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb56-6">  verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb56-7">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> 0.314158
  0.154329
  0.154237
  0.154232
  0.154232
 </code></pre>
</div>
</div>
<p>Not too shabby!</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb58" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb58-1">acc(train_x, coeffs_est, train_y), acc(valid_x, coeffs_est, valid_y)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>(tensor(0.7823), tensor(0.7989))</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb60" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb60-1">show_coeffs(coeffs_est)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>               value
Age        -0.516476
SibSp      -0.423656
Parch      -0.179623
LogFare     0.396468
Sex_male   -0.927410
Sex_female  0.349448
Pclass_1    0.713895
Pclass_2    0.320935
Pclass_3    0.078919
Embarked_C  0.107378
Embarked_Q  0.082943
Embarked_S -0.036137</code></pre>
</div>
</div>
<p>In implementing the sigmoid, let’s go ahead and optimize how we calculate the predictions using a matrix shorthand for getting the predictions (which is also much more efficient/faster)<sup>10</sup>. To do this, the coefficients will need to be a column vector, so we change our <span class="func">init_coeffs</span> function slightly<sup>11</sup>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb62" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb62-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> calc_preds(X, weights): </span>
<span id="cb62-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> torch.sigmoid(X<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span>weights)</span>
<span id="cb62-3"></span>
<span id="cb62-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> init_coeffs(n_wts): </span>
<span id="cb62-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (torch.rand(n_wts, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>).requires_grad_()</span></code></pre></div></div>
</div>
<p>Now our functions are more like the mathematical notation we’d usually see for linear regression.</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%7By%7D%20=%20X%5Cbeta"></p>
</section>
<section id="compare-to-linearlogistic-regression" class="level3">
<h3 class="anchored" data-anchor-id="compare-to-linearlogistic-regression">Compare to Linear/Logistic Regression</h3>
<p>Before getting too excited, let’s compare our results to basic linear and logistic regression. The linear regression is more like our model before using the sigmoid transformation, while the logistic is more like when we used it. Depending on your settings, the logistic regression is probably doing better at this point.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb63" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb63-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> linear_model</span>
<span id="cb63-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.metrics <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> accuracy_score</span>
<span id="cb63-3"></span>
<span id="cb63-4"></span>
<span id="cb63-5">reg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> linear_model.LinearRegression()</span>
<span id="cb63-6">reg.fit(train_x, train_y)</span></code></pre></div></div>
<div class="cell-output-display">
<style>#sk-container-id-1 {
  /* Definition of color scheme common for light and dark mode */
  --sklearn-color-text: #000;
  --sklearn-color-text-muted: #666;
  --sklearn-color-line: gray;
  /* Definition of color scheme for unfitted estimators */
  --sklearn-color-unfitted-level-0: #fff5e6;
  --sklearn-color-unfitted-level-1: #f6e4d2;
  --sklearn-color-unfitted-level-2: #ffe0b3;
  --sklearn-color-unfitted-level-3: chocolate;
  /* Definition of color scheme for fitted estimators */
  --sklearn-color-fitted-level-0: #f0f8ff;
  --sklearn-color-fitted-level-1: #d4ebff;
  --sklearn-color-fitted-level-2: #b3dbfd;
  --sklearn-color-fitted-level-3: cornflowerblue;

  /* Specific color for light theme */
  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));
  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));
  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));
  --sklearn-color-icon: #696969;

  @media (prefers-color-scheme: dark) {
    /* Redefinition of color scheme for dark theme */
    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));
    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));
    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));
    --sklearn-color-icon: #878787;
  }
}

#sk-container-id-1 {
  color: var(--sklearn-color-text);
}

#sk-container-id-1 pre {
  padding: 0;
}

#sk-container-id-1 input.sk-hidden--visually {
  border: 0;
  clip: rect(1px 1px 1px 1px);
  clip: rect(1px, 1px, 1px, 1px);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
}

#sk-container-id-1 div.sk-dashed-wrapped {
  border: 1px dashed var(--sklearn-color-line);
  margin: 0 0.4em 0.5em 0.4em;
  box-sizing: border-box;
  padding-bottom: 0.4em;
  background-color: var(--sklearn-color-background);
}

#sk-container-id-1 div.sk-container {
  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`
     but bootstrap.min.css set `[hidden] { display: none !important; }`
     so we also need the `!important` here to be able to override the
     default hidden behavior on the sphinx rendered scikit-learn.org.
     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */
  display: inline-block !important;
  position: relative;
}

#sk-container-id-1 div.sk-text-repr-fallback {
  display: none;
}

div.sk-parallel-item,
div.sk-serial,
div.sk-item {
  /* draw centered vertical line to link estimators */
  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));
  background-size: 2px 100%;
  background-repeat: no-repeat;
  background-position: center center;
}

/* Parallel-specific style estimator block */

#sk-container-id-1 div.sk-parallel-item::after {
  content: "";
  width: 100%;
  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);
  flex-grow: 1;
}

#sk-container-id-1 div.sk-parallel {
  display: flex;
  align-items: stretch;
  justify-content: center;
  background-color: var(--sklearn-color-background);
  position: relative;
}

#sk-container-id-1 div.sk-parallel-item {
  display: flex;
  flex-direction: column;
}

#sk-container-id-1 div.sk-parallel-item:first-child::after {
  align-self: flex-end;
  width: 50%;
}

#sk-container-id-1 div.sk-parallel-item:last-child::after {
  align-self: flex-start;
  width: 50%;
}

#sk-container-id-1 div.sk-parallel-item:only-child::after {
  width: 0;
}

/* Serial-specific style estimator block */

#sk-container-id-1 div.sk-serial {
  display: flex;
  flex-direction: column;
  align-items: center;
  background-color: var(--sklearn-color-background);
  padding-right: 1em;
  padding-left: 1em;
}


/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is
clickable and can be expanded/collapsed.
- Pipeline and ColumnTransformer use this feature and define the default style
- Estimators will overwrite some part of the style using the `sk-estimator` class
*/

/* Pipeline and ColumnTransformer style (default) */

#sk-container-id-1 div.sk-toggleable {
  /* Default theme specific background. It is overwritten whether we have a
  specific estimator or a Pipeline/ColumnTransformer */
  background-color: var(--sklearn-color-background);
}

/* Toggleable label */
#sk-container-id-1 label.sk-toggleable__label {
  cursor: pointer;
  display: flex;
  width: 100%;
  margin-bottom: 0;
  padding: 0.5em;
  box-sizing: border-box;
  text-align: center;
  align-items: start;
  justify-content: space-between;
  gap: 0.5em;
}

#sk-container-id-1 label.sk-toggleable__label .caption {
  font-size: 0.6rem;
  font-weight: lighter;
  color: var(--sklearn-color-text-muted);
}

#sk-container-id-1 label.sk-toggleable__label-arrow:before {
  /* Arrow on the left of the label */
  content: "▸";
  float: left;
  margin-right: 0.25em;
  color: var(--sklearn-color-icon);
}

#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {
  color: var(--sklearn-color-text);
}

/* Toggleable content - dropdown */

#sk-container-id-1 div.sk-toggleable__content {
  max-height: 0;
  max-width: 0;
  overflow: hidden;
  text-align: left;
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-0);
}

#sk-container-id-1 div.sk-toggleable__content.fitted {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-0);
}

#sk-container-id-1 div.sk-toggleable__content pre {
  margin: 0.2em;
  border-radius: 0.25em;
  color: var(--sklearn-color-text);
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-0);
}

#sk-container-id-1 div.sk-toggleable__content.fitted pre {
  /* unfitted */
  background-color: var(--sklearn-color-fitted-level-0);
}

#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {
  /* Expand drop-down */
  max-height: 200px;
  max-width: 100%;
  overflow: auto;
}

#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {
  content: "▾";
}

/* Pipeline/ColumnTransformer-specific style */

#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {
  color: var(--sklearn-color-text);
  background-color: var(--sklearn-color-unfitted-level-2);
}

#sk-container-id-1 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {
  background-color: var(--sklearn-color-fitted-level-2);
}

/* Estimator-specific style */

/* Colorize estimator box */
#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-2);
}

#sk-container-id-1 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-2);
}

#sk-container-id-1 div.sk-label label.sk-toggleable__label,
#sk-container-id-1 div.sk-label label {
  /* The background is the default theme color */
  color: var(--sklearn-color-text-on-default-background);
}

/* On hover, darken the color of the background */
#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {
  color: var(--sklearn-color-text);
  background-color: var(--sklearn-color-unfitted-level-2);
}

/* Label box, darken color on hover, fitted */
#sk-container-id-1 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {
  color: var(--sklearn-color-text);
  background-color: var(--sklearn-color-fitted-level-2);
}

/* Estimator label */

#sk-container-id-1 div.sk-label label {
  font-family: monospace;
  font-weight: bold;
  display: inline-block;
  line-height: 1.2em;
}

#sk-container-id-1 div.sk-label-container {
  text-align: center;
}

/* Estimator-specific */
#sk-container-id-1 div.sk-estimator {
  font-family: monospace;
  border: 1px dotted var(--sklearn-color-border-box);
  border-radius: 0.25em;
  box-sizing: border-box;
  margin-bottom: 0.5em;
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-0);
}

#sk-container-id-1 div.sk-estimator.fitted {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-0);
}

/* on hover */
#sk-container-id-1 div.sk-estimator:hover {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-2);
}

#sk-container-id-1 div.sk-estimator.fitted:hover {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-2);
}

/* Specification for estimator info (e.g. "i" and "?") */

/* Common style for "i" and "?" */

.sk-estimator-doc-link,
a:link.sk-estimator-doc-link,
a:visited.sk-estimator-doc-link {
  float: right;
  font-size: smaller;
  line-height: 1em;
  font-family: monospace;
  background-color: var(--sklearn-color-background);
  border-radius: 1em;
  height: 1em;
  width: 1em;
  text-decoration: none !important;
  margin-left: 0.5em;
  text-align: center;
  /* unfitted */
  border: var(--sklearn-color-unfitted-level-1) 1pt solid;
  color: var(--sklearn-color-unfitted-level-1);
}

.sk-estimator-doc-link.fitted,
a:link.sk-estimator-doc-link.fitted,
a:visited.sk-estimator-doc-link.fitted {
  /* fitted */
  border: var(--sklearn-color-fitted-level-1) 1pt solid;
  color: var(--sklearn-color-fitted-level-1);
}

/* On hover */
div.sk-estimator:hover .sk-estimator-doc-link:hover,
.sk-estimator-doc-link:hover,
div.sk-label-container:hover .sk-estimator-doc-link:hover,
.sk-estimator-doc-link:hover {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-3);
  color: var(--sklearn-color-background);
  text-decoration: none;
}

div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,
.sk-estimator-doc-link.fitted:hover,
div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,
.sk-estimator-doc-link.fitted:hover {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-3);
  color: var(--sklearn-color-background);
  text-decoration: none;
}

/* Span, style for the box shown on hovering the info icon */
.sk-estimator-doc-link span {
  display: none;
  z-index: 9999;
  position: relative;
  font-weight: normal;
  right: .2ex;
  padding: .5ex;
  margin: .5ex;
  width: min-content;
  min-width: 20ex;
  max-width: 50ex;
  color: var(--sklearn-color-text);
  box-shadow: 2pt 2pt 4pt #999;
  /* unfitted */
  background: var(--sklearn-color-unfitted-level-0);
  border: .5pt solid var(--sklearn-color-unfitted-level-3);
}

.sk-estimator-doc-link.fitted span {
  /* fitted */
  background: var(--sklearn-color-fitted-level-0);
  border: var(--sklearn-color-fitted-level-3);
}

.sk-estimator-doc-link:hover span {
  display: block;
}

/* "?"-specific style due to the `<a>` HTML tag */

#sk-container-id-1 a.estimator_doc_link {
  float: right;
  font-size: 1rem;
  line-height: 1em;
  font-family: monospace;
  background-color: var(--sklearn-color-background);
  border-radius: 1rem;
  height: 1rem;
  width: 1rem;
  text-decoration: none;
  /* unfitted */
  color: var(--sklearn-color-unfitted-level-1);
  border: var(--sklearn-color-unfitted-level-1) 1pt solid;
}

#sk-container-id-1 a.estimator_doc_link.fitted {
  /* fitted */
  border: var(--sklearn-color-fitted-level-1) 1pt solid;
  color: var(--sklearn-color-fitted-level-1);
}

/* On hover */
#sk-container-id-1 a.estimator_doc_link:hover {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-3);
  color: var(--sklearn-color-background);
  text-decoration: none;
}

#sk-container-id-1 a.estimator_doc_link.fitted:hover {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-3);
}
</style><div id="sk-container-id-1" class="sk-top-container"><div class="sk-text-repr-fallback"><pre>LinearRegression()</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br>On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class="sk-container" hidden=""><div class="sk-item"><div class="sk-estimator fitted sk-toggleable"><input class="sk-toggleable__control sk-hidden--visually" id="sk-estimator-id-1" type="checkbox" checked=""><label for="sk-estimator-id-1" class="sk-toggleable__label fitted sk-toggleable__label-arrow"><div><div>LinearRegression</div></div><div><a class="sk-estimator-doc-link fitted" rel="noreferrer" target="_blank" href="https://scikit-learn.org/1.6/modules/generated/sklearn.linear_model.LinearRegression.html">?<span>Documentation for LinearRegression</span></a><span class="sk-estimator-doc-link fitted">i<span>Fitted</span></span></div></label><div class="sk-toggleable__content fitted"><pre>LinearRegression()</pre></div> </div></div></div></div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb64" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb64-1">acc(valid_x, coeffs_est, valid_y), acc(valid_x, reg.coef_.T, valid_y)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>(tensor(0.7989), tensor(0.7821))</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb66" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb66-1">reg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> linear_model.LogisticRegression()</span>
<span id="cb66-2">reg.fit(train_x, train_y)</span></code></pre></div></div>
<div class="cell-output-display">
<style>#sk-container-id-2 {
  /* Definition of color scheme common for light and dark mode */
  --sklearn-color-text: #000;
  --sklearn-color-text-muted: #666;
  --sklearn-color-line: gray;
  /* Definition of color scheme for unfitted estimators */
  --sklearn-color-unfitted-level-0: #fff5e6;
  --sklearn-color-unfitted-level-1: #f6e4d2;
  --sklearn-color-unfitted-level-2: #ffe0b3;
  --sklearn-color-unfitted-level-3: chocolate;
  /* Definition of color scheme for fitted estimators */
  --sklearn-color-fitted-level-0: #f0f8ff;
  --sklearn-color-fitted-level-1: #d4ebff;
  --sklearn-color-fitted-level-2: #b3dbfd;
  --sklearn-color-fitted-level-3: cornflowerblue;

  /* Specific color for light theme */
  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));
  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));
  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));
  --sklearn-color-icon: #696969;

  @media (prefers-color-scheme: dark) {
    /* Redefinition of color scheme for dark theme */
    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));
    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));
    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));
    --sklearn-color-icon: #878787;
  }
}

#sk-container-id-2 {
  color: var(--sklearn-color-text);
}

#sk-container-id-2 pre {
  padding: 0;
}

#sk-container-id-2 input.sk-hidden--visually {
  border: 0;
  clip: rect(1px 1px 1px 1px);
  clip: rect(1px, 1px, 1px, 1px);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
}

#sk-container-id-2 div.sk-dashed-wrapped {
  border: 1px dashed var(--sklearn-color-line);
  margin: 0 0.4em 0.5em 0.4em;
  box-sizing: border-box;
  padding-bottom: 0.4em;
  background-color: var(--sklearn-color-background);
}

#sk-container-id-2 div.sk-container {
  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`
     but bootstrap.min.css set `[hidden] { display: none !important; }`
     so we also need the `!important` here to be able to override the
     default hidden behavior on the sphinx rendered scikit-learn.org.
     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */
  display: inline-block !important;
  position: relative;
}

#sk-container-id-2 div.sk-text-repr-fallback {
  display: none;
}

div.sk-parallel-item,
div.sk-serial,
div.sk-item {
  /* draw centered vertical line to link estimators */
  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));
  background-size: 2px 100%;
  background-repeat: no-repeat;
  background-position: center center;
}

/* Parallel-specific style estimator block */

#sk-container-id-2 div.sk-parallel-item::after {
  content: "";
  width: 100%;
  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);
  flex-grow: 1;
}

#sk-container-id-2 div.sk-parallel {
  display: flex;
  align-items: stretch;
  justify-content: center;
  background-color: var(--sklearn-color-background);
  position: relative;
}

#sk-container-id-2 div.sk-parallel-item {
  display: flex;
  flex-direction: column;
}

#sk-container-id-2 div.sk-parallel-item:first-child::after {
  align-self: flex-end;
  width: 50%;
}

#sk-container-id-2 div.sk-parallel-item:last-child::after {
  align-self: flex-start;
  width: 50%;
}

#sk-container-id-2 div.sk-parallel-item:only-child::after {
  width: 0;
}

/* Serial-specific style estimator block */

#sk-container-id-2 div.sk-serial {
  display: flex;
  flex-direction: column;
  align-items: center;
  background-color: var(--sklearn-color-background);
  padding-right: 1em;
  padding-left: 1em;
}


/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is
clickable and can be expanded/collapsed.
- Pipeline and ColumnTransformer use this feature and define the default style
- Estimators will overwrite some part of the style using the `sk-estimator` class
*/

/* Pipeline and ColumnTransformer style (default) */

#sk-container-id-2 div.sk-toggleable {
  /* Default theme specific background. It is overwritten whether we have a
  specific estimator or a Pipeline/ColumnTransformer */
  background-color: var(--sklearn-color-background);
}

/* Toggleable label */
#sk-container-id-2 label.sk-toggleable__label {
  cursor: pointer;
  display: flex;
  width: 100%;
  margin-bottom: 0;
  padding: 0.5em;
  box-sizing: border-box;
  text-align: center;
  align-items: start;
  justify-content: space-between;
  gap: 0.5em;
}

#sk-container-id-2 label.sk-toggleable__label .caption {
  font-size: 0.6rem;
  font-weight: lighter;
  color: var(--sklearn-color-text-muted);
}

#sk-container-id-2 label.sk-toggleable__label-arrow:before {
  /* Arrow on the left of the label */
  content: "▸";
  float: left;
  margin-right: 0.25em;
  color: var(--sklearn-color-icon);
}

#sk-container-id-2 label.sk-toggleable__label-arrow:hover:before {
  color: var(--sklearn-color-text);
}

/* Toggleable content - dropdown */

#sk-container-id-2 div.sk-toggleable__content {
  max-height: 0;
  max-width: 0;
  overflow: hidden;
  text-align: left;
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-0);
}

#sk-container-id-2 div.sk-toggleable__content.fitted {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-0);
}

#sk-container-id-2 div.sk-toggleable__content pre {
  margin: 0.2em;
  border-radius: 0.25em;
  color: var(--sklearn-color-text);
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-0);
}

#sk-container-id-2 div.sk-toggleable__content.fitted pre {
  /* unfitted */
  background-color: var(--sklearn-color-fitted-level-0);
}

#sk-container-id-2 input.sk-toggleable__control:checked~div.sk-toggleable__content {
  /* Expand drop-down */
  max-height: 200px;
  max-width: 100%;
  overflow: auto;
}

#sk-container-id-2 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {
  content: "▾";
}

/* Pipeline/ColumnTransformer-specific style */

#sk-container-id-2 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {
  color: var(--sklearn-color-text);
  background-color: var(--sklearn-color-unfitted-level-2);
}

#sk-container-id-2 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {
  background-color: var(--sklearn-color-fitted-level-2);
}

/* Estimator-specific style */

/* Colorize estimator box */
#sk-container-id-2 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-2);
}

#sk-container-id-2 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-2);
}

#sk-container-id-2 div.sk-label label.sk-toggleable__label,
#sk-container-id-2 div.sk-label label {
  /* The background is the default theme color */
  color: var(--sklearn-color-text-on-default-background);
}

/* On hover, darken the color of the background */
#sk-container-id-2 div.sk-label:hover label.sk-toggleable__label {
  color: var(--sklearn-color-text);
  background-color: var(--sklearn-color-unfitted-level-2);
}

/* Label box, darken color on hover, fitted */
#sk-container-id-2 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {
  color: var(--sklearn-color-text);
  background-color: var(--sklearn-color-fitted-level-2);
}

/* Estimator label */

#sk-container-id-2 div.sk-label label {
  font-family: monospace;
  font-weight: bold;
  display: inline-block;
  line-height: 1.2em;
}

#sk-container-id-2 div.sk-label-container {
  text-align: center;
}

/* Estimator-specific */
#sk-container-id-2 div.sk-estimator {
  font-family: monospace;
  border: 1px dotted var(--sklearn-color-border-box);
  border-radius: 0.25em;
  box-sizing: border-box;
  margin-bottom: 0.5em;
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-0);
}

#sk-container-id-2 div.sk-estimator.fitted {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-0);
}

/* on hover */
#sk-container-id-2 div.sk-estimator:hover {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-2);
}

#sk-container-id-2 div.sk-estimator.fitted:hover {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-2);
}

/* Specification for estimator info (e.g. "i" and "?") */

/* Common style for "i" and "?" */

.sk-estimator-doc-link,
a:link.sk-estimator-doc-link,
a:visited.sk-estimator-doc-link {
  float: right;
  font-size: smaller;
  line-height: 1em;
  font-family: monospace;
  background-color: var(--sklearn-color-background);
  border-radius: 1em;
  height: 1em;
  width: 1em;
  text-decoration: none !important;
  margin-left: 0.5em;
  text-align: center;
  /* unfitted */
  border: var(--sklearn-color-unfitted-level-1) 1pt solid;
  color: var(--sklearn-color-unfitted-level-1);
}

.sk-estimator-doc-link.fitted,
a:link.sk-estimator-doc-link.fitted,
a:visited.sk-estimator-doc-link.fitted {
  /* fitted */
  border: var(--sklearn-color-fitted-level-1) 1pt solid;
  color: var(--sklearn-color-fitted-level-1);
}

/* On hover */
div.sk-estimator:hover .sk-estimator-doc-link:hover,
.sk-estimator-doc-link:hover,
div.sk-label-container:hover .sk-estimator-doc-link:hover,
.sk-estimator-doc-link:hover {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-3);
  color: var(--sklearn-color-background);
  text-decoration: none;
}

div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,
.sk-estimator-doc-link.fitted:hover,
div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,
.sk-estimator-doc-link.fitted:hover {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-3);
  color: var(--sklearn-color-background);
  text-decoration: none;
}

/* Span, style for the box shown on hovering the info icon */
.sk-estimator-doc-link span {
  display: none;
  z-index: 9999;
  position: relative;
  font-weight: normal;
  right: .2ex;
  padding: .5ex;
  margin: .5ex;
  width: min-content;
  min-width: 20ex;
  max-width: 50ex;
  color: var(--sklearn-color-text);
  box-shadow: 2pt 2pt 4pt #999;
  /* unfitted */
  background: var(--sklearn-color-unfitted-level-0);
  border: .5pt solid var(--sklearn-color-unfitted-level-3);
}

.sk-estimator-doc-link.fitted span {
  /* fitted */
  background: var(--sklearn-color-fitted-level-0);
  border: var(--sklearn-color-fitted-level-3);
}

.sk-estimator-doc-link:hover span {
  display: block;
}

/* "?"-specific style due to the `<a>` HTML tag */

#sk-container-id-2 a.estimator_doc_link {
  float: right;
  font-size: 1rem;
  line-height: 1em;
  font-family: monospace;
  background-color: var(--sklearn-color-background);
  border-radius: 1rem;
  height: 1rem;
  width: 1rem;
  text-decoration: none;
  /* unfitted */
  color: var(--sklearn-color-unfitted-level-1);
  border: var(--sklearn-color-unfitted-level-1) 1pt solid;
}

#sk-container-id-2 a.estimator_doc_link.fitted {
  /* fitted */
  border: var(--sklearn-color-fitted-level-1) 1pt solid;
  color: var(--sklearn-color-fitted-level-1);
}

/* On hover */
#sk-container-id-2 a.estimator_doc_link:hover {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-3);
  color: var(--sklearn-color-background);
  text-decoration: none;
}

#sk-container-id-2 a.estimator_doc_link.fitted:hover {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-3);
}
</style><div id="sk-container-id-2" class="sk-top-container"><div class="sk-text-repr-fallback"><pre>LogisticRegression()</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br>On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class="sk-container" hidden=""><div class="sk-item"><div class="sk-estimator fitted sk-toggleable"><input class="sk-toggleable__control sk-hidden--visually" id="sk-estimator-id-2" type="checkbox" checked=""><label for="sk-estimator-id-2" class="sk-toggleable__label fitted sk-toggleable__label-arrow"><div><div>LogisticRegression</div></div><div><a class="sk-estimator-doc-link fitted" rel="noreferrer" target="_blank" href="https://scikit-learn.org/1.6/modules/generated/sklearn.linear_model.LogisticRegression.html">?<span>Documentation for LogisticRegression</span></a><span class="sk-estimator-doc-link fitted">i<span>Fitted</span></span></div></label><div class="sk-toggleable__content fitted"><pre>LogisticRegression()</pre></div> </div></div></div></div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb67" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb67-1">accuracy_score(valid_y.numpy(), reg.predict(valid_x))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0.7821229050279329</code></pre>
</div>
</div>
<p>It looks like our coefficient estimates are similar to the logistic regression ones.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb69" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb69-1">show_coeffs(coeffs_est).assign(logreg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(reg.coef_.T, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>               value  logreg
Age        -0.516476 -0.4799
SibSp      -0.423656 -0.4191
Parch      -0.179623 -0.1265
LogFare     0.396468  0.3441
Sex_male   -0.927410 -0.6262
Sex_female  0.349448  0.6262
Pclass_1    0.713895  0.3941
Pclass_2    0.320935  0.0675
Pclass_3    0.078919 -0.3945
Embarked_C  0.107378  0.0546
Embarked_Q  0.082943  0.0655
Embarked_S -0.036137 -0.0890</code></pre>
</div>
</div>
</section>
</section>
<section id="a-neural-network" class="level2">
<h2 class="anchored" data-anchor-id="a-neural-network">A Neural Network</h2>
<p><img src="https://m-clark.github.io/img/nnet.png" style="display:block; margin: 0 auto; width:33%"></p>
<p>At this point we’ve basically reproduced a general linear model. A <em>neural network</em>, on the other hand, has from one to many <em>hidden layers</em> of varying types in between input and output. Let’s say we have a single layer with two nodes. For a <em>fully connected</em> or <em>dense</em> network, we’d need weights to map our features to each node of the hidden layer (<code>n_wts</code> * <code>n_hidden</code> parameters total), and then another set of weights to map the hidden nodes to our next layer, which is our output, basically creating the predicted values. You can think of it as a second hidden layer with a single output node. With additional hidden nodes we add more complexity, but also flexibility, to the model. But this may come at a price, e.g.&nbsp;more difficulty with training due to the additional parameters that have to be estimated.</p>
<p>So basically we need matrices of weights, and the following function allows us to create those. We also add a <em>bias/intercept/constant</em> for the hidden-to-output processing. In the first layer, we divide the weights by <code>n_hidden</code> to create sums at the next layer that are of similar magnitude as the inputs. In general though, there are many ways to <a href="https://machinelearningmastery.com/weight-initialization-for-deep-learning-neural-networks/">initialize weights</a>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb71" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb71-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> init_weights(n_wts, n_hidden <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>):</span>
<span id="cb71-2">    layer1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (torch.rand(n_wts, n_hidden) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> n_hidden <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># n_wts x n_hidden matrix of weights</span></span>
<span id="cb71-3">    layer2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.rand(n_hidden, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>                  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># n_hidden weights</span></span>
<span id="cb71-4">    const  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.rand(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]                               <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># constant</span></span>
<span id="cb71-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> layer1.requires_grad_(), layer2.requires_grad_(), const.requires_grad_()</span></code></pre></div></div>
</div>
<p>Now we revise our <span class="func">calc_preds</span> function to incorporate all the weights. Initially, we extract the different sets of weights that are estimated by the model. For the original inputs, we multiply them by the layer 1 weights and sum. Then we apply a transformation to them to induce nonlinearity. Typical approaches are the sigmoid function we used before, hyperbolic tangent, and, probably the most common, the <a href="https://en.wikipedia.org/wiki/Rectifier_(neural_networks)">relu</a>. The original notebook used relu, while I use a more recent one called <em>Mish</em>, which is a variant of relu. The hidden layer nodes then get multiplied by their respective weights and summed with the constant added. We then use our sigmoid function to get the probability scale as before.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb72" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb72-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> torch.nn.functional <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> F</span>
<span id="cb72-2"></span>
<span id="cb72-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> calc_preds(X, weights):</span>
<span id="cb72-4">    l1, l2, const <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> weights</span>
<span id="cb72-5">    res <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> F.mish(X<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span>l1)</span>
<span id="cb72-6">    res <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> res<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span>l2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> const</span>
<span id="cb72-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> torch.sigmoid(res).flatten()</span></code></pre></div></div>
</div>
<p>With additional sets of weights, we use an update loop.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb73" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb73-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> update_weights(weights, lr):</span>
<span id="cb73-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> layer <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> weights:</span>
<span id="cb73-3">        layer.sub_(layer.grad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> lr)</span>
<span id="cb73-4">        layer.grad.zero_()</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb74" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb74-1">coeffs_est <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_model(train_x, train_y, epochs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> 0.325837
  0.155810
  0.141485
  0.137652
  0.136034
 </code></pre>
</div>
</div>
<p>At this point we’re doing a little bit better in general, and even better than standard logistic regression on the test set!</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb76" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb76-1">acc(train_x, coeffs_est, train_y), <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb76-2">acc(valid_x, coeffs_est, valid_y), <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb76-3">accuracy_score(valid_y.numpy(), reg.predict(valid_x))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>(tensor(0.8160), tensor(0.8045), 0.7821229050279329)</code></pre>
</div>
</div>
</section>
<section id="deep-learning" class="level2">
<h2 class="anchored" data-anchor-id="deep-learning">Deep Learning</h2>
<p>We previously used a single hidden layer, but we want to go deeper! That’s the whole point of deep learning right? The following modifies our previous functions to allow for an arbitrary number of layers. You’ll note there are some hacks to get the weights in a good way for each layer<sup>12</sup>, but you normally wouldn’t have to do that on your own, since most tools will provide sensible modifications.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb78" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb78-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> one_epoch(X, weights, target, lr, verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>):</span>
<span id="cb78-2">    loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> calc_loss(X, weights, target)</span>
<span id="cb78-3">    loss.backward()</span>
<span id="cb78-4">    </span>
<span id="cb78-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">with</span> torch.no_grad(): update_weights(weights, lr)</span>
<span id="cb78-6">    </span>
<span id="cb78-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb78-8">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb78-9">            <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>loss<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">: 3f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>, end <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> '</span>)</span>
<span id="cb78-10"></span>
<span id="cb78-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># change loss to binary</span></span>
<span id="cb78-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> calc_loss(X, weights, target, which <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'l2'</span>):</span>
<span id="cb78-13">    preds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> calc_preds(X, weights)</span>
<span id="cb78-14"></span>
<span id="cb78-15">    loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> torch.nn.BCELoss()</span>
<span id="cb78-16"></span>
<span id="cb78-17">    L <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> loss(preds, target.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">float</span>())</span>
<span id="cb78-18"></span>
<span id="cb78-19">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span>(L)</span>
<span id="cb78-20"></span>
<span id="cb78-21"></span>
<span id="cb78-22"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> init_weights(n_wts, hiddens):  </span>
<span id="cb78-23">    sizes <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [n_wts] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> hiddens <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb78-24">    n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(sizes)</span>
<span id="cb78-25">    layers <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [(torch.rand(sizes[i], sizes[i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>sizes[i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)]</span>
<span id="cb78-26">    consts <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [(torch.rand(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)]</span>
<span id="cb78-27">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> l <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> layers<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>consts: l.requires_grad_()</span>
<span id="cb78-28">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> layers, consts</span>
<span id="cb78-29"></span>
<span id="cb78-30"></span>
<span id="cb78-31"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> calc_preds(X, weights):</span>
<span id="cb78-32">    layers, consts <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> weights</span>
<span id="cb78-33">    n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(layers)</span>
<span id="cb78-34">    res <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X</span>
<span id="cb78-35">    </span>
<span id="cb78-36">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, l <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(layers):</span>
<span id="cb78-37">        res <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> res<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span>l <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> consts[i]</span>
<span id="cb78-38">    </span>
<span id="cb78-39">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>: </span>
<span id="cb78-40">      res <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> F.mish(res)</span>
<span id="cb78-41">      </span>
<span id="cb78-42">    </span>
<span id="cb78-43">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> torch.sigmoid(res).flatten()</span>
<span id="cb78-44"></span>
<span id="cb78-45"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> update_weights(weights, lr):</span>
<span id="cb78-46">    layers, consts <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> weights</span>
<span id="cb78-47">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> layer <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> layers <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> consts:</span>
<span id="cb78-48">        layer.sub_(layer.grad <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> lr)</span>
<span id="cb78-49">        layer.grad.zero_()</span>
<span id="cb78-50"></span>
<span id="cb78-51"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> train_model(X, target, hiddens <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>], epochs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-3</span>, verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>):</span>
<span id="cb78-52">    torch.manual_seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">442</span>)</span>
<span id="cb78-53">    coeffs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> init_weights(X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], hiddens)</span>
<span id="cb78-54">    </span>
<span id="cb78-55">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(epochs): </span>
<span id="cb78-56">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb78-57">            one_epoch(X, coeffs, target, lr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lr, verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> verbose, i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> i)</span>
<span id="cb78-58">    </span>
<span id="cb78-59">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> coeffs</span></code></pre></div></div>
</div>
<p>With everything set up, let’s do some deep linear modeling! You can play around with the number of hidden layers, number of nodes and other settings. Feel free to explore!</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb79" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb79-1">coeffs_est <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> train_model(</span>
<span id="cb79-2">  train_x,</span>
<span id="cb79-3">  train_y,</span>
<span id="cb79-4">  hiddens <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">250</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>],</span>
<span id="cb79-5">  epochs  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>,</span>
<span id="cb79-6">  lr      <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-4</span>,</span>
<span id="cb79-7">  verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span></span>
<span id="cb79-8">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> 5.123790
  0.666971
  0.653124
  0.640325
  0.628476
  0.617496
  0.607313
  0.597861
  0.589081
  0.580918
  0.573322
  0.566249
  0.559658
  0.553510
  0.547772
  0.542413
  0.537403
  0.532715
  0.528326
  0.524212
  0.520354
  0.516733
  0.513330
  0.510130
  0.507118
  0.504281
  0.501605
  0.499080
  0.496695
  0.494439
  0.492305
  0.490283
  0.488366
  0.486547
  0.484820
  0.483178
  0.481616
  0.480129
  0.478712
  0.477361
  0.476072
  0.474840
  0.473663
  0.472538
  0.471461
  0.470429
  0.469440
  0.468493
  0.467583
  0.466710
 </code></pre>
</div>
</div>
<p>Hooray! Our best model yet (at least tied).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb81" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb81-1">pd.DataFrame({</span>
<span id="cb81-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc_train'</span>: acc(train_x, coeffs_est, train_y).flatten(), </span>
<span id="cb81-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc_test'</span>: acc(valid_x, coeffs_est, valid_y).flatten(), </span>
<span id="cb81-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc_test_glm'</span>: accuracy_score(valid_y.numpy(), (reg.predict(valid_x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">.5</span>).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>))</span>
<span id="cb81-5">}, index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'value'</span>])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>       acc_train  acc_test  acc_test_glm
value    0.77809  0.804469      0.782123</code></pre>
</div>
</div>
</section>
<section id="the-elephant-in-the-room" class="level2">
<h2 class="anchored" data-anchor-id="the-elephant-in-the-room">The Elephant in the Room</h2>
<p>As noted in my previous posts [<a href="https://m-clark.github.io/posts/2021-07-15-dl-for-tabular/">1</a>, <a href="https://m-clark.github.io/posts/2022-04-01-more-dl-for-tabular/">2</a>], probably your biggest challenge in implementing a deep learning model for tabular data, one with mixed data types and other complexities, is beating an off the shelf boosting model. Here is a quick demo with <span class="pack">lightgbm</span>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb83" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb83-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> lightgbm <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LGBMClassifier</span>
<span id="cb83-2"></span>
<span id="cb83-3">model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LGBMClassifier(</span>
<span id="cb83-4">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># n_estimators = 500,  # the sorts of parameters you can play with (many more!)</span></span>
<span id="cb83-5">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># max_depth    = 4,</span></span>
<span id="cb83-6">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># reg_alpha    = .1</span></span>
<span id="cb83-7">)</span>
<span id="cb83-8"></span>
<span id="cb83-9">model.fit(train_x, train_y)</span></code></pre></div></div>
<div class="cell-output-display">
<style>#sk-container-id-3 {
  /* Definition of color scheme common for light and dark mode */
  --sklearn-color-text: #000;
  --sklearn-color-text-muted: #666;
  --sklearn-color-line: gray;
  /* Definition of color scheme for unfitted estimators */
  --sklearn-color-unfitted-level-0: #fff5e6;
  --sklearn-color-unfitted-level-1: #f6e4d2;
  --sklearn-color-unfitted-level-2: #ffe0b3;
  --sklearn-color-unfitted-level-3: chocolate;
  /* Definition of color scheme for fitted estimators */
  --sklearn-color-fitted-level-0: #f0f8ff;
  --sklearn-color-fitted-level-1: #d4ebff;
  --sklearn-color-fitted-level-2: #b3dbfd;
  --sklearn-color-fitted-level-3: cornflowerblue;

  /* Specific color for light theme */
  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));
  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));
  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));
  --sklearn-color-icon: #696969;

  @media (prefers-color-scheme: dark) {
    /* Redefinition of color scheme for dark theme */
    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));
    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));
    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));
    --sklearn-color-icon: #878787;
  }
}

#sk-container-id-3 {
  color: var(--sklearn-color-text);
}

#sk-container-id-3 pre {
  padding: 0;
}

#sk-container-id-3 input.sk-hidden--visually {
  border: 0;
  clip: rect(1px 1px 1px 1px);
  clip: rect(1px, 1px, 1px, 1px);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
}

#sk-container-id-3 div.sk-dashed-wrapped {
  border: 1px dashed var(--sklearn-color-line);
  margin: 0 0.4em 0.5em 0.4em;
  box-sizing: border-box;
  padding-bottom: 0.4em;
  background-color: var(--sklearn-color-background);
}

#sk-container-id-3 div.sk-container {
  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`
     but bootstrap.min.css set `[hidden] { display: none !important; }`
     so we also need the `!important` here to be able to override the
     default hidden behavior on the sphinx rendered scikit-learn.org.
     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */
  display: inline-block !important;
  position: relative;
}

#sk-container-id-3 div.sk-text-repr-fallback {
  display: none;
}

div.sk-parallel-item,
div.sk-serial,
div.sk-item {
  /* draw centered vertical line to link estimators */
  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));
  background-size: 2px 100%;
  background-repeat: no-repeat;
  background-position: center center;
}

/* Parallel-specific style estimator block */

#sk-container-id-3 div.sk-parallel-item::after {
  content: "";
  width: 100%;
  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);
  flex-grow: 1;
}

#sk-container-id-3 div.sk-parallel {
  display: flex;
  align-items: stretch;
  justify-content: center;
  background-color: var(--sklearn-color-background);
  position: relative;
}

#sk-container-id-3 div.sk-parallel-item {
  display: flex;
  flex-direction: column;
}

#sk-container-id-3 div.sk-parallel-item:first-child::after {
  align-self: flex-end;
  width: 50%;
}

#sk-container-id-3 div.sk-parallel-item:last-child::after {
  align-self: flex-start;
  width: 50%;
}

#sk-container-id-3 div.sk-parallel-item:only-child::after {
  width: 0;
}

/* Serial-specific style estimator block */

#sk-container-id-3 div.sk-serial {
  display: flex;
  flex-direction: column;
  align-items: center;
  background-color: var(--sklearn-color-background);
  padding-right: 1em;
  padding-left: 1em;
}


/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is
clickable and can be expanded/collapsed.
- Pipeline and ColumnTransformer use this feature and define the default style
- Estimators will overwrite some part of the style using the `sk-estimator` class
*/

/* Pipeline and ColumnTransformer style (default) */

#sk-container-id-3 div.sk-toggleable {
  /* Default theme specific background. It is overwritten whether we have a
  specific estimator or a Pipeline/ColumnTransformer */
  background-color: var(--sklearn-color-background);
}

/* Toggleable label */
#sk-container-id-3 label.sk-toggleable__label {
  cursor: pointer;
  display: flex;
  width: 100%;
  margin-bottom: 0;
  padding: 0.5em;
  box-sizing: border-box;
  text-align: center;
  align-items: start;
  justify-content: space-between;
  gap: 0.5em;
}

#sk-container-id-3 label.sk-toggleable__label .caption {
  font-size: 0.6rem;
  font-weight: lighter;
  color: var(--sklearn-color-text-muted);
}

#sk-container-id-3 label.sk-toggleable__label-arrow:before {
  /* Arrow on the left of the label */
  content: "▸";
  float: left;
  margin-right: 0.25em;
  color: var(--sklearn-color-icon);
}

#sk-container-id-3 label.sk-toggleable__label-arrow:hover:before {
  color: var(--sklearn-color-text);
}

/* Toggleable content - dropdown */

#sk-container-id-3 div.sk-toggleable__content {
  max-height: 0;
  max-width: 0;
  overflow: hidden;
  text-align: left;
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-0);
}

#sk-container-id-3 div.sk-toggleable__content.fitted {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-0);
}

#sk-container-id-3 div.sk-toggleable__content pre {
  margin: 0.2em;
  border-radius: 0.25em;
  color: var(--sklearn-color-text);
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-0);
}

#sk-container-id-3 div.sk-toggleable__content.fitted pre {
  /* unfitted */
  background-color: var(--sklearn-color-fitted-level-0);
}

#sk-container-id-3 input.sk-toggleable__control:checked~div.sk-toggleable__content {
  /* Expand drop-down */
  max-height: 200px;
  max-width: 100%;
  overflow: auto;
}

#sk-container-id-3 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {
  content: "▾";
}

/* Pipeline/ColumnTransformer-specific style */

#sk-container-id-3 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {
  color: var(--sklearn-color-text);
  background-color: var(--sklearn-color-unfitted-level-2);
}

#sk-container-id-3 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {
  background-color: var(--sklearn-color-fitted-level-2);
}

/* Estimator-specific style */

/* Colorize estimator box */
#sk-container-id-3 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-2);
}

#sk-container-id-3 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-2);
}

#sk-container-id-3 div.sk-label label.sk-toggleable__label,
#sk-container-id-3 div.sk-label label {
  /* The background is the default theme color */
  color: var(--sklearn-color-text-on-default-background);
}

/* On hover, darken the color of the background */
#sk-container-id-3 div.sk-label:hover label.sk-toggleable__label {
  color: var(--sklearn-color-text);
  background-color: var(--sklearn-color-unfitted-level-2);
}

/* Label box, darken color on hover, fitted */
#sk-container-id-3 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {
  color: var(--sklearn-color-text);
  background-color: var(--sklearn-color-fitted-level-2);
}

/* Estimator label */

#sk-container-id-3 div.sk-label label {
  font-family: monospace;
  font-weight: bold;
  display: inline-block;
  line-height: 1.2em;
}

#sk-container-id-3 div.sk-label-container {
  text-align: center;
}

/* Estimator-specific */
#sk-container-id-3 div.sk-estimator {
  font-family: monospace;
  border: 1px dotted var(--sklearn-color-border-box);
  border-radius: 0.25em;
  box-sizing: border-box;
  margin-bottom: 0.5em;
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-0);
}

#sk-container-id-3 div.sk-estimator.fitted {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-0);
}

/* on hover */
#sk-container-id-3 div.sk-estimator:hover {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-2);
}

#sk-container-id-3 div.sk-estimator.fitted:hover {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-2);
}

/* Specification for estimator info (e.g. "i" and "?") */

/* Common style for "i" and "?" */

.sk-estimator-doc-link,
a:link.sk-estimator-doc-link,
a:visited.sk-estimator-doc-link {
  float: right;
  font-size: smaller;
  line-height: 1em;
  font-family: monospace;
  background-color: var(--sklearn-color-background);
  border-radius: 1em;
  height: 1em;
  width: 1em;
  text-decoration: none !important;
  margin-left: 0.5em;
  text-align: center;
  /* unfitted */
  border: var(--sklearn-color-unfitted-level-1) 1pt solid;
  color: var(--sklearn-color-unfitted-level-1);
}

.sk-estimator-doc-link.fitted,
a:link.sk-estimator-doc-link.fitted,
a:visited.sk-estimator-doc-link.fitted {
  /* fitted */
  border: var(--sklearn-color-fitted-level-1) 1pt solid;
  color: var(--sklearn-color-fitted-level-1);
}

/* On hover */
div.sk-estimator:hover .sk-estimator-doc-link:hover,
.sk-estimator-doc-link:hover,
div.sk-label-container:hover .sk-estimator-doc-link:hover,
.sk-estimator-doc-link:hover {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-3);
  color: var(--sklearn-color-background);
  text-decoration: none;
}

div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,
.sk-estimator-doc-link.fitted:hover,
div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,
.sk-estimator-doc-link.fitted:hover {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-3);
  color: var(--sklearn-color-background);
  text-decoration: none;
}

/* Span, style for the box shown on hovering the info icon */
.sk-estimator-doc-link span {
  display: none;
  z-index: 9999;
  position: relative;
  font-weight: normal;
  right: .2ex;
  padding: .5ex;
  margin: .5ex;
  width: min-content;
  min-width: 20ex;
  max-width: 50ex;
  color: var(--sklearn-color-text);
  box-shadow: 2pt 2pt 4pt #999;
  /* unfitted */
  background: var(--sklearn-color-unfitted-level-0);
  border: .5pt solid var(--sklearn-color-unfitted-level-3);
}

.sk-estimator-doc-link.fitted span {
  /* fitted */
  background: var(--sklearn-color-fitted-level-0);
  border: var(--sklearn-color-fitted-level-3);
}

.sk-estimator-doc-link:hover span {
  display: block;
}

/* "?"-specific style due to the `<a>` HTML tag */

#sk-container-id-3 a.estimator_doc_link {
  float: right;
  font-size: 1rem;
  line-height: 1em;
  font-family: monospace;
  background-color: var(--sklearn-color-background);
  border-radius: 1rem;
  height: 1rem;
  width: 1rem;
  text-decoration: none;
  /* unfitted */
  color: var(--sklearn-color-unfitted-level-1);
  border: var(--sklearn-color-unfitted-level-1) 1pt solid;
}

#sk-container-id-3 a.estimator_doc_link.fitted {
  /* fitted */
  border: var(--sklearn-color-fitted-level-1) 1pt solid;
  color: var(--sklearn-color-fitted-level-1);
}

/* On hover */
#sk-container-id-3 a.estimator_doc_link:hover {
  /* unfitted */
  background-color: var(--sklearn-color-unfitted-level-3);
  color: var(--sklearn-color-background);
  text-decoration: none;
}

#sk-container-id-3 a.estimator_doc_link.fitted:hover {
  /* fitted */
  background-color: var(--sklearn-color-fitted-level-3);
}
</style><div id="sk-container-id-3" class="sk-top-container"><div class="sk-text-repr-fallback"><pre>LGBMClassifier()</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br>On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class="sk-container" hidden=""><div class="sk-item"><div class="sk-estimator fitted sk-toggleable"><input class="sk-toggleable__control sk-hidden--visually" id="sk-estimator-id-3" type="checkbox" checked=""><label for="sk-estimator-id-3" class="sk-toggleable__label fitted sk-toggleable__label-arrow"><div><div>LGBMClassifier</div></div><div><span class="sk-estimator-doc-link fitted">i<span>Fitted</span></span></div></label><div class="sk-toggleable__content fitted"><pre>LGBMClassifier()</pre></div> </div></div></div></div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb84" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb84-1">model.score(valid_x, valid_y.numpy())</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0.8491620111731844</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb86" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb86-1"></span>
<span id="cb86-2"></span>
<span id="cb86-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># sklearn example</span></span>
<span id="cb86-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># from sklearn.ensemble import HistGradientBoostingClassifier</span></span>
<span id="cb86-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># </span></span>
<span id="cb86-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># res = HistGradientBoostingClassifier().fit(train_x.numpy(), train_y.numpy())</span></span>
<span id="cb86-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># </span></span>
<span id="cb86-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># res.score(valid_x.numpy(), valid_y.numpy())</span></span></code></pre></div></div>
</div>
<p>No tuning at all, and we’re already doing significantly better. Granted, if you use a packaged DL model for tabular data like the one in <span class="pack">fastai</span>, you should be doing better than our little demo. Even then though, you may still find the boosting results tough to beat.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb87" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb87-1">df_accs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({ </span>
<span id="cb87-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc_test_dl'</span>:   acc(valid_x, coeffs_est, valid_y).flatten(), </span>
<span id="cb87-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc_test_glm'</span>:  accuracy_score(valid_y.numpy(), (reg.predict(valid_x) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">.5</span>).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)),</span>
<span id="cb87-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acc_test_lgbm'</span>: model.score(valid_x, valid_y.numpy())</span>
<span id="cb87-5">}, index <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'value'</span>]).<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb87-6"></span>
<span id="cb87-7">df_accs</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>       acc_test_dl  acc_test_glm  acc_test_lgbm
value       0.8045        0.7821         0.8492</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb89" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb89-1">df_perc_improvement <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (df_accs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> df_accs.iloc[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># % improvement</span></span>
<span id="cb89-2">df_perc_improvement</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>       acc_test_dl  acc_test_glm  acc_test_lgbm
value     2.864075           0.0       8.579466</code></pre>
</div>
</div>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>This was a lot of work to do slightly better than a logistic regression! However, there is a lot going on with a typical DL model that would likely prove even better. But it also serves as a reminder to have a suitable baseline, and as we saw with the lightgbm model, it can take little effort to do very well without deep learning. Hopefully though, the peek behind the scenes to do some ‘deep’ linear modeling can make it more accessible for you.</p>



</section>


<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-clark2022dl4tab2" class="csl-entry">
Clark, Michael. 2022a. <em>Deep Learning for Tabular Data</em>. <a href="https://m-clark.github.io/posts/2022-04-01-more-dl-for-tabular/">https://m-clark.github.io/posts/2022-04-01-more-dl-for-tabular/</a>.
</div>
<div id="ref-clark2022dl4tab1" class="csl-entry">
Clark, Michael. 2022b. <em>This Is Definitely Not All You Need</em>. <a href="https://m-clark.github.io/posts/2021-07-15-dl-for-tabular/">https://m-clark.github.io/posts/2021-07-15-dl-for-tabular/</a>.
</div>
<div id="ref-howard2022neuralnet" class="csl-entry">
Howard, Jeremy. 2022a. <span>“How Does a Neural Net Really Work?”</span> <em>Kaggle</em>. <a href="https://www.kaggle.com/code/jhoward/how-does-a-neural-net-really-work">https://www.kaggle.com/code/jhoward/how-does-a-neural-net-really-work</a>.
</div>
<div id="ref-howard2022linreg" class="csl-entry">
Howard, Jeremy. 2022b. <span>“Linear Model and Neural Net from Scratch.”</span> <em>Kaggle</em>. <a href="https://www.kaggle.com/code/jhoward/linear-model-and-neural-net-from-scratch">https://www.kaggle.com/code/jhoward/linear-model-and-neural-net-from-scratch</a>.
</div>
<div id="ref-howard2022neuralnet2" class="csl-entry">
Howard, Jeremy. 2022c. <span>“What Is Torch.nn Really?”</span> <em>Kaggle</em>. <a href="https://pytorch.org/tutorials/beginner/nn_tutorial.html">https://pytorch.org/tutorials/beginner/nn_tutorial.html</a>.
</div>
<div id="ref-raschka2022chrono" class="csl-entry">
Raschka, Sebastian. 2022. <em>A Short Chronology of Deep Learning for Tabular Data</em>. <a href="https://sebastianraschka.com/blog/2022/deep-learning-for-tabular-data.html">https://sebastianraschka.com/blog/2022/deep-learning-for-tabular-data.html</a>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>I won’t actually use <span class="pack">fastai</span>, since they aren’t up to supporting M1/2 Macs very well. I think it was only used for the train/test data split anyway. I would rant a bit about this, but a lot of <span class="pack">fastai</span> is geared toward non-local computing, and the fault is really with Apple and NVidia as near as I can tell.↩︎</p></li>
<li id="fn2"><p>I’m also not going to go into broadcasting, submitting to Kaggle, and other things that I don’t think are necessary for our purposes here.↩︎</p></li>
<li id="fn3"><p>Just as an aside, this sort of approach to impute has largely been frowned upon in the statistical world for decades for numerous (and valid) reasons, but we just want something quick and dirty here, and sometimes that’s enough.↩︎</p></li>
<li id="fn4"><p>Even though every modeling tool requires this, strangely very few in the Python world offer options for automatic handling of such things, but it’s getting better.↩︎</p></li>
<li id="fn5"><p>We actually aren’t too far removed from this in our model coming up, the main difference is that we don’t treat the categorical feature part of the model separately.↩︎</p></li>
<li id="fn6"><p>I’ll not perpetuate calling features/predictor variables that are clearly not independent as independent. That nomenclature really only works for randomized experiments, and that is definitely not the case here.↩︎</p></li>
<li id="fn7"><p>You could use <span class="func">torch.randn</span> to get standard normal values, and often times we’ll even start with just zeros if we really are just doing a standard linear model.↩︎</p></li>
<li id="fn8"><p>Unless you are an economist, in which case you call it a <em>linear probability model</em> and ignore the ridiculous predictions because you have very fine standard errors.↩︎</p></li>
<li id="fn9"><p>A lot of R folks seem unaware that the base R <span class="func">plogis</span> function accomplishes this.↩︎</p></li>
<li id="fn10"><p>The <code>@</code> operator is essentially the dot product, so <code>x@y</code> is <code>np.dot(x, y)</code>↩︎</p></li>
<li id="fn11"><p>The <span class="pack">fastai</span> demo also changes the target to a column vector, but this doesn’t seem necessary.↩︎</p></li>
<li id="fn12"><p>And they probably aren’t as good for the changes I’ve made.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2022,
  author = {Clark, Michael},
  title = {Deep {Linear} {Models}},
  date = {2022-10-10},
  url = {https://m-clark.github.io/posts/2022-09-deep-linear-models/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2022" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2022. <span>“Deep Linear Models.”</span> October 10. <a href="https://m-clark.github.io/posts/2022-09-deep-linear-models/">https://m-clark.github.io/posts/2022-09-deep-linear-models/</a>.
</div></div></section></div> ]]></description>
  <category>deep learning</category>
  <category>boosting</category>
  <category>regression</category>
  <category>machine learning</category>
  <guid>https://m-clark.github.io/posts/2022-09-deep-linear-models/</guid>
  <pubDate>Mon, 10 Oct 2022 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/nnet.png" medium="image" type="image/png" height="120" width="144"/>
</item>
<item>
  <title>Exploring Time</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2021-05-time-series/</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>NB: This post was revisited when updating the website early 2025, and some changes were required. Attempts to keep things consistent were made, but if you feel you’ve found an issue, please post it at <a href="http://github.com/m-clark/m-clark.github.io/issues">GitHub</a>.</p>
</blockquote>
<section id="intro" class="level2">
<h2 class="anchored" data-anchor-id="intro">Intro</h2>
<blockquote class="blockquote">
<p>This post was mostly complete around May 2021, but for various reasons not actually posted until August of 2022. I haven’t changed much aside from adding a section on boosting, and have used the results I conjured up previously (for the most part). However, many package updates since then may mean that parts of the code may not work as well, especially for the torch code. I would also recommend modeltime as starting point for implementing a variety of model approaches for time series data with R. It was still pretty new when this was first written, but has many new features and capabilities, and could do some version of the models shown here.</p>
</blockquote>
<p>It is extremely common to have data that exists over a period of time. For example, we might have yearly sports statistics, daily manufacturing records, server logs that might be occurring many times per second, and similar. There are many approaches we could use to model the data in these scenarios. When there are few time points and they are clustered within other units, like repeated observations of exercise data for many individuals, we often use tools like <a href="https://m-clark.github.io/mixed-models-with-R/">mixed models</a> for example, and even with many observations in a series, we can still use tools like that. But sometimes there may be no natural clustering, or we might want to use other approaches to handle additional complexity.</p>
<p>This post is inspired by a co-worker’s efforts in using PyTorch to analyze Chicago Transit data. <a href="https://twitter.com/codydirks">Cody Dirks</a> wrote <a href="https://www.strong.io/blog/forecasting-public-transport-utilization-in-chicago">a post</a> where he used a <a href="https://github.com/strongio/torchcast">Python module</a> developed by our group at <a href="https://strong.io/">Strong Analytics</a> to analyze the ridership across all the ‘<a href="https://en.wikipedia.org/wiki/Chicago_%22L%22">L</a>’. This post can be seen as a demonstration of some simpler models which might also be viable for a given situation such as this, allowing for quick dives, or even as ends in themselves.</p>
</section>
<section id="outline" class="level2">
<h2 class="anchored" data-anchor-id="outline">Outline</h2>
<p>The models we’ll go through are the following:</p>
<ul>
<li>Error models and random effects</li>
<li>GAM</li>
<li>More elaborate time series with seasonal and other effects</li>
<li>Boosting and Deep learning</li>
</ul>
<p>In what follows I will show some more detailed code in the beginning, but won’t show it later for conciseness, focusing mostly just on the basic model code. You can always find the code for these posts on my <a href="https:://github.com/m-clark/m-clark.github.io">GitHub</a>.</p>
</section>
<section id="quick-summary" class="level2">
<h2 class="anchored" data-anchor-id="quick-summary">Quick Summary</h2>
<ul>
<li><p>Classical econometrics approaches like ARIMA models may take notable effort to match the flexibility of other approaches one might take with time series. It’s also difficult to believe a specific lag/ma number will hold up with any data change.</p></li>
<li><p>GAMs extend mixed models, and should probably be preferred if a probabilistic approach is desired. Prophet-style approaches would likely take notable effort and still likely lack performance, without adding interpretability.</p></li>
<li><p>For black box methods, boosting can do very well without much feature engineering, but possibly take a bit more for parameter tuning. Deep learning methods may be your best bet given data size and other data modeling needs.</p></li>
</ul>
</section>
<section id="data-description" class="level2">
<h2 class="anchored" data-anchor-id="data-description">Data Description</h2>
<p>As noted in <a href="https://www.strong.io/blog/forecasting-public-transport-utilization-in-chicago">Cody’s post</a>, over 750,000 people use the Chicago Transit Authority’s ‘L’ system to get around the city. There are 8 interconnected rail lines named after colors- the Red, Blue, Green, Brown, Pink, Orange, Purple, and Yellow, 145 entry/exit stations, and over 2,300 combined trips by its railcars every day<sup>1</sup>.</p>
<p>The city of Chicago provides ridership data that can be accessed publicly.</p>
<ul>
<li><a href="https://data.cityofchicago.org/Transportation/CTA-Ridership-L-Station-Entries-Daily-Totals/5neh-572f">ridership</a></li>
<li><a href="https://data.cityofchicago.org/Transportation/CTA-System-Information-List-of-L-Stops/8pix-ypme">station info</a></li>
</ul>
<p>In Cody’s exploration, he added pertinent information regarding weather, sporting events, and more. You can access the <a href="https://github.com/m-clark/m-clark.github.io/tree/master/data/time-series/processed_df.csv">processed data</a>.</p>
<p>For our demonstrations we have daily ridership from 2012-2018, and we will use a variety of methods to model this. We will use a normalized ride count (mean of 0, standard deviation of 1) as our target variable.</p>
<section id="import-setup" class="level3">
<h3 class="anchored" data-anchor-id="import-setup">Import &amp; Setup</h3>
<p>To get things started we’ll use the tidyverse for some additional data processing, and lubridate for any date processing, for example, converting to weekdays.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Data Processing</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;">library</span>(lubridate)</span>
<span id="cb1-5"></span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Misc</span></span>
<span id="cb1-8"></span>
<span id="cb1-9">START_DT <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;">'2008-06-01'</span></span>
<span id="cb1-10">END_DT   <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;">'2018-12-31'</span></span>
<span id="cb1-11">SPLIT_DT <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;">'2017-06-01'</span></span></code></pre></div></div>
</div>
<section id="main-data" class="level5">
<h5 class="anchored" data-anchor-id="main-data">Main data</h5>
<p>I start with data having already been processed, but as mentioned the source is publicly available. I use <span class="pack" style="">data.table</span> to read it in more quickly, but it’s default date class can cause issues with other packages, so I deal with that. I also extract the year, month, weekday, etc.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> data.table<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fread</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'data/time-series/processed_df.csv'</span>)</span>
<span id="cb2-2"></span>
<span id="cb2-3">df_start <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb2-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tibble</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb2-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">contains</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'_attributes'</span>), <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>(tsun<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>wt22)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb2-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb2-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">date      =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_date</span>(date), <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># remove IDATE class</span></span>
<span id="cb2-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rides_log =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(rides),</span>
<span id="cb2-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">year      =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">year</span>(date),</span>
<span id="cb2-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">year_fac  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(year),</span>
<span id="cb2-11">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">month     =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">month</span>(date, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>),</span>
<span id="cb2-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">day       =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wday</span>(date, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ordered =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>),</span>
<span id="cb2-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">year_day  =</span> lubridate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">yday</span>(date),</span>
<span id="cb2-14">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">line      =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(line),</span>
<span id="cb2-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">snow_scaled =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale</span>(snow)[, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb2-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colors =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.character</span>(line),</span>
<span id="cb2-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">colors =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ifelse</span>(colors <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;">'purple_express'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'purple4'</span>, colors),</span>
<span id="cb2-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">red_line_modernization =</span> </span>
<span id="cb2-19">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ifelse</span>(</span>
<span id="cb2-20">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">between</span>(date, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_date</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'2013-05-19'</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_date</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'2013-10-20'</span>)), </span>
<span id="cb2-21">        <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, </span>
<span id="cb2-22">        <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb2-23">      )</span>
<span id="cb2-24">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb2-25">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(date, line)</span></code></pre></div></div>
</div>
</section>
</section>
<section id="training-and-validation" class="level3">
<h3 class="anchored" data-anchor-id="training-and-validation">Training and Validation</h3>
<p>We split our data into training and validation sets, such that everything before 2017-06-01 is used for training, while everything after will be used for testing model performance<sup>2</sup>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">df_train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_start <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb3-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(date <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> SPLIT_DT, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(rides))</span>
<span id="cb3-3"></span>
<span id="cb3-4">df_validate <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_start <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb3-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(date <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> SPLIT_DT, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(rides))</span>
<span id="cb3-6"></span>
<span id="cb3-7">red_line_train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_train <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb3-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(line <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;">'red'</span>)</span>
<span id="cb3-9"></span>
<span id="cb3-10">red_line_validate <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_validate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb3-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(line <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;">'red'</span>)</span></code></pre></div></div>
</div>
</section>
<section id="other" class="level3">
<h3 class="anchored" data-anchor-id="other">Other</h3>
<p>Holidays are available via the <span class="pack" style="">prophet</span> package, which we’ll be demonstrating a model with later. The data we’re using already has a ‘holiday vs.&nbsp;not’ variable for simplicity, though it comes from a different source. The <span class="pack" style="">prophet</span> version has both the actual date and the observed date counted as a holiday, and I prefer to use both.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">holidays <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> prophet<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>generated_holidays <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;">filter</span>(country <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;">'US'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb4-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ds =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_date</span>(ds))) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb4-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">droplevels</span>()</span></code></pre></div></div>
</div>
<p>We’ll take a quick look at the red line similar to Cody’s post, so we can feel we have the data processed as we should.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-05-time-series/index_files/figure-html/dupe-plot-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>With the data ready to go, we are ready for modeling, so let’s get started!</p>
</section>
</section>
<section id="classical-time-series" class="level2">
<h2 class="anchored" data-anchor-id="classical-time-series">Classical Time Series</h2>
<section id="intro-1" class="level3">
<h3 class="anchored" data-anchor-id="intro-1">Intro</h3>
<p>Classical times series from an econometrics perspective often considers a error model that accounts for the correlation a current observation has with past observations. A traditional example is the so-called <em>autoregressive</em>, or <em>AR</em>, model, which lets a current observation be predicted by past observations up to a certain point. For example, would could start by just using the last observation to predict the current one. Next we extend this to predict the current based on the previous two observations, and so on. How many <em>lags</em> we use is part of the model exploration.</p>
<p><img src="https://latex.codecogs.com/png.latex?y_t%20=%20%5Calpha_1y_%7Bt-1%7D%20+%20%5Cdots%20+%5Calpha_%7Bp%7Dy_%7Bt-p%7D%20+%20%5Cvarepsilon_t"></p>
<p>We can extend this to include not just past observations but also past residuals, called a <em>moving average</em>. So formally, our <em>ARMA</em> (p, q) model now looks like this for an observation <img src="https://latex.codecogs.com/png.latex?y"> at time <img src="https://latex.codecogs.com/png.latex?t">:</p>
<p><img src="https://latex.codecogs.com/png.latex?y_t%20=%20%5Calpha_1y_%7Bt-1%7D%20+%20%5Cdots%20+%5Calpha_%7Bp%7Dy_%7Bt-p%7D%20+%20(%5Cvarepsilon_t%20+%20%5Ctheta_1%20%5Cvarepsilon_%7Bt-1%7D%20+%20%5Ccdots%20+%5Ctheta_q%20%5Cvarepsilon_%7Bt-q%7D)"></p>
<p>We can also use <a href="https://otexts.com/fpp3/stationarity.html">differencing</a>, for example subtracting the previous time value from the current observation value for all values, to come to the final <a href="https://en.wikipedia.org/wiki/Autoregressive_integrated_moving_average"><em>ARIMA</em> (p, d, q) model</a>. See <span class="citation" data-cites="Hyndman2021">Hyndman and Athanasopoulos (2021)</span> for more details.</p>
</section>
<section id="model" class="level3">
<h3 class="anchored" data-anchor-id="model">Model</h3>
<p>Even base R comes with basic time series models such as this. However, as mentioned, we typically don’t know what to set the values of an ARIMA(p, d, q) to. A quick way to explore this is via the <span class="pack" style="">forecast</span> package, which will search over the various hyperparameters and select one based on AIC. Note that <span class="pack" style="">fable</span>, a package we will be using later, will also allow such an approach, and if you’d like to go ahead and start using it I show some commented code below.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1">model_arima <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> forecast<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">auto.arima</span>(</span>
<span id="cb5-2">  red_line_train<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>rides_scaled</span>
<span id="cb5-3">)</span>
<span id="cb5-4"></span>
<span id="cb5-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># model_arima = red_line_train %&gt;%</span></span>
<span id="cb5-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   select(date, rides_scaled) %&gt;%</span></span>
<span id="cb5-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   tsibble::as_tsibble() %&gt;%</span></span>
<span id="cb5-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   fabletools::model(fable::ARIMA(</span></span>
<span id="cb5-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     rides_scaled ~ 0 + PDQ(0,0,0),</span></span>
<span id="cb5-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     stepwise = FALSE,</span></span>
<span id="cb5-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     approximation = FALSE</span></span>
<span id="cb5-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   ))</span></span>
<span id="cb5-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fabletools::report(model_arima)</span></span></code></pre></div></div>
</div>
</section>
<section id="explore" class="level3">
<h3 class="anchored" data-anchor-id="explore">Explore</h3>
<p>In this case we have a selected AR of 3 and MA of 4 for the centered value. But looking at the predictions, we can see this is an almost useless result for any number of days out, and does little better than guessing.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">broom<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tidy</span>(model_arima)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">term</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">estimate</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">std.error</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">ar1</td>
<td style="text-align: right;">0.238</td>
<td style="text-align: right;">0.048</td>
</tr>
<tr class="even">
<td style="text-align: left;">ar2</td>
<td style="text-align: right;">-0.285</td>
<td style="text-align: right;">0.035</td>
</tr>
<tr class="odd">
<td style="text-align: left;">ar3</td>
<td style="text-align: right;">0.354</td>
<td style="text-align: right;">0.043</td>
</tr>
<tr class="even">
<td style="text-align: left;">ma1</td>
<td style="text-align: right;">-0.725</td>
<td style="text-align: right;">0.046</td>
</tr>
<tr class="odd">
<td style="text-align: left;">ma2</td>
<td style="text-align: right;">-0.189</td>
<td style="text-align: right;">0.046</td>
</tr>
<tr class="even">
<td style="text-align: left;">ma3</td>
<td style="text-align: right;">-0.575</td>
<td style="text-align: right;">0.029</td>
</tr>
<tr class="odd">
<td style="text-align: left;">ma4</td>
<td style="text-align: right;">0.552</td>
<td style="text-align: right;">0.025</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># plot(acf(residuals(model_arima))) # weekly autocorrelation still exists</span></span>
<span id="cb7-2"></span>
<span id="cb7-3">red_line_validate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb7-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">slice</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)  <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb7-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pred =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(model_arima, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n.ahead =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>pred) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb7-6">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># mutate(pred = forecast(model_arima, h = 30)$.mean) %&gt;%</span></span>
<span id="cb7-7">  <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>(date, rides_scaled)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_line</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;">y =</span> pred), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'darkred'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-05-time-series/index_files/figure-html/arima-explore-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>We’ll use <span class="pack" style="">yardstick</span> to help us evaluate performance for this and subsequent models. In this case however, the visualization told us enough- a basic ARIMA isn’t going cut it.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(yardstick)</span>
<span id="cb8-2"></span>
<span id="cb8-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># this function will be used for all subsequent models!</span></span>
<span id="cb8-4">metric_score <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">metric_set</span>(rmse, mae, rsq) </span>
<span id="cb8-5"></span>
<span id="cb8-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># validation</span></span>
<span id="cb8-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb8-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pred =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(model_arima, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> red_line_validate, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n.ahead =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>pred,</span>
<span id="cb8-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">observed =</span> red_line_validate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>rides_scaled[<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;">30</span>]</span>
<span id="cb8-10">) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb8-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">metric_score</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">truth =</span> observed, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">estimate =</span> pred)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">.metric</th>
<th style="text-align: left;" data-quarto-table-cell-role="th">.estimator</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">.estimate</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">rmse</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.632</td>
</tr>
<tr class="even">
<td style="text-align: left;">mae</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.572</td>
</tr>
<tr class="odd">
<td style="text-align: left;">rsq</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.132</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>One nice thing about the <span class="pack" style="">forecast</span> package is that it can include additional features via the <code>xreg</code> argument, which is exactly what we need- additional information. Now our model looks something like this, where <img src="https://latex.codecogs.com/png.latex?X"> is our model matrix of features and <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> their corresponding regression weights.</p>
<p><img src="https://latex.codecogs.com/png.latex?y_t%20=%20X_t%5Cbeta%20+%20%5Calpha_1y_%7Bt-1%7D%20+%20%5Cdots%20+%5Calpha_%7Bp%7Dy_%7Bt-p%7D%20+%20(%5Cvarepsilon_t%20+%20%5Ctheta_1%20%5Cvarepsilon_%7Bt-1%7D%20+%20%5Ccdots%20+%5Ctheta_q%20%5Cvarepsilon_%7Bt-q%7D)"></p>
<p>Adding these is not exactly straightforward, since it requires a matrix rather than a data frame, but this is not too big a deal once you are used to creating model matrices.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1">mm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">model.matrix</span>(</span>
<span id="cb9-2">  <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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, </span>
<span id="cb9-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> red_line_train <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb9-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(is_weekend<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>is_sox_game, tmax_scaled, prcp_scaled, red_line_modernization)</span>
<span id="cb9-5">)</span>
<span id="cb9-6"></span>
<span id="cb9-7">model_arima_xreg <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> forecast<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">auto.arima</span>(</span>
<span id="cb9-8">  red_line_train<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>rides_scaled,</span>
<span id="cb9-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">max.p =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>,</span>
<span id="cb9-10">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">max.q =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>,</span>
<span id="cb9-11">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xreg  =</span> mm</span>
<span id="cb9-12">)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">term</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">estimate</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">std.error</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">ar1</td>
<td style="text-align: right;">-0.444</td>
<td style="text-align: right;">0.018</td>
</tr>
<tr class="even">
<td style="text-align: left;">ar2</td>
<td style="text-align: right;">-0.430</td>
<td style="text-align: right;">0.018</td>
</tr>
<tr class="odd">
<td style="text-align: left;">ar3</td>
<td style="text-align: right;">-0.370</td>
<td style="text-align: right;">0.019</td>
</tr>
<tr class="even">
<td style="text-align: left;">ar4</td>
<td style="text-align: right;">-0.325</td>
<td style="text-align: right;">0.019</td>
</tr>
<tr class="odd">
<td style="text-align: left;">ar5</td>
<td style="text-align: right;">-0.312</td>
<td style="text-align: right;">0.019</td>
</tr>
<tr class="even">
<td style="text-align: left;">ar6</td>
<td style="text-align: right;">-0.356</td>
<td style="text-align: right;">0.019</td>
</tr>
<tr class="odd">
<td style="text-align: left;">ar7</td>
<td style="text-align: right;">0.307</td>
<td style="text-align: right;">0.018</td>
</tr>
<tr class="even">
<td style="text-align: left;">ar8</td>
<td style="text-align: right;">-0.051</td>
<td style="text-align: right;">0.017</td>
</tr>
<tr class="odd">
<td style="text-align: left;">is_weekend</td>
<td style="text-align: right;">-1.154</td>
<td style="text-align: right;">0.023</td>
</tr>
<tr class="even">
<td style="text-align: left;">is_holiday</td>
<td style="text-align: right;">-1.045</td>
<td style="text-align: right;">0.021</td>
</tr>
<tr class="odd">
<td style="text-align: left;">is_cubs_game</td>
<td style="text-align: right;">0.208</td>
<td style="text-align: right;">0.015</td>
</tr>
<tr class="even">
<td style="text-align: left;">is_sox_game</td>
<td style="text-align: right;">0.072</td>
<td style="text-align: right;">0.015</td>
</tr>
<tr class="odd">
<td style="text-align: left;">tmax_scaled</td>
<td style="text-align: right;">0.085</td>
<td style="text-align: right;">0.011</td>
</tr>
<tr class="even">
<td style="text-align: left;">prcp_scaled</td>
<td style="text-align: right;">-0.031</td>
<td style="text-align: right;">0.004</td>
</tr>
<tr class="odd">
<td style="text-align: left;">red_line_modernization</td>
<td style="text-align: right;">-0.550</td>
<td style="text-align: right;">0.131</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>This is looking much better! We can also see how notably different the ARMA structure is relative to the previous model. We also see that adding weekend and holiday effects result in a huge drop in ridership as expected, while baseball games and good weather will lead to an increase.</p>
<p>In the following code, we create a model matrix similar to the training data that we can feed into the <span class="func" style="">predict</span> function. The forecast package also offers a <span class="func" style="">glance</span> method if desired.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1">nd <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> red_line_validate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb10-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(is_weekend<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>is_sox_game, tmax_scaled, prcp_scaled, red_line_modernization) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb10-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">model.matrix</span>( <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> . <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> .)</span>
<span id="cb10-4"></span>
<span id="cb10-5">preds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(model_arima_xreg, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newxreg =</span> nd, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n.ahead =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(red_line_validate))<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>pred</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1">p_arima_red <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> red_line_validate <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;">pred =</span> preds) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb11-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(date, rides_scaled)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_line</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;">y =</span> pred), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'red'</span>) <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;">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;">''</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Rides (scaled)'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ARIMA'</span>)</span>
<span id="cb11-7"></span>
<span id="cb11-8">p_arima_red</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-05-time-series/index_files/figure-html/unnamed-chunk-4-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>And here we can see performance is notably improved (restrict to first 30 obs for a direct comparison to the previous).</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">.metric</th>
<th style="text-align: left;" data-quarto-table-cell-role="th">.estimator</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">.estimate</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">rmse</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.371</td>
</tr>
<tr class="even">
<td style="text-align: left;">mae</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.282</td>
</tr>
<tr class="odd">
<td style="text-align: left;">rsq</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.747</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</section>
<section id="mixed-model-with-ar-structure" class="level2">
<h2 class="anchored" data-anchor-id="mixed-model-with-ar-structure">Mixed model with AR Structure</h2>
<section id="intro-2" class="level3">
<h3 class="anchored" data-anchor-id="intro-2">Intro</h3>
<p>More generally, we can think of that original AR error as a random effect, such that after the linear predictor is constructed, we add a random effect based on the correlation structure desired, in this case, autoregressive. In the mixed model setting, it is actually quite common to use an AR residual structure within a cluster or group, and here we can do so as well, as the data is naturally grouped by line.</p>
<p>To make this a bit more clear, we can state the AR effect more formally as follows for a single line at time <img src="https://latex.codecogs.com/png.latex?t">:</p>
<p><img src="https://latex.codecogs.com/png.latex?z_t%20%20%5Csim%20N(0,%20%5CSigma_%7Bar%7D)"> <img src="https://latex.codecogs.com/png.latex?%5CSigma_%7Bar%7D%20=%20cov(z(s),%20z(t))%20=%20%5Csigma%5E2%5Cexp(-%5Ctheta%7Ct-s%7C)"></p>
<p>Where t,s are different time points, e.g.&nbsp;within a line.</p>
<p>If we were to simulate it for 4 time points, with autocovariance value of .5, we could do so as follows<sup>3</sup>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">n_clusters   <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb12-2">n_timepoints <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb12-3">mu  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb12-4">var <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># not actually used if the value is 1</span></span>
<span id="cb12-5">S <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dist</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n_timepoints))</span>
<span id="cb12-6"></span>
<span id="cb12-7">S</span>
<span id="cb12-8"></span>
<span id="cb12-9">z <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> MASS<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mvrnorm</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mu =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(mu, n_timepoints), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Sigma =</span> S)</span>
<span id="cb12-10"></span>
<span id="cb12-11">z</span></code></pre></div></div>
</div>
<p>And here is our typical model with a single random effect, e.g.&nbsp;for line:</p>
<p><img src="https://latex.codecogs.com/png.latex?%20y_%7Btl%7D%20%5Csim%20X%5Cbeta%20+%20z%5E%7Bline%7D_%7Bl%7D%20+%20e_%7Btl%7D"> <img src="https://latex.codecogs.com/png.latex?%5Ctextrm%7Bz%7D_%7Bl%7D%20%5Csim%20N(0,%20%5Csigma_l%5E2)"> <img src="https://latex.codecogs.com/png.latex?%5Cepsilon%20%5Csim%20N(0,%20%5Csigma_e%5E2)"></p>
<p>The X may be at either line or observation level, and potentially the <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> could vary by line.</p>
<p>Putting it all together, we’re just adding the AR random effect to the standard mixed model for a single line.</p>
<p><img src="https://latex.codecogs.com/png.latex?%20y_%7Btl%7D%20%5Csim%20X%5Cbeta%20+%20z%5E%7Bar%7D_t%20+z%5E%7Bline%7D_%7Bl%7D%20+%20e_%7Btl%7D"></p>
</section>
<section id="data-prep" class="level3">
<h3 class="anchored" data-anchor-id="data-prep">Data Prep</h3>
<p>So let’s try this! First some minor data prep to add holidays.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1">df_train_mixed <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_train <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb13-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">date =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(date)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb13-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">left_join</span>(holidays, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'date'</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;">'ds'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'year'</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;">'year'</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb13-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">holiday =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ifelse</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(holiday), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'0'</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.character</span>(holiday))))</span>
<span id="cb13-5"></span>
<span id="cb13-6">df_validate_mixed <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_validate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb13-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">date =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(date)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb13-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">left_join</span>(holidays, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'date'</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;">'ds'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'year'</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;">'year'</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb13-9">  <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;">holiday =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ifelse</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(holiday), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'0'</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.character</span>(holiday))))</span></code></pre></div></div>
</div>
</section>
<section id="model-1" class="level3">
<h3 class="anchored" data-anchor-id="model-1">Model</h3>
<p>For the model, we can now easily think of it as we do other standard modeling scenarios. Along with standard features, we’ll add random effects for line, day, day x line interaction, etc. Finally we also add an AR random effect. For each line, we have an autoregressive structure for days, such that days right next to each other are correlated, and this correlation tapers off as days are further apart. This is not our only option, but seems straightforward to me.</p>
<p>Depending on what you include in the model, you may have convergence issues, so feel free to reduce the complexity if needed. For example, most of the day effect is captured by weekend vs.&nbsp;not, and a by line year trend wasn’t really necessary. In addition, the way the AR random effect variance is estimated as noted above, this essentially captures the line intercept variance.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1">model_mixed <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> </span>
<span id="cb14-2">  rides_scaled <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> </span>
<span id="cb14-3">  is_weekend <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb14-4">  is_cubs_game <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb14-5">  is_sox_game <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb14-6">  tmax_scaled <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb14-7">  prcp_scaled <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb14-8">  snow_scaled <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb14-9">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># year_day +</span></span>
<span id="cb14-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ar1</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> day<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>line) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>     <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the 0 + is a nuance of tmb's approach</span></span>
<span id="cb14-11">  (<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>holiday) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>           <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># as RE with all holidays instead of just holiday vs. not</span></span>
<span id="cb14-12">  (<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>year) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>     </span>
<span id="cb14-13">  (<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> red_line_modernization<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>line) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the project shifted ridership from red to other lines</span></span>
<span id="cb14-14">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># (1|day) #+ </span></span>
<span id="cb14-15">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># (1|line) +</span></span>
<span id="cb14-16">  (<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>day<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>line) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#+</span></span>
<span id="cb14-17">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># (1 + year_day|line)</span></span>
<span id="cb14-18"></span>
<span id="cb14-19"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(glmmTMB)</span>
<span id="cb14-20"></span>
<span id="cb14-21">fit_mixed <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glmmTMB</span>(model_mixed, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> df_train_mixed)</span></code></pre></div></div>
</div>
</section>
<section id="explore-1" class="level3">
<h3 class="anchored" data-anchor-id="explore-1">Explore</h3>
<p>The mixed model approach is nice because it is highly interpretable. We get both standard regression coefficients, and variance components to help us understand how the rest of the variance breaks down. For example, I would interpret the following that that line and weekend are the biggest contributors to the variability seen, and that we have high autocorrelation, as expected.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(mixedup)</span>
<span id="cb15-2"></span>
<span id="cb15-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise_model</span>(fit_mixed, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">digits =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb15-4"></span>
<span id="cb15-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">extract_cor_structure</span>(fit_mixed, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">which_cor =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ar1'</span>)</span></code></pre></div></div>
</div>
<p>We can visually inspect how well it matches the data. In the following the colored lines are the predictions, while the observed is gray. It looks like performance tapers for more recent time periods, and holiday effects are not as prevalent for some lines (e.g.&nbsp;yellow). The latter could be helped by adding a <code>holiday:line</code> random effect.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(glmmTMB)</span>
<span id="cb16-2"></span>
<span id="cb16-3">p_mixed <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_validate_mixed <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb16-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">droplevels</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb16-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pred =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(fit_mixed, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> ., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">allow.new.levels=</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb16-6">  <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;">date =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_date</span>(date)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb16-7">  <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>(date, rides_scaled)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_line</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;">y =</span> pred, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">I</span>(colors)), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">facet_grid</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rows =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(line), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scales =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'free_y'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb16-11">  <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;">''</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Rides (scaled)'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">subtitle =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Mixed'</span>)</span>
<span id="cb16-12"></span>
<span id="cb16-13">p_mixed</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-05-time-series/index_files/figure-html/mixed-vis-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>As before we can measure performance via yardstick. This model does appears to do very well.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb17-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># validation</span></span>
<span id="cb17-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb17-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pred =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(fit_mixed, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> df_validate_mixed, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">allow.new.levels =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>),</span>
<span id="cb17-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">observed =</span> df_validate_mixed<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>rides_scaled</span>
<span id="cb17-5">) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb17-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">metric_score</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">truth =</span> observed, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">estimate =</span> pred)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">.metric</th>
<th style="text-align: left;" data-quarto-table-cell-role="th">.estimator</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">.estimate</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">rmse</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.189</td>
</tr>
<tr class="even">
<td style="text-align: left;">mae</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.110</td>
</tr>
<tr class="odd">
<td style="text-align: left;">rsq</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.965</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>For more on autocorrelation structure in the mixed model setting, <a href="https://m-clark.github.io/mixed-models-with-R/extensions.html#autocorrelation">see my mixed model document here</a><sup>4</sup>.</p>
</section>
</section>
<section id="generalized-additive-models" class="level2">
<h2 class="anchored" data-anchor-id="generalized-additive-models">Generalized Additive Models</h2>
<section id="intro-3" class="level3">
<h3 class="anchored" data-anchor-id="intro-3">Intro</h3>
<p>We can generalize mixed models even further to incorporate nonlinear components, which may include cyclic or other effects. Such models are typically referred to as <a href="https://m-clark.github.io/generalized-additive-models/">generalized additive models</a> (GAMs). AR processes themselves can be seen as a special case of <a href="http://www.gaussianprocess.org/">gaussian processes</a>, which can potentially be approximated via GAMs. As GAMs can accommodate spatial, temporal, nonlinear, and other effects, they are sometimes more generally referred to as <em>structured additive regression models</em>, or STARs.</p>
</section>
<section id="data-prep-1" class="level3">
<h3 class="anchored" data-anchor-id="data-prep-1">Data Prep</h3>
<p>The data prep for the GAM is the same as with the mixed model, so we’ll just use that data.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">df_train_gam <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_train_mixed</span>
<span id="cb18-2"></span>
<span id="cb18-3">df_validate_gam <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_validate_mixed</span></code></pre></div></div>
</div>
</section>
<section id="model-2" class="level3">
<h3 class="anchored" data-anchor-id="model-2">Model</h3>
<p>With data in place we are ready to conduct the model. We have numerous options for how we’d like to take this. However, as an example, I tried various smooths, but didn’t really see much difference, which is actually a good thing. For any further improvements we’d likely have to tweak the core model itself. I also use <span class="func" style="">bam</span> for a quicker result, but this isn’t really necessary, as it didn’t even take a minute to run with standard gam. As with the mixed model, we will use holiday as a random effect, but we add the holiday by line interaction since we saw that need. In addition, our year-day by line interaction should help some with the tailing off of more recent predictions.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">library</span>(mgcv)</span>
<span id="cb19-2"></span>
<span id="cb19-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># for year, use year (numeric) or use year_fac, but for latter, it will not be</span></span>
<span id="cb19-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># able to predict any year not in the training data unless you use</span></span>
<span id="cb19-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># drop.unused.levels.</span></span>
<span id="cb19-6">model_gam <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> </span>
<span id="cb19-7">  rides_scaled <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> </span>
<span id="cb19-8">  is_weekend <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb19-9">  is_cubs_game <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb19-10">  is_sox_game <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb19-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(tmax_scaled) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb19-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(prcp_scaled) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb19-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(snow_scaled) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb19-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(red_line_modernization, line, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'re'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb19-15">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(holiday,  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'re'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb19-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(holiday, line,  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'re'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb19-17">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(year_fac, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'re'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>      </span>
<span id="cb19-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(day,  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'re'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb19-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(line, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'re'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb19-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(line, day, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'re'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> </span>
<span id="cb19-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(year_day, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> line, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bs =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ds'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'fs'</span>))</span>
<span id="cb19-22"></span>
<span id="cb19-23"></span>
<span id="cb19-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># will take a while!</span></span>
<span id="cb19-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fit_gam = gam(</span></span>
<span id="cb19-26"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   model_gam, </span></span>
<span id="cb19-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   data     = df_train_gam,</span></span>
<span id="cb19-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   drop.unused.levels = FALSE, </span></span>
<span id="cb19-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   method   = "REML"</span></span>
<span id="cb19-30"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># )</span></span>
<span id="cb19-31"></span>
<span id="cb19-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fast even without parallel</span></span>
<span id="cb19-33">fit_gam <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bam</span>(</span>
<span id="cb19-34">  model_gam, </span>
<span id="cb19-35">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data     =</span> df_train_gam,</span>
<span id="cb19-36">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">drop.unused.levels =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>, </span>
<span id="cb19-37">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method   =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fREML"</span>,</span>
<span id="cb19-38">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">discrete =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>     <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># will fit the model in a second rather than a couple seconds</span></span>
<span id="cb19-39">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># nthreads = 8,     # this option assumes a cluster is available. not necessary for this.</span></span>
<span id="cb19-40">)</span></code></pre></div></div>
</div>
</section>
<section id="explore-2" class="level3">
<h3 class="anchored" data-anchor-id="explore-2">Explore</h3>
<p>As with <span class="pack" style="">glmmTMB</span>, I use a custom function to summarize the model, or extract different components from it. From the initial glance we can see things that we expect (e.g.&nbsp;line and weekend effects are large).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">mixedup<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise_model</span>(fit_gam)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>
Variance Components:</code></pre>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>                       Group                 Effect Variance   SD SD_2.5
                 tmax_scaled              Intercept     0.01 0.09   0.04
                 prcp_scaled              Intercept     0.00 0.01   0.00
                 snow_scaled              Intercept     0.00 0.01   0.00
                        line red_line_modernization     0.09 0.31   0.19
                     holiday              Intercept     0.05 0.22   0.14
                     holiday                   line     0.04 0.21   0.18
                    year_fac              Intercept     0.00 0.06   0.04
                         day              Intercept     0.00 0.00   0.00
                        line              Intercept     0.49 0.70   0.42
                        line                    day     0.05 0.22   0.18
           year_day:lineblue              Intercept     0.00 0.00   0.00
          year_day:linebrown              Intercept     0.00 0.00   0.00
          year_day:linegreen              Intercept     0.00 0.00   0.00
         year_day:lineorange              Intercept     0.00 0.00   0.00
           year_day:linepink              Intercept     0.00 0.00   0.00
         year_day:linepurple              Intercept     0.00 0.00   0.00
 year_day:linepurple_express              Intercept     0.00 0.00   0.00
            year_day:linered              Intercept     0.00 0.00   0.00
         year_day:lineyellow              Intercept     0.00 0.00   0.00
                    Residual                     NA     0.02 0.13   0.13
      SD_97.5 Var_prop
 2.100000e-01     0.01
 2.000000e-02     0.00
 2.000000e-02     0.00
 4.900000e-01     0.13
 3.300000e-01     0.06
 2.400000e-01     0.06
 1.000000e-01     0.01
 4.162009e+69     0.00
 1.150000e+00     0.65
 2.700000e-01     0.06
 0.000000e+00     0.00
 0.000000e+00     0.00
 0.000000e+00     0.00
 0.000000e+00     0.00
 0.000000e+00     0.00
 0.000000e+00     0.00
 0.000000e+00     0.00
 0.000000e+00     0.00
 0.000000e+00     0.00
 1.300000e-01     0.02</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>
Fixed Effects:</code></pre>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>         Term Value   SE     t P_value Lower_2.5 Upper_97.5
    Intercept -0.28 0.24 -1.14    0.25     -0.76       0.20
   is_weekend -0.54 0.06 -8.27    0.00     -0.66      -0.41
 is_cubs_game  0.04 0.00 13.81    0.00      0.03       0.04
  is_sox_game  0.01 0.00  3.81    0.00      0.00       0.02</code></pre>
</div>
</div>
<p>Now we can visualize test predictions broken about by line. The greater flexibility of the GAM for fixed and other effects allows it to follow the trends more easily than the standard linear mixed model approach.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-05-time-series/index_files/figure-html/gam-vis-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>We can also see improvement over our standard mixed model approach, and our best performance yet.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">.metric</th>
<th style="text-align: left;" data-quarto-table-cell-role="th">.estimator</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">.estimate</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">rmse</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.140</td>
</tr>
<tr class="even">
<td style="text-align: left;">mae</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.087</td>
</tr>
<tr class="odd">
<td style="text-align: left;">rsq</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.981</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</section>
<section id="prophet" class="level2">
<h2 class="anchored" data-anchor-id="prophet">Prophet</h2>
<section id="intro-4" class="level3">
<h3 class="anchored" data-anchor-id="intro-4">Intro</h3>
<p><em>Prophet</em> is an approach from Facebook that uses Stan to estimate a time series model taking various trends, seasonality, and other factors under consideration. By default, it only uses Stan for optimization (e.g.&nbsp;via ‘BFGS’), but you can switch to fully Bayesian if desired, and take advantage of all that the Bayesian approach has to offer.</p>
</section>
<section id="data-prep-2" class="level3">
<h3 class="anchored" data-anchor-id="data-prep-2">Data Prep</h3>
<p>The <span class="pack" style="">prophet</span> package in R takes some getting used to. We have to have specific names for our variables, and unfortunately have to do extra work to incorporate categorical features. We can use <span class="pack" style="">recipes</span> (like <span class="pack" style="">yardstick</span>, part of the <span class="pack" style="">tidymodels</span> ’verse) to set up the data (e.g.&nbsp;one-hot encoding).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">library</span>(prophet)</span>
<span id="cb25-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(recipes)</span>
<span id="cb25-3"></span>
<span id="cb25-4">df_train_prophet <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_train <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb25-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(date, line) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb25-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y  =</span> rides_scaled,</span>
<span id="cb25-7">         <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ds =</span> date)</span>
<span id="cb25-8"></span>
<span id="cb25-9">rec <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> recipes<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">recipe</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>., df_train_prophet)</span>
<span id="cb25-10"></span>
<span id="cb25-11">df_train_prophet <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> rec <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb25-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_dummy</span>(line, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">one_hot =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">keep_original_cols =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb25-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prep</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">training =</span> df_train_prophet) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb25-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bake</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">new_data =</span> df_train_prophet) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb25-15">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename_with</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'line_'</span>), str_remove, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'line_'</span>)</span>
<span id="cb25-16"></span>
<span id="cb25-17">df_validate_prophet <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_validate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb25-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(date, line)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb25-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ds =</span> date, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> rides_scaled)</span>
<span id="cb25-20"></span>
<span id="cb25-21">rec <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">recipe</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>., df_validate_prophet)</span>
<span id="cb25-22"></span>
<span id="cb25-23">df_validate_prophet <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> rec <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb25-24">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step_dummy</span>(line, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">one_hot =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">keep_original_cols =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb25-25">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prep</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">training =</span> df_train_prophet) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb25-26">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bake</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">new_data =</span> df_validate_prophet) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb25-27">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename_with</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.cols =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">starts_with</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'line_'</span>), str_remove, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'line_'</span>)</span></code></pre></div></div>
</div>
</section>
<section id="model-3" class="level3">
<h3 class="anchored" data-anchor-id="model-3">Model</h3>
<p>With data in place, we are ready to build the model. Note that later we will compare results to <span class="pack" style="">fable.prophet</span>, which will mask some of the functions here, or vice versa depending on which you load first. I would suggest only doing the prophet model, or only doing the fable model, rather than trying to do both at the same time, to avoid any mix-up.</p>
<p>After setting up the model, you have to add additional features in separate steps. Prophet has a nice way to incorporate holidays though. When you run this model, you may have to wait for a minute or so.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># use prophet::prophet in case you have fable.prophet loaded also</span></span>
<span id="cb26-2">model_prophet <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> prophet<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prophet</span>(</span>
<span id="cb26-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">holidays =</span> generated_holidays <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;">filter</span>(country <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;">'US'</span>),</span>
<span id="cb26-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">yearly.seasonality =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb26-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seasonality.mode =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"multiplicative"</span>,</span>
<span id="cb26-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">changepoint.prior.scale =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span></span>
<span id="cb26-7">)</span>
<span id="cb26-8"></span>
<span id="cb26-9">line_names <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb26-10">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'blue'</span>,</span>
<span id="cb26-11">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'brown'</span>,</span>
<span id="cb26-12">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'green'</span>,</span>
<span id="cb26-13">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'orange'</span>,</span>
<span id="cb26-14">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pink'</span>,</span>
<span id="cb26-15">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'purple'</span>,</span>
<span id="cb26-16">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'purple_express'</span>,</span>
<span id="cb26-17">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'red'</span>,</span>
<span id="cb26-18">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'yellow'</span></span>
<span id="cb26-19">)</span>
<span id="cb26-20"></span>
<span id="cb26-21">predictors <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb26-22">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'is_weekend'</span>,</span>
<span id="cb26-23">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'is_cubs_game'</span>,</span>
<span id="cb26-24">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'is_sox_game'</span>,</span>
<span id="cb26-25">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 'is_holiday',</span></span>
<span id="cb26-26">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tmax_scaled'</span>,</span>
<span id="cb26-27">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'prcp_scaled'</span>,</span>
<span id="cb26-28">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'snow_scaled'</span>,</span>
<span id="cb26-29">  line_names</span>
<span id="cb26-30">)</span>
<span id="cb26-31"></span>
<span id="cb26-32"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (i <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> predictors) {</span>
<span id="cb26-33">  model_prophet <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add_regressor</span>(model_prophet, i, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">standardize =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mode =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'additive'</span>)</span>
<span id="cb26-34">}</span>
<span id="cb26-35"></span>
<span id="cb26-36">model_prophet <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add_country_holidays</span>(model_prophet, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">country_name =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'US'</span>)</span>
<span id="cb26-37"></span>
<span id="cb26-38">fit_prophet <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fit.prophet</span>(model_prophet, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">df =</span> df_train_prophet)</span>
<span id="cb26-39"></span>
<span id="cb26-40">forecast <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(fit_prophet, df_validate_prophet)</span></code></pre></div></div>
</div>
</section>
<section id="explore-3" class="level3">
<h3 class="anchored" data-anchor-id="explore-3">Explore</h3>
<p>We now visualize predictions as we did with the GAM. But one of the nice things with <span class="pack" style="">prophet</span> is that you can plot the various parts of the model results via the <span class="func" style="">plot</span> method or <span class="func" style="">prophet_plot_components</span> (not shown). Unfortunately, our baseline effort seems to undersmooth our more popular lines (blue, red), and overreacts to some of the others (purple, yellow). This is because it’s not really changing the predictions according to line.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-05-time-series/index_files/figure-html/prophet-vis-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>We can also assess performance as before, but note that <span class="pack" style="">prophet</span> has it’s own cross-validation capabilities which would be better to utilize if this was your primary tool. Between the previous visualization and these metrics, our first stab doesn’t appear to do as well as the GAM, so you might like to go back and tweak things.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">.metric</th>
<th style="text-align: left;" data-quarto-table-cell-role="th">.estimator</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">.estimate</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">rmse</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.280</td>
</tr>
<tr class="even">
<td style="text-align: left;">mae</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.198</td>
</tr>
<tr class="odd">
<td style="text-align: left;">rsq</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.925</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</section>
<section id="fable" class="level2">
<h2 class="anchored" data-anchor-id="fable">Fable</h2>
<section id="intro-5" class="level3">
<h3 class="anchored" data-anchor-id="intro-5">Intro</h3>
<p>I came across <span class="pack" style="">fable.prophet</span> as a possibly easier way to engage prophet. It is an extension of <span class="pack" style="">fable</span> and related packages, which are very useful for time series processing and analysis. Note that it is 0.1.0 version development, and hasn’t had much done with it in the past year, so your mileage may vary with regard to utility by the time you read this<sup>5</sup>. But with it we can specify the model in more of an R fashion, and we now don’t have as much data pre-processing.</p>
</section>
<section id="data-prep-3" class="level3">
<h3 class="anchored" data-anchor-id="data-prep-3">Data Prep</h3>
<p>One key difference using <span class="pack" style="">fable.prophet</span> is that it works with <code>tsibble</code> objects, and thus must have unique date observations. We can do this by setting <code>line</code> as the key<sup>6</sup>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb27-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(fable.prophet)</span>
<span id="cb27-2"></span>
<span id="cb27-3">df_train_fable <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_train_prophet <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb27-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tsibble</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">index =</span> ds, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">key =</span> line)</span>
<span id="cb27-5"></span>
<span id="cb27-6">df_validate_fable <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_validate_prophet <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb27-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tsibble</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">index =</span> ds, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">key =</span> line)</span>
<span id="cb27-8"></span>
<span id="cb27-9">holidays_fable <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> holidays <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb27-10">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(country <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;">'US'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb27-11">  <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;">ds =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_date</span>(ds)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb27-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tsibble</span>()</span></code></pre></div></div>
</div>
</section>
<section id="model-4" class="level3">
<h3 class="anchored" data-anchor-id="model-4">Model</h3>
<p>Beyond this we use functions within our formula to set the various components. With line as the key, <span class="pack" style="">fable</span> is actually running separate prophet models for each line, and we can do so in parallel if desired.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">model_prophet <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> fable.prophet<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prophet</span>(</span>
<span id="cb28-2">  y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> </span>
<span id="cb28-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">growth</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'linear'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">changepoint_prior_scale =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb28-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">season</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"week"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"multiplicative"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb28-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">holiday</span>(holidays_fable) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb28-6">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xreg</span>(</span>
<span id="cb28-7">      is_weekend,</span>
<span id="cb28-8">      is_cubs_game,</span>
<span id="cb28-9">      is_sox_game,</span>
<span id="cb28-10">      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># is_holiday,</span></span>
<span id="cb28-11">      tmax_scaled,</span>
<span id="cb28-12">      prcp_scaled,</span>
<span id="cb28-13">      snow_scaled</span>
<span id="cb28-14">    ) </span>
<span id="cb28-15">)</span>
<span id="cb28-16"></span>
<span id="cb28-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># library(future)</span></span>
<span id="cb28-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># plan(multisession)</span></span>
<span id="cb28-19"></span>
<span id="cb28-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># furrr is used under the hood, and though it wants a seed, it doesn't</span></span>
<span id="cb28-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># automatically use one so will give warnings. I don't think it can be passed</span></span>
<span id="cb28-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># via the model function, so expect to see ignorable warnings (suppressed here).</span></span>
<span id="cb28-23"></span>
<span id="cb28-24">fit_fable <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">model</span>(df_train_fable, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mdl =</span> model_prophet)</span>
<span id="cb28-25"></span>
<span id="cb28-26">forecast_fable <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> fit_fable <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb28-27">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">forecast</span>(df_validate_fable) </span>
<span id="cb28-28"></span>
<span id="cb28-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># plan(sequential)</span></span></code></pre></div></div>
</div>
</section>
<section id="explore-4" class="level3">
<h3 class="anchored" data-anchor-id="explore-4">Explore</h3>
<p>With <span class="pack" style="">fable.prophet</span> visualization, we have the more automatic plots, but again we’ll stick with the basic validation plot we’ve been doing.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb29" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb29-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">components</span>(fit_fable)</span>
<span id="cb29-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">components</span>(fit_fable) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb29-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">autoplot</span>()</span>
<span id="cb29-4">forecast_fable <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb29-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">autoplot</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">level =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#ff5500'</span>)</span></code></pre></div></div>
</div>
<p>This model does well, and better than basic <span class="pack" style="">prophet</span>, but we can see its limitations, for example, with the yellow line, and more recent ridership in general.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-05-time-series/index_files/figure-html/fable-model-explore-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>And we check performance as before. The <span class="pack" style="">fable</span> model is doing almost as well as our GAM approach did.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">.metric</th>
<th style="text-align: left;" data-quarto-table-cell-role="th">.estimator</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">.estimate</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">rmse</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.154</td>
</tr>
<tr class="even">
<td style="text-align: left;">mae</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.092</td>
</tr>
<tr class="odd">
<td style="text-align: left;">rsq</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.979</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>One nice thing about the <span class="pack" style="">fable</span> approach is its internal performance metrics, which are easily obtained. It will give us results for each line<sup>7</sup>, validation data results shown. We see that we have more error for the popular lines as before, but in terms of percentage error, the other lines are showing more difficulty. You can find out more about the additional metrics available <a href="https://otexts.com/fpp3/accuracy.html">here</a>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">accuracy</span>(fit_fable)</span>
<span id="cb30-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">accuracy</span>(forecast_fable, df_validate_fable)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">.model</th>
<th style="text-align: left;" data-quarto-table-cell-role="th">line</th>
<th style="text-align: left;" data-quarto-table-cell-role="th">.type</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">ME</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">RMSE</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">MAE</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">MPE</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">MAPE</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">ACF1</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">mdl</td>
<td style="text-align: left;">blue</td>
<td style="text-align: left;">Test</td>
<td style="text-align: right;">0.083</td>
<td style="text-align: right;">0.251</td>
<td style="text-align: right;">0.180</td>
<td style="text-align: right;">-27.007</td>
<td style="text-align: right;">62.199</td>
<td style="text-align: right;">0.641</td>
</tr>
<tr class="even">
<td style="text-align: left;">mdl</td>
<td style="text-align: left;">brown</td>
<td style="text-align: left;">Test</td>
<td style="text-align: right;">0.001</td>
<td style="text-align: right;">0.126</td>
<td style="text-align: right;">0.084</td>
<td style="text-align: right;">-31.034</td>
<td style="text-align: right;">88.711</td>
<td style="text-align: right;">0.621</td>
</tr>
<tr class="odd">
<td style="text-align: left;">mdl</td>
<td style="text-align: left;">green</td>
<td style="text-align: left;">Test</td>
<td style="text-align: right;">0.088</td>
<td style="text-align: right;">0.118</td>
<td style="text-align: right;">0.100</td>
<td style="text-align: right;">-105.627</td>
<td style="text-align: right;">112.000</td>
<td style="text-align: right;">0.660</td>
</tr>
<tr class="even">
<td style="text-align: left;">mdl</td>
<td style="text-align: left;">orange</td>
<td style="text-align: left;">Test</td>
<td style="text-align: right;">0.035</td>
<td style="text-align: right;">0.084</td>
<td style="text-align: right;">0.063</td>
<td style="text-align: right;">-43.228</td>
<td style="text-align: right;">60.244</td>
<td style="text-align: right;">0.638</td>
</tr>
<tr class="odd">
<td style="text-align: left;">mdl</td>
<td style="text-align: left;">pink</td>
<td style="text-align: left;">Test</td>
<td style="text-align: right;">0.058</td>
<td style="text-align: right;">0.089</td>
<td style="text-align: right;">0.072</td>
<td style="text-align: right;">-18.386</td>
<td style="text-align: right;">20.452</td>
<td style="text-align: right;">0.675</td>
</tr>
<tr class="even">
<td style="text-align: left;">mdl</td>
<td style="text-align: left;">purple</td>
<td style="text-align: left;">Test</td>
<td style="text-align: right;">0.006</td>
<td style="text-align: right;">0.012</td>
<td style="text-align: right;">0.009</td>
<td style="text-align: right;">-0.633</td>
<td style="text-align: right;">0.982</td>
<td style="text-align: right;">0.503</td>
</tr>
<tr class="odd">
<td style="text-align: left;">mdl</td>
<td style="text-align: left;">purple_express</td>
<td style="text-align: left;">Test</td>
<td style="text-align: right;">0.049</td>
<td style="text-align: right;">0.107</td>
<td style="text-align: right;">0.083</td>
<td style="text-align: right;">-41.459</td>
<td style="text-align: right;">218.861</td>
<td style="text-align: right;">0.752</td>
</tr>
<tr class="even">
<td style="text-align: left;">mdl</td>
<td style="text-align: left;">red</td>
<td style="text-align: left;">Test</td>
<td style="text-align: right;">0.045</td>
<td style="text-align: right;">0.297</td>
<td style="text-align: right;">0.211</td>
<td style="text-align: right;">-3.003</td>
<td style="text-align: right;">14.880</td>
<td style="text-align: right;">0.598</td>
</tr>
<tr class="odd">
<td style="text-align: left;">mdl</td>
<td style="text-align: left;">yellow</td>
<td style="text-align: left;">Test</td>
<td style="text-align: right;">-0.027</td>
<td style="text-align: right;">0.030</td>
<td style="text-align: right;">0.027</td>
<td style="text-align: right;">2.892</td>
<td style="text-align: right;">2.912</td>
<td style="text-align: right;">0.726</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>The <span class="pack" style="">fable</span> results suggests what we already knew from our GAM and mixed model approach, that interactions of the series with line are important. We weren’t easily able to do this with the default <span class="pack" style="">prophet</span> (it would likely require adding time x line interaction regresssors), so it’s nice that we have the option here.</p>
</section>
</section>
<section id="gbm" class="level2">
<h2 class="anchored" data-anchor-id="gbm">GBM</h2>
<section id="intro-6" class="level3">
<h3 class="anchored" data-anchor-id="intro-6">Intro</h3>
<p>This part is actually new from when I first wrote up this post over a year ago. I basically wanted to test if a boosting approach would work decently out of the box without doing anything special regarding the structure of the data. I don’t add it to the summary visualizations, but provide the standard results here.</p>
</section>
<section id="data-prep-4" class="level3">
<h3 class="anchored" data-anchor-id="data-prep-4">Data Prep</h3>
<p>I’ll use <span class="pack" style="">lightgbm</span> which I’ve been increasingly using of late. It requires a matrix object for input, and so some additional processing as well.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb31" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb31-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(lightgbm)</span>
<span id="cb31-2"></span>
<span id="cb31-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># lightgbm only accepts a matrix input</span></span>
<span id="cb31-4">df_train_lgb_init <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_train <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb31-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(</span>
<span id="cb31-6">    rides_scaled,</span>
<span id="cb31-7">    is_weekday,</span>
<span id="cb31-8">    is_holiday,</span>
<span id="cb31-9">    is_cubs_game,</span>
<span id="cb31-10">    is_sox_game,</span>
<span id="cb31-11">    tmax_scaled,</span>
<span id="cb31-12">    prcp_scaled,</span>
<span id="cb31-13">    line, </span>
<span id="cb31-14">    red_line_modernization,</span>
<span id="cb31-15">    year,</span>
<span id="cb31-16">    month,</span>
<span id="cb31-17">    year_day</span>
<span id="cb31-18">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb31-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb31-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">line =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.integer</span>(line),</span>
<span id="cb31-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">month =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.integer</span>(month)</span>
<span id="cb31-22">  )</span>
<span id="cb31-23"></span>
<span id="cb31-24">X_train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.matrix</span>(df_train_lgb_init <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;">select</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>rides_scaled))</span>
<span id="cb31-25"></span>
<span id="cb31-26">X_test  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_validate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb31-27">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(</span>
<span id="cb31-28">    is_weekday,</span>
<span id="cb31-29">    is_holiday,</span>
<span id="cb31-30">    is_cubs_game,</span>
<span id="cb31-31">    is_sox_game,</span>
<span id="cb31-32">    tmax_scaled,</span>
<span id="cb31-33">    prcp_scaled,</span>
<span id="cb31-34">    line, </span>
<span id="cb31-35">    red_line_modernization,</span>
<span id="cb31-36">    year,</span>
<span id="cb31-37">    month,</span>
<span id="cb31-38">    year_day</span>
<span id="cb31-39">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb31-40">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb31-41">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">line =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.integer</span>(line),</span>
<span id="cb31-42">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">month =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.integer</span>(month)</span>
<span id="cb31-43">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb31-44">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.matrix</span>()</span>
<span id="cb31-45"></span>
<span id="cb31-46"></span>
<span id="cb31-47">df_train_lgb <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lgb.Dataset</span>(</span>
<span id="cb31-48">  X_train,</span>
<span id="cb31-49">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> df_train_lgb_init<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>rides_scaled,</span>
<span id="cb31-50">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">categorical_feature =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb31-51">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'is_weekday'</span>,</span>
<span id="cb31-52">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'is_holiday'</span>,</span>
<span id="cb31-53">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'is_cubs_game'</span>,</span>
<span id="cb31-54">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'is_sox_game'</span>,</span>
<span id="cb31-55">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'line'</span>,</span>
<span id="cb31-56">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'year'</span>,</span>
<span id="cb31-57">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'month'</span></span>
<span id="cb31-58">  )</span>
<span id="cb31-59">)</span>
<span id="cb31-60"></span>
<span id="cb31-61">df_test_lgb  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lgb.Dataset.create.valid</span>(</span>
<span id="cb31-62">  df_train_lgb, </span>
<span id="cb31-63">  X_test,</span>
<span id="cb31-64">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">label =</span> df_validate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>rides_scaled</span>
<span id="cb31-65">)</span></code></pre></div></div>
</div>
</section>
<section id="model-5" class="level3">
<h3 class="anchored" data-anchor-id="model-5">Model</h3>
<p>Typically we would perform some sort of search over the (many) parameters available to tweak with <span class="pack">lightgbm</span>, like the number of trees, learning rate, regularizer parameters and more. I ignore that, but I did fiddle with the learning rate and bumped up the <code>nrounds</code> (trees), but that’s it.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">params <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb32-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">objective       =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"regression"</span></span>
<span id="cb32-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;">"l2"</span></span>
<span id="cb32-4">  , <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">min_data      =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>L</span>
<span id="cb32-5">  , <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">learning_rate =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">01</span></span>
<span id="cb32-6">)</span>
<span id="cb32-7"></span>
<span id="cb32-8">fit_gbm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lgb.train</span>(</span>
<span id="cb32-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">params    =</span> params</span>
<span id="cb32-10">  , <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data    =</span> df_train_lgb</span>
<span id="cb32-11">  , <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nrounds =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>L</span>
<span id="cb32-12">)</span></code></pre></div></div>
</div>
</section>
<section id="explore-5" class="level3">
<h3 class="anchored" data-anchor-id="explore-5">Explore</h3>
<p>Some may be surprised at how well this does, but regular users of boosting probably are not. We didn’t have to do much and it’s already the best performing model.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-05-time-series/index_files/figure-html/gbm-vis-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">.metric</th>
<th style="text-align: left;" data-quarto-table-cell-role="th">.estimator</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">.estimate</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">rmse</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.130</td>
</tr>
<tr class="even">
<td style="text-align: left;">mae</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.076</td>
</tr>
<tr class="odd">
<td style="text-align: left;">rsq</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.984</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</section>
<section id="torch" class="level2">
<h2 class="anchored" data-anchor-id="torch">Torch</h2>
<p>At this point we have a collection of models that are still relatively interpretable, and mostly within our standard regression model framework. It’s good to see them able to perform very well without too much complexity. However, we still have other methods available that would be more computationally demanding, are more opaque in operations, but which would potentially provide the most accurate forecasts. For this we turn to using PyTorch, which is now available via the <span class="pack" style="">torch</span> package in R<sup>8</sup>.</p>
<p>In using <span class="pack" style="">torch</span>, we’re going to follow the <a href="https://blogs.rstudio.com/ai/posts/2021-03-19-forecasting-time-series-with-torch_4/">demo series at the RStudio AI blog</a> <sup>9</sup>. It shows in four parts how to use a <em>recurrent neural network</em>. In their example, they use a data set for a single series with (summarized) daily values, similar to our daily counts here. We will use the final model demonstrated in the series, a soi disant <em>seq2seq</em> model that includes an <em>attention</em> mechanism. More detail can be found <a href="https://www.deeplearningbook.org/contents/rnn.html">here</a>. The conceptual gist of the model can be described as taking a set of time points to predict another set of future time points, and doing so for all points in the series.</p>
<p>To be clear, they only use a single series, no other information (e.g.&nbsp;additional regressors). So we will do the same, coming full circle to what we started out with, just looking at daily ridership- a single time series for the red line.</p>
<section id="data" class="level3">
<h3 class="anchored" data-anchor-id="data">Data</h3>
<p>As usual we’ll need some data prep, both for initial training-test split creation, but also specifically for usage with Torch.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb33" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb33-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tsibble)</span>
<span id="cb33-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(lubridate)</span>
<span id="cb33-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(torch)</span>
<span id="cb33-4"></span>
<span id="cb33-5"></span>
<span id="cb33-6">df_train_torch <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_train <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb33-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(line <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;">'red'</span>, year <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2017</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb33-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pull</span>(rides_scaled) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb33-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.matrix</span>()</span>
<span id="cb33-10"></span>
<span id="cb33-11">df_validate_torch <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_validate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb33-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(line <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;">'red'</span>, year <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2017</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb33-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pull</span>(rides_scaled) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb33-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.matrix</span>()</span>
<span id="cb33-15"></span>
<span id="cb33-16">df_test_torch <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_validate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb33-17">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(line <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;">'red'</span>, date <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'2017-12-24'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb33-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pull</span>(rides_scaled) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb33-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.matrix</span>()</span>
<span id="cb33-20"></span>
<span id="cb33-21">train_mean <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(df_train_torch)</span>
<span id="cb33-22">train_sd   <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sd</span>(df_train_torch)</span></code></pre></div></div>
</div>
</section>
<section id="torch-data" class="level3">
<h3 class="anchored" data-anchor-id="torch-data">Torch data</h3>
<p>For our data, we will use a week behind lag to predict the following week. This seems appropriate for this problem, but for any particular time series problem we’d want to probably think hard about this and/or test different settings.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">n_timesteps <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># we use a week instead of 14 days in original blog</span></span>
<span id="cb34-2">n_forecast  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># look ahead one week</span></span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb35" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb35-1">cta_dataset <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;">dataset</span>(</span>
<span id="cb35-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cta_dataset"</span>,</span>
<span id="cb35-3"></span>
<span id="cb35-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">initialize =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x, n_timesteps, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sample_frac =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) {</span>
<span id="cb35-5"></span>
<span id="cb35-6">    self<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>n_timesteps <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> n_timesteps</span>
<span id="cb35-7">    self<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x <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;">torch_tensor</span>((x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> train_mean) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> train_sd)</span>
<span id="cb35-8"></span>
<span id="cb35-9">    n <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;">length</span>(self<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> self<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>n_timesteps <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb35-10"></span>
<span id="cb35-11">    self<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>starts <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;">sort</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample.int</span>(</span>
<span id="cb35-12">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> n,</span>
<span id="cb35-13">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> sample_frac</span>
<span id="cb35-14">    ))</span>
<span id="cb35-15"></span>
<span id="cb35-16">  },</span>
<span id="cb35-17"></span>
<span id="cb35-18">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.getitem =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(i) {</span>
<span id="cb35-19"></span>
<span id="cb35-20">    start <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> self<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>starts[i]</span>
<span id="cb35-21">    end <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> start <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> self<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>n_timesteps <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb35-22">    lag <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb35-23"></span>
<span id="cb35-24">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb35-25">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> self<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x[start<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>end],</span>
<span id="cb35-26">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> self<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x[(start<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>lag)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>(end<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>lag)]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">squeeze</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb35-27">    )</span>
<span id="cb35-28"></span>
<span id="cb35-29">  },</span>
<span id="cb35-30"></span>
<span id="cb35-31">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.length =</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>() {</span>
<span id="cb35-32">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(self<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>starts)</span>
<span id="cb35-33">  }</span>
<span id="cb35-34">)</span>
<span id="cb35-35"></span>
<span id="cb35-36">batch_size <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">32</span></span>
<span id="cb35-37"></span>
<span id="cb35-38">train_ds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cta_dataset</span>(df_train_torch, n_timesteps)</span>
<span id="cb35-39">train_dl <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dataloader</span>(train_ds, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">batch_size =</span> batch_size, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">shuffle =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb35-40"></span>
<span id="cb35-41">valid_ds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cta_dataset</span>(df_validate_torch, n_timesteps)</span>
<span id="cb35-42">valid_dl <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dataloader</span>(valid_ds, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">batch_size =</span> batch_size)</span>
<span id="cb35-43"></span>
<span id="cb35-44">test_ds  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cta_dataset</span>(df_test_torch, n_timesteps)</span>
<span id="cb35-45">test_dl  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dataloader</span>(test_ds, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">batch_size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span></code></pre></div></div>
</div>
</section>
<section id="model-6" class="level3">
<h3 class="anchored" data-anchor-id="model-6">Model</h3>
<p>I leave it to the <a href="https://blogs.rstudio.com/ai/posts/2021-03-19-forecasting-time-series-with-torch_4/#attention-module">blog</a> for details, but briefly, there are four components to the model:</p>
<ul>
<li><strong>Encoder</strong>: takes input, and produces outputs and states via RNN</li>
<li><strong>Decoder</strong>: takes the last predicted value as input and current context to make a new prediction</li>
<li><strong>Seq2Seq</strong>: essentially encodes once, and calls the decoder in a loop</li>
<li><strong>Attention</strong>: allows output from the encoder at a specific time point to provide ‘context’ for the decoder</li>
</ul>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">net <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span></span>
<span id="cb36-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq2seq_module</span>(</span>
<span id="cb36-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gru"</span>,</span>
<span id="cb36-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">input_size     =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb36-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">hidden_size    =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">32</span>,</span>
<span id="cb36-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">attention_type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"multiplicative"</span>,</span>
<span id="cb36-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">attention_size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>,</span>
<span id="cb36-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n_forecast     =</span> n_forecast</span>
<span id="cb36-9">  )</span>
<span id="cb36-10"></span>
<span id="cb36-11">b <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dataloader_make_iter</span>(train_dl) <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;">dataloader_next</span>()</span>
<span id="cb36-12"></span>
<span id="cb36-13"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">net</span>(b<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x, b<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">teacher_forcing_ratio =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span></code></pre></div></div>
</div>
</section>
<section id="training" class="level3">
<h3 class="anchored" data-anchor-id="training">Training</h3>
<p>With data in place, we’re ready to train the model. For the most part, not much is going on here that would be different from other deep learning situations, e.g.&nbsp;choosing an optimizer, number of epochs, etc. We’ll use mean squared error as our loss, and I create an object to store the validation loss over the epochs of training. I played around with it a bit, and you’re probably not going to see much improvement after letting it go for 100 epochs.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb37" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb37-1">optimizer <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">optim_adam</span>(net<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>parameters, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lr =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.001</span>)</span>
<span id="cb37-2"></span>
<span id="cb37-3">num_epochs <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb37-4"></span>
<span id="cb37-5">train_batch <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(b, teacher_forcing_ratio) {</span>
<span id="cb37-6"></span>
<span id="cb37-7">  optimizer<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">zero_grad</span>()</span>
<span id="cb37-8">  output <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;">net</span>(b<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x, b<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>y, teacher_forcing_ratio)</span>
<span id="cb37-9">  target <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> b<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>y</span>
<span id="cb37-10"></span>
<span id="cb37-11">  loss <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;">nnf_mse_loss</span>(output, target[ , <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="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dim</span>(output)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])])</span>
<span id="cb37-12">  loss<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">backward</span>()</span>
<span id="cb37-13">  optimizer<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">step</span>()</span>
<span id="cb37-14"></span>
<span id="cb37-15">  loss<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">item</span>()</span>
<span id="cb37-16"></span>
<span id="cb37-17">}</span>
<span id="cb37-18"></span>
<span id="cb37-19">valid_batch <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(b, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">teacher_forcing_ratio =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) {</span>
<span id="cb37-20"></span>
<span id="cb37-21">  output <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;">net</span>(b<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x, b<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>y, teacher_forcing_ratio)</span>
<span id="cb37-22">  target <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> b<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>y</span>
<span id="cb37-23"></span>
<span id="cb37-24">  loss <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;">nnf_mse_loss</span>(output, target[ , <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="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dim</span>(output)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])])</span>
<span id="cb37-25"></span>
<span id="cb37-26">  loss<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">item</span>()</span>
<span id="cb37-27"></span>
<span id="cb37-28">}</span>
<span id="cb37-29"></span>
<span id="cb37-30"></span>
<span id="cb37-31">all_valid_loss <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>()</span>
<span id="cb37-32"></span>
<span id="cb37-33"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (epoch <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>num_epochs) {</span>
<span id="cb37-34"></span>
<span id="cb37-35">  net<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">train</span>()</span>
<span id="cb37-36">  train_loss <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;">c</span>()</span>
<span id="cb37-37"></span>
<span id="cb37-38">  coro<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loop</span>(<span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (b <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> train_dl) {</span>
<span id="cb37-39">    loss <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;">train_batch</span>(b, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">teacher_forcing_ratio =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>)</span>
<span id="cb37-40">    train_loss <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;">c</span>(train_loss, loss)</span>
<span id="cb37-41">  })</span>
<span id="cb37-42"></span>
<span id="cb37-43">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">Epoch %d, training: loss: %3.5f </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, epoch, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(train_loss)))</span>
<span id="cb37-44"></span>
<span id="cb37-45">  net<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">eval</span>()</span>
<span id="cb37-46">  valid_loss <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;">c</span>()</span>
<span id="cb37-47"></span>
<span id="cb37-48">  coro<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loop</span>(<span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (b <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> valid_dl) {</span>
<span id="cb37-49">    loss <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;">valid_batch</span>(b)</span>
<span id="cb37-50">    valid_loss <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;">c</span>(valid_loss, loss)</span>
<span id="cb37-51">  })</span>
<span id="cb37-52">  </span>
<span id="cb37-53">  all_valid_loss <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(all_valid_loss, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(valid_loss))</span>
<span id="cb37-54"></span>
<span id="cb37-55">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">Epoch %d, validation: loss: %3.5f </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, epoch, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(valid_loss)))</span>
<span id="cb37-56">}</span></code></pre></div></div>
</div>
</section>
<section id="evaluations" class="level3">
<h3 class="anchored" data-anchor-id="evaluations">Evaluations</h3>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">net<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">eval</span>()</span>
<span id="cb38-2"></span>
<span id="cb38-3">test_preds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vector</span>(<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;">"list"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(test_dl))</span>
<span id="cb38-4"></span>
<span id="cb38-5">i <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb38-6"></span>
<span id="cb38-7">coro<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loop</span>(<span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (b <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> test_dl) {</span>
<span id="cb38-8"></span>
<span id="cb38-9">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (i <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb38-10">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(i)</span>
<span id="cb38-11"></span>
<span id="cb38-12">  output <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;">net</span>(b<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x, b<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">teacher_forcing_ratio =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb38-13">  preds <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;">as.numeric</span>(output)</span>
<span id="cb38-14"></span>
<span id="cb38-15">  test_preds[[i]] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> preds</span>
<span id="cb38-16">  i <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;&lt;-</span> i <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb38-17">})</span></code></pre></div></div>
</div>
<p>For this visualization, we do things a little different. In our current setup, we have 7 timesteps predicting 7 day windows. We started our test set at the beginning of December so that the first prediction is January first, and then proceeds accordingly.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb39" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb39-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># same as test</span></span>
<span id="cb39-2">df_eval_torch <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df_validate <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb39-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(line <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;">'red'</span>, date <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'2017-12-01'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb39-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(rides_scaled, date) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb39-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tsibble</span>()</span>
<span id="cb39-6"></span>
<span id="cb39-7">test_preds_plot <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vector</span>(<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;">"list"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(test_preds))</span>
<span id="cb39-8"></span>
<span id="cb39-9"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (i <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(test_preds_plot)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>  n_forecast)) {</span>
<span id="cb39-10">  test_preds_plot[[i]] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span></span>
<span id="cb39-11">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb39-12">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pred =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb39-13">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>, n_timesteps <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (i <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb39-14">        test_preds[[i]] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> train_sd <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> train_mean,</span>
<span id="cb39-15">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(df_eval_torch) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> (i <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> n_timesteps <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> n_forecast)</span>
<span id="cb39-16">      )</span>
<span id="cb39-17">    )</span>
<span id="cb39-18">}</span>
<span id="cb39-19"></span>
<span id="cb39-20">df_eval_torch_plot0 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span></span>
<span id="cb39-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bind_cols</span>(df_eval_torch, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bind_cols</span>(test_preds_plot))</span></code></pre></div></div>
</div>
<p>A visualization of the predictions makes this more clear. Each 7 day segment is making predictions for the next 7 days. The following predictions are for the last two months, with each column a set of 7 predictions for that time point.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-05-time-series/index_files/figure-html/unnamed-chunk-9-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>So for our red line plot, we’ll just use the average prediction at each date to make it comparable to the other plots. In general it looks to be doing okay, even armed with no contextual information. Certainly better than the base ARIMA plot.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-05-time-series/index_files/figure-html/unnamed-chunk-10-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>However, we can see that there is much information lost just adhering to the series alone.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">.metric</th>
<th style="text-align: left;" data-quarto-table-cell-role="th">.estimator</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">.estimate</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">rmse</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.804</td>
</tr>
<tr class="even">
<td style="text-align: left;">mae</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.584</td>
</tr>
<tr class="odd">
<td style="text-align: left;">rsq</td>
<td style="text-align: left;">standard</td>
<td style="text-align: right;">0.120</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</section>
<section id="all" class="level2">
<h2 class="anchored" data-anchor-id="all">All</h2>
<p><img src="https://m-clark.github.io/img/time-series/model-test-comparison-all-lines.svg" class="img-fluid"></p>
<p><img src="https://m-clark.github.io/img/time-series/model-test-comparison-red-line.svg" class="img-fluid"></p>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<ul>
<li>ARIMA: no real reason to still be doing such a simplified model</li>
<li>Mixed Model: may be just what you need, but may lack in other settings</li>
<li>GAM: great, more viable than some might suspect, easy implementation</li>
<li>Prophet/Fable: Prophet needs notable work out of the box, though Fable saves you some of that work, and did great in this situation via by-group models</li>
<li>GBM: can it really be this easy?</li>
<li>Torch: pretty good even with minimal information</li>
</ul>
<p>To get some information on what Torch would do at the next level, i.e.&nbsp;adding additional features and other considerations, see <a href="https://www.strong.io/blog/forecasting-public-transport-utilization-in-chicago">Cody’s post</a>.</p>



</section>


<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-Hyndman2021" class="csl-entry">
Hyndman, R. J., and G. Athanasopoulos. 2021. <em>Forecasting: Principles and Practice</em>. 3rd ed. <a href="https://OTexts.com/fpp3">https://OTexts.com/fpp3</a>.
</div>
<div id="ref-west2022" class="csl-entry">
West, Brady T, Kathleen B Welch, and Andrzej T Galecki. 2022. <em>Linear Mixed Models: A Practical Guide Using Statistical Software</em>. Crc Press.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>There is also the Purple express line, which is very irregular compared to the others.↩︎</p></li>
<li id="fn2"><p>Technically we should scale the test set using the mean/sd of the training set, and though with very large data this should not matter, for time series it’s a particular concern as data can ‘shift’ over time.↩︎</p></li>
<li id="fn3"><p>This follows <a href="https://cran.r-project.org/web/packages/glmmTMB/vignettes/covstruct.html">Bolker’s demo</a>.↩︎</p></li>
<li id="fn4"><p>I always appreciated the depiction of this topic in <span class="citation" data-cites="west2022">West et al. (2022)</span> quite a bit.↩︎</p></li>
<li id="fn5"><p>A year plus later after that statement, it still hasn’t gone beyond 0.1.0, so I don’t think this will continue to be useful for very long. Unfortunate, but honestly, it’s not clear <span class="pack" style="">prophet&lt;/span itself can do much better than many other tools.↩︎</span></p></li>
<li id="fn6"><p><span class="pack" style="">fable.prophet</span> may have a bug enabling the holidays functionality with parallel, so you can just use the original holiday column if you do so (single core doesn’t take too long).↩︎</p></li>
<li id="fn7"><p>We can also do this with our previous method with a split-by-apply approach. You would obtain the same results, so this serves as a nice supplement to our ‘overall’ metrics.↩︎</p></li>
<li id="fn8"><p>For the basics of using PyTorch via R, including installation, see <a href="https://blogs.rstudio.com/ai/posts/2020-09-29-introducing-torch-for-r/">the RStudio</a> post.↩︎</p></li>
<li id="fn9"><p>The blog code actually has several issues, but the <a href="https://github.com/mlverse/torchbook_materials/blob/master/scripts/rnn_attention.R">github repo</a> should work fine and is what is followed for this demo.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2022,
  author = {Clark, Michael},
  title = {Exploring {Time}},
  date = {2022-08-10},
  url = {https://m-clark.github.io/posts/2021-05-time-series/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2022" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2022. <span>“Exploring Time.”</span> August 10. <a href="https://m-clark.github.io/posts/2021-05-time-series/">https://m-clark.github.io/posts/2021-05-time-series/</a>.
</div></div></section></div> ]]></description>
  <category>mixed models</category>
  <category>regression</category>
  <category>boosting</category>
  <category>time series</category>
  <category>deep learning</category>
  <guid>https://m-clark.github.io/posts/2021-05-time-series/</guid>
  <pubDate>Wed, 10 Aug 2022 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/time-series/dalle_mini_time_series_seasonal_effect.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>Programming Odds &amp; Ends</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2022-07-25-programming/</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>NB: This post was revisited when updating the website early 2025, and some changes were required. Attempts to keep things consistent were made, but if you feel you’ve found an issue, please post it at <a href="http://github.com/m-clark/m-clark.github.io/issues">GitHub</a>.</p>
</blockquote>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>Oftentimes I’m looking to gain speed/memory advantages, or maybe just exploring how to do the same thing differently in case it becomes useful later on. I thought I’d start posting them, but then I don’t get around to it. Here are a few that have come up over the past year (or two 😞), and even as I wrote this, more examples kept coming up, so I may come back to add more in the future.</p>
</section>
<section id="quick-summary" class="level2">
<h2 class="anchored" data-anchor-id="quick-summary">Quick summary</h2>
<p>Data processing efficiency really depends on context. Faster doesn’t mean memory efficient, and what may be the best in a standard setting can be notably worse in others. Some approaches won’t show their value until the data is very large, or there are many groups to deal with, while others will get notably worse. Also, you may not want an additional package dependency beyond what you’re using, and may need a base R approach. The good news is you’ll always have options!</p>
<p>One caveat: I’m not saying that the following timed approaches are necessarily the best/fastest, I mostly stuck to ones I’d try first. You may find even better for your situation! A great resource to keep in mind is the <a href="https://github.com/fastverse">fastverse</a>, which is a collection of packages with speed and efficiency in mind, and includes a couple that are demonstrated here.</p>
</section>
<section id="setup-and-orientation" class="level2">
<h2 class="anchored" data-anchor-id="setup-and-orientation">Setup and orientation</h2>
<p>Required packages.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(dplyr)</span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tidyr)</span>
<span id="cb1-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(dtplyr)</span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tidyfast)</span>
<span id="cb1-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(data.table)</span>
<span id="cb1-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(collapse)</span>
<span id="cb1-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(vctrs)</span>
<span id="cb1-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(bench)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># for timings</span></span></code></pre></div></div>
</div>
<p>Also, in the following bench marks I turn off checking if the results are equivalent (i.e.&nbsp;<code>check = FALSE</code>) because even if the resulting data is the same, the objects may be different classes, or some objects may even be of the same class, but have different attributes. You are welcome to double check that you would get the same thing as I did. Also, you might want to look at the <code>autoplot</code> of the bench mark summaries, as many results have some variability that isn’t captured by just looking at median/best times.</p>
</section>
<section id="fill-in-missing-values" class="level2">
<h2 class="anchored" data-anchor-id="fill-in-missing-values">Fill in missing values</h2>
<p>We’ll start with the problem of filling in missing values by group. I’ve created a realistic example where the missingness is seen randomly across multiple columns, and differently across groups. I’ve chosen to compare <span class="pack">tidyr</span>, <span class="pack">tidyfast</span>, the underlying approach of <span class="pack">tidyr</span> via <span class="pack">vctrs</span>, and <span class="pack">data.table</span>.</p>
<p>Note that only <span class="pack">data.table</span> is not last observation carried forward by default (‘down’ in <span class="pack">tidyr</span> parlance), so that argument is made explicit. All of these objects will have different attributes or classes. <span class="pack">tidyfast</span> for some reason renames the grouping variable to ‘by’. If you wrap all of these in <code>data.frame</code>, that will remove the attributes and give them all the same class, so you can verify they return the same result.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="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;">1234</span>)</span>
<span id="cb2-2"></span>
<span id="cb2-3">N <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e5</span></span>
<span id="cb2-4">Ng <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5000</span></span>
<span id="cb2-5"></span>
<span id="cb2-6">create_missing <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x) {</span>
<span id="cb2-7">  x[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(x), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb2-8">  x</span>
<span id="cb2-9">}</span>
<span id="cb2-10"></span>
<span id="cb2-11"></span>
<span id="cb2-12">df_missing <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">grp =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>Ng, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">e =</span> N <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> Ng)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb2-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arrange</span>(grp) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb2-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(grp) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb2-15">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb2-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>(),</span>
<span id="cb2-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rpois</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb2-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">z =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb2-19">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>z, create_missing)</span>
<span id="cb2-20">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb2-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ungroup</span>()</span>
<span id="cb2-22"></span>
<span id="cb2-23">df_missing <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="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb2-24"></span>
<span id="cb2-25">dt_missing <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.data.table</span>(df_missing) <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;">setkey</span>(grp)</span>
<span id="cb2-26">tf_missing <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">copy</span>(dt_missing)</span>
<span id="cb2-27"></span>
<span id="cb2-28">bm_fill <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb2-29">  bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb2-30">    <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%!in%</span></span>
<span id="cb2-31">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tidyr    =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fill</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df_missing, grp), x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>z),  </span>
<span id="cb2-32">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tidyfast =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dt_fill</span>(tf_missing, x, y, z, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">id =</span> grp),</span>
<span id="cb2-33">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">vctrs    =</span> df_missing <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;">group_by</span>(grp) <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;">mutate</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">across</span>(x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>z, vec_fill_missing)),</span>
<span id="cb2-34">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dt =</span> dt_missing[</span>
<span id="cb2-35">      ,</span>
<span id="cb2-36">      .(<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;">nafill</span>(x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'locf'</span>),</span>
<span id="cb2-37">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nafill</span>(y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'locf'</span>),</span>
<span id="cb2-38">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">z =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nafill</span>(z, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'locf'</span>)),</span>
<span id="cb2-39">      <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> grp</span>
<span id="cb2-40">    ],</span>
<span id="cb2-41">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">check =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span id="cb2-42">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iterations =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span></span>
<span id="cb2-43">  )</span></code></pre></div></div>
</div>
<p>This is a great example of where there is a notable speed/memory trade-off. Very surprising how much memory <span class="pack">data.table</span> uses<sup>1</sup>, while not giving much speed advantage relative to the <span class="pack">tidyr</span>. Perhaps there is something I’m missing (😏)? Also note that we can get an even ‘tidier’ advantage by using <span class="pack">vctrs</span> directly, rather than wrapping it via <span class="pack">tidyr</span>, and seeing how easy it is to use, it’s probably the best option.</p>
<div class="cell">
<div class="cell-output-display">
<div id="sgxkvpnlkv" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#sgxkvpnlkv table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#sgxkvpnlkv .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#sgxkvpnlkv .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">tidyfast</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">18.3ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">24.5ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">39.87MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">6.06</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">vctrs</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">27ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">28.5ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">6.58MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.16</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dt</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">111.7ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">117.8ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">237.08MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.81</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">36.04</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">tidyr</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">132.3ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">147.2ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">6.59MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">6.01</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
<section id="antijoins" class="level2">
<h2 class="anchored" data-anchor-id="antijoins">Antijoins</h2>
<p>Sometimes you just don’t want that! In the following we have a situation where we want to filter values based on the negation of some condition. Think of a case where certain person IDs are not viable for consideration for analysis. Many times, a natural approach would be to use something like a filter where instead of using <code>vals %in% values_desired</code>, we just negate that with a bang (<code>!</code>) operator. However, another approach is to create a data frame of the undesired values and use an <code>anti_join</code>. When using joins in general, you get a relative advantage by explicitly noting the variables you’re joining on, so I compare that as well for demonstration. Finally, in this particular example we could use <span class="pack">data.table’s</span> built-in character match, <code>chin</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb3-2"></span>
<span id="cb3-3">df1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(</span>
<span id="cb3-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">id =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(letters, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb3-5">)</span>
<span id="cb3-6"></span>
<span id="cb3-7">df2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(</span>
<span id="cb3-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">id =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(letters[<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 class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb3-9">)</span>
<span id="cb3-10"></span>
<span id="cb3-11">df1_lazy <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lazy_dt</span>(df1)</span>
<span id="cb3-12">df2_lazy <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lazy_dt</span>(df2)</span>
<span id="cb3-13"></span>
<span id="cb3-14">df1_dt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.table</span>(df1)</span>
<span id="cb3-15">df2_dt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.table</span>(df2)</span>
<span id="cb3-16"></span>
<span id="cb3-17"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">suppressMessages</span>({</span>
<span id="cb3-18">  bm_antijoin <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb3-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">in_     =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(df1, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>id <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> letters[<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="cb3-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">in_dtp  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">collect</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(df1_lazy, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>id <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> letters[<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># not usable until collected/as_tibbled</span></span>
<span id="cb3-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">chin    =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(df1, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>id <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%chin%</span> letters[<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># chin for char vector only, from data.table</span></span>
<span id="cb3-22">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">chin_dt =</span> df1_dt[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>df1_dt<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>id <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%chin%</span> letters[<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="cb3-23">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coll    =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fsubset</span>(df1, id <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%!in%</span> letters[<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 class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># can work with dt or tidyverse</span></span>
<span id="cb3-24">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">aj      =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">anti_join</span>(df1, df2, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'id'</span>),</span>
<span id="cb3-25">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">aj_noby =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">anti_join</span>(df1, df2),</span>
<span id="cb3-26"></span>
<span id="cb3-27">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iterations =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>,</span>
<span id="cb3-28">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">check      =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb3-29">  )</span>
<span id="cb3-30">})</span></code></pre></div></div>
</div>
<p>In this case, the fully <span class="pack">data.table</span> approach is best in speed and memory, but <span class="pack">collapse</span> is not close behind<sup>2</sup>. In addition, if you are in the tidyverse, the <code>anti_join</code> function is a very good option. Hopefully the lesson about explicitly setting the <code>by</code> argument is made clear.</p>
<div class="cell">
<div class="cell-output-display">
<div id="oiunnmcslx" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#oiunnmcslx table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#oiunnmcslx .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#oiunnmcslx .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">chin_dt</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">152µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">160µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">206KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">coll</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">167µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">185µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">268KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.16</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.3</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">aj</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">529µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">559µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">293KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">3.5</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.42</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">chin</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">626µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">662µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">270KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.15</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.31</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">in_</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">716µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">804µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">387KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">5.04</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.88</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">in_dtp</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">923µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">988µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">479KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">6.2</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">2.33</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">aj_noby</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">9.95ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">10.962ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">323KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">68.72</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.57</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
<section id="lagleaddifferences" class="level2">
<h2 class="anchored" data-anchor-id="lagleaddifferences">Lag/lead/differences</h2>
<p>Here we are interested in getting the difference in the current value of some feature from it’s last (or next) value, typically called a lag (lead). Note that it doesn’t have to be the last value, but that is most common. In the tidyverse we have <code>lag</code>/<code>lead</code> functions, or with <span class="pack">data.table</span>, we have the generic <code>shift</code> function that can do both. In the following I look at using that function in the fully <span class="pack">data.table</span> situation or within a tibble.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="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;">1234</span>)</span>
<span id="cb4-2"></span>
<span id="cb4-3">N <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e5</span></span>
<span id="cb4-4">Ng <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5000</span></span>
<span id="cb4-5"></span>
<span id="cb4-6">df  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(</span>
<span id="cb4-7">  <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;">rpois</span>(N, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>),</span>
<span id="cb4-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">grp =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>Ng, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">e =</span> N <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> Ng)</span>
<span id="cb4-9">)</span>
<span id="cb4-10"></span>
<span id="cb4-11">dt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.data.table</span>(df)</span>
<span id="cb4-12"></span>
<span id="cb4-13">bm_lag <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb4-14">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dplyr_lag  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(df, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff =</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lag</span>(x)),</span>
<span id="cb4-15">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dplyr_lead =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(df, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff =</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lead</span>(x)),</span>
<span id="cb4-16">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dt_lag     =</span> dt[, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff :=</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">shift</span>(x)],</span>
<span id="cb4-17">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dt_lead    =</span> dt[, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff :=</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">shift</span>(x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)],</span>
<span id="cb4-18">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dt_dp_lag  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(df, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff =</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">shift</span>(x)),</span>
<span id="cb4-19">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dt_dp_lead =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(df, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff =</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">shift</span>(x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb4-20">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coll_lag   =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ftransform</span>(df, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff =</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">flag</span>(x)),</span>
<span id="cb4-21">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coll_lead  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ftransform</span>(df, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff =</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">flag</span>(x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)),</span>
<span id="cb4-22">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iterations =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>,</span>
<span id="cb4-23">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">check      =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb4-24">)</span></code></pre></div></div>
</div>
<p>In this case, <span class="pack">collapse</span> is best, with <span class="pack">data.table</span> not far behind, but using the <code>shift</code> function within the tidy approach is a very solid gain. Oddly, <code>lag</code> and <code>lead</code> seem somewhat different in terms of speed and memory.</p>
<div class="cell">
<div class="cell-output-display">
<div id="jwxduoznik" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#jwxduoznik table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#jwxduoznik .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#jwxduoznik .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">coll_lag</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">226µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">260µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">783.84KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">coll_lead</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">250µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">309µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">783.84KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.18</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dt_lag</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">316µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">354µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">813.87KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.36</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.04</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dt_lead</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">319µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">355µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">813.87KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.36</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.04</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dt_dp_lag</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">792µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">818µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">782.91KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">3.14</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dt_dp_lead</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">797µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">892µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">782.91KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">3.42</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dplyr_lead</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">994µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">1.115ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">1.53MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.28</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">2</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dplyr_lag</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">1.044ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">1.2ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">1.15MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.61</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.5</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>What about a grouped scenario? To keep it simple we’ll just look at using lagged values.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1">bm_lag_grp <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb5-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dt_lag    =</span> dt[, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff :=</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">shift</span>(x), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> grp],</span>
<span id="cb5-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dt_dp_lag =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, grp), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff =</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">shift</span>(x)),</span>
<span id="cb5-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dplyr_lag =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, grp), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff =</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lag</span>(x)),</span>
<span id="cb5-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coll_lag  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fmutate</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fgroup_by</span>(df, grp), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x_diff =</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">flag</span>(x)),</span>
<span id="cb5-6">  </span>
<span id="cb5-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iterations =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>,</span>
<span id="cb5-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">check      =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb5-9">)</span></code></pre></div></div>
</div>
<p>In the grouped situation, using a <span class="pack">collapse</span> isn’t best for memory, but the speed gain is ridiculous!!</p>
<div class="cell">
<div class="cell-output-display">
<div id="bkdbedqaaa" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#bkdbedqaaa table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#bkdbedqaaa .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#bkdbedqaaa .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">coll_lag</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">484µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">548µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">1.59MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">3.52</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dt_lag</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">25.692ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">28.067ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">462.32KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">51.2</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dt_dp_lag</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">30.843ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">32.969ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">2.61MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">60.15</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">5.77</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dplyr_lag</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">77.156ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">78.771ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">5.19MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">143.7</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">11.49</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
<section id="firstlast" class="level2">
<h2 class="anchored" data-anchor-id="firstlast">First/Last</h2>
<p>In this demo, we want to take the first (last) value of each group. Surprisingly, for the same functionality, it turns out that the number of groups matter when doing groupwise operations. For the following I’ll even use a base R approach (though within <span class="pack">dplyr’s</span> mutate) to demonstrate some differences.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1234</span>)</span>
<span id="cb6-2"></span>
<span id="cb6-3">N <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100000</span></span>
<span id="cb6-4"></span>
<span id="cb6-5">df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(</span>
<span id="cb6-6">  <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;">rpois</span>(N, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>),</span>
<span id="cb6-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">id =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, N, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb6-8">)</span>
<span id="cb6-9"></span>
<span id="cb6-10">dt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.data.table</span>(df)</span>
<span id="cb6-11"></span>
<span id="cb6-12">bm_first <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb6-13">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_first  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarize</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, id), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> x[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]),</span>
<span id="cb6-14">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_last   =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarize</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, id), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> x[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(x)]),</span>
<span id="cb6-15">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dplyr_first =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarize</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, id), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">first</span>(x)),</span>
<span id="cb6-16">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dplyr_last  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarize</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, id), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">last</span>(x)),</span>
<span id="cb6-17">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dt_first    =</span> dt[, .(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> data.table<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">first</span>(x)), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> id],</span>
<span id="cb6-18">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dt_last     =</span> dt[, .(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> data.table<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">last</span>(x)),  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> id],</span>
<span id="cb6-19">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coll_first  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ffirst</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fgroup_by</span>(df, id)),</span>
<span id="cb6-20">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coll_last   =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">flast</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fgroup_by</span>(df, id)),</span>
<span id="cb6-21">  </span>
<span id="cb6-22">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iterations  =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>,</span>
<span id="cb6-23">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">check       =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb6-24">)</span></code></pre></div></div>
</div>
<p>The first result is actually not too surprising, in that the fully dt approaches are fast and memory efficient, though <span class="pack">collapse</span> is notably faster. Somewhat interesting is that the base last is a bit faster than <span class="pack">dplyr’s</span> <code>last</code> (technically <code>nth</code>) approach.</p>
<div class="cell">
<div class="cell-output-display">
<div id="ggsqtgsqap" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#ggsqtgsqap table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#ggsqtgsqap .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#ggsqtgsqap .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">coll_last</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">307µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">341µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">783.53KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.72</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">coll_first</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">299µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">345µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">783.53KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.01</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.72</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dt_last</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">698µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">876µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">454.62KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">2.57</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dt_first</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">689µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">895µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">454.62KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">2.62</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">base_last</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">1.944ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">2.036ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">2.06MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">5.97</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.64</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dplyr_first</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">2.026ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">2.127ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">2.06MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">6.24</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.64</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">base_first</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">1.984ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">2.165ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">2.06MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">6.35</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.64</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dplyr_last</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">2.111ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">2.553ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">2.06MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">7.49</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.64</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>In the following, the only thing that changes is the number of groups.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="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;">1234</span>)</span>
<span id="cb7-2"></span>
<span id="cb7-3">N <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100000</span></span>
<span id="cb7-4"></span>
<span id="cb7-5">df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(</span>
<span id="cb7-6">  <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;">rpois</span>(N, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>),</span>
<span id="cb7-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">id =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>(N<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>), N, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># &lt;--- change is here</span></span>
<span id="cb7-8">)</span>
<span id="cb7-9"></span>
<span id="cb7-10">dt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.data.table</span>(df)</span>
<span id="cb7-11"></span>
<span id="cb7-12">bm_first_more_groups <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb7-13">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_first  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarize</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, id), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> x[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]),</span>
<span id="cb7-14">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base_last   =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarize</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, id), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> x[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(x)]),</span>
<span id="cb7-15">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dplyr_first =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarize</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, id), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">first</span>(x)),</span>
<span id="cb7-16">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dplyr_last  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarize</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, id), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">last</span>(x)),</span>
<span id="cb7-17">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dt_first    =</span> dt[, .(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> data.table<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">first</span>(x)), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> id],</span>
<span id="cb7-18">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dt_last     =</span> dt[, .(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> data.table<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">last</span>(x)),  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> id],</span>
<span id="cb7-19">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coll_first  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ffirst</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, id)),</span>
<span id="cb7-20">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coll_last   =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">flast</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, id)),</span>
<span id="cb7-21">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iterations  =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>,</span>
<span id="cb7-22">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">check       =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb7-23">)</span></code></pre></div></div>
</div>
<p>Now what the heck is going on here? The base R approach is way faster than even <span class="pack">data.table</span>, while not using any more memory than what <span class="pack">dplyr</span> is doing (because of the group-by-summarize). More to the point is that <span class="pack">collapse</span> is notably faster than the other options, but still a bit heavy memory-wise relative to <span class="pack">data.table</span>.</p>
<div class="cell">
<div class="cell-output-display">
<div id="guoivyxhmb" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#guoivyxhmb table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#guoivyxhmb .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#guoivyxhmb .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">coll_last</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">2.813ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">3.006ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">2.79MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">3.8</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">coll_first</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">2.838ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">3.128ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">2.79MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.04</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">3.8</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">base_first</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">10.596ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">11.4ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">3.06MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">3.79</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.17</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">base_last</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">12.551ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">13.151ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">3.06MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.37</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.17</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dt_last</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">17.588ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">18.318ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">752.15KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">6.09</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dt_first</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">17.671ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">18.379ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">752.15KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">6.11</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dplyr_first</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">20.066ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">20.943ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">3.06MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">6.97</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.17</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dplyr_last</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">20.916ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">21.357ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">3.16MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">7.1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.31</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
<section id="coalesceifelse" class="level2">
<h2 class="anchored" data-anchor-id="coalesceifelse">Coalesce/ifelse</h2>
<p>It’s very often we want to change a single value based on some condition, often starting with <code>ifelse</code>. This is similar to our previous fill situation for missing values, but applies a constant as opposed to last/next value. <code>Coalesce</code> is similar to <span class="pack">tidyr’s</span> <code>fill</code>, and is often used in cases where we might otherwise use an <code>ifelse</code> style approach . In the following, we want to change NA values to zero, and there are many ways we might go about it.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><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;">1234</span>)</span>
<span id="cb8-2">x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>)</span>
<span id="cb8-3">x[x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb8-4"></span>
<span id="cb8-5"></span>
<span id="cb8-6">bm_coalesce <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb8-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">base      =</span> {x[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(x)] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>; x},</span>
<span id="cb8-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ifelse    =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ifelse</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(x), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, x),</span>
<span id="cb8-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">if_else   =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">if_else</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(x), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, x),</span>
<span id="cb8-10">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">vctrs     =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vec_assign</span>(x, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(x), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb8-11">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tidyr     =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace_na</span>(x, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb8-12">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fifelse   =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fifelse</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(x), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, x),</span>
<span id="cb8-13">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coalesce  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coalesce</span>(x, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb8-14">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fcoalesce =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fcoalesce</span>(x, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb8-15">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nafill    =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nafill</span>(x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb8-16">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">coll      =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replace_NA</span>(x)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># default is 0</span></span>
<span id="cb8-17">)</span></code></pre></div></div>
</div>
<p>The key result here to me is just how much memory the <span class="pack">dplyr</span> <code>if_else</code> approach is using, as well as how fast and memory efficient the base R approach is even with a second step. While providing type safety, <code>if_else</code> is both slow and a memory hog, so probably anything else is better. <span class="pack">tidyr</span> itself would be a good option here, and while it makes up for the memory issue, it’s relatively slow compared to other approaches, including the function it’s a wrapper for (<code>vec_assign</code>), which is also demonstrated. Interestingly, <code>fcoalesce</code> and <code>fifelse</code> would both be better options than <span class="pack">data.table’s</span> other approach that is explicitly for this task.</p>
<div class="cell">
<div class="cell-output-display">
<div id="pgwkwymidr" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#pgwkwymidr table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#pgwkwymidr .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#pgwkwymidr .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">fcoalesce</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">1µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">1µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">7.86KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">coll</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">1µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">1µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">7.86KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.03</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">base</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">2µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">3µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">7.91KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">2.17</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.01</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">fifelse</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">3µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">4µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">11.81KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">2.6</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.5</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">vctrs</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">4µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">4µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">11.81KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">3.09</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.5</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">nafill</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">5µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">6µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">23.95KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.14</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">3.05</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">tidyr</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">9µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">10µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">11.81KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">7.09</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.5</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">coalesce</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">15µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">17µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">20.19KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">11.71</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">2.57</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">ifelse</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">15µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">17µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">47.31KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">12.11</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">6.02</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">if_else</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">21µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">25µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">71.06KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">17.54</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">9.04</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
<section id="conditional-slide" class="level2">
<h2 class="anchored" data-anchor-id="conditional-slide">Conditional Slide</h2>
<p>I recently had a problem where I wanted to do a apply a certain function that required taking the difference between the current and last value as we did in the lag demo. The problem was that ‘last’ depended on a specific condition being met. The basic idea is that we want to take x - lag(x) but where the condition is <code>FALSE</code>, we need to basically ignore that value for consideration as the last value, and only use the previous value for which the condition is <code>TRUE</code>. In the following, for the first two values where the condition is met, this is straightforward (6 minus 10). But for the fourth row, 4 should subtract 6, rather than 5, because the condition is <code>FALSE</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="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;">1234</span>)</span>
<span id="cb9-2"></span>
<span id="cb9-3">df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(</span>
<span id="cb9-4">  <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;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>),</span>
<span id="cb9-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cond =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>),</span>
<span id="cb9-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">group =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'a'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b'</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">e =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb9-7">)</span>
<span id="cb9-8"></span>
<span id="cb9-9">df </span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 10 × 3
       x cond  group
   &lt;int&gt; &lt;lgl&gt; &lt;chr&gt;
 1    10 TRUE  a    
 2     6 TRUE  a    
 3     5 FALSE a    
 4     4 TRUE  a    
 5     1 FALSE a    
 6     8 TRUE  b    
 7     2 FALSE b    
 8     7 FALSE b    
 9     9 TRUE  b    
10     3 FALSE b    </code></pre>
</div>
</div>
<p>While somewhat simple in concept, it doesn’t really work with simple lags, as the answer would be wrong, or sliding functions, because the window is adaptive. I wrote the following function to deal with this. By default, it basically takes our vector under consideration, <code>x</code>, makes it <code>NA</code> where the condition doesn’t hold, then fills in the NA values with the last value using the <code>vec_fill_missing</code> (or a supplied constant/single value). However there is flexibility beyond that type of fill. In addition, the function applied is generic, and could be applied to the newly created variable (<code>.x</code>), or use both the original (<code>x</code>) and the newly created variable.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1">conditional_slide <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span></span>
<span id="cb11-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x,</span>
<span id="cb11-3">           condition,</span>
<span id="cb11-4">           fun,</span>
<span id="cb11-5">           <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">direction  =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"down"</span>),</span>
<span id="cb11-6">           <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill_value =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>,</span>
<span id="cb11-7">           <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">na_value   =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>,</span>
<span id="cb11-8">           ...) {</span>
<span id="cb11-9">    </span>
<span id="cb11-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>direction <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"constant"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"down"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"up"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"downup"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"updown"</span>))</span>
<span id="cb11-11">      rlang<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abort</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'direction must be one of "constant", "down", "up", "downup", "updown"'</span>)</span>
<span id="cb11-12">    </span>
<span id="cb11-13">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(x) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(condition))</span>
<span id="cb11-14">      rlang<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abort</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'condition and x must be the same length'</span>)</span>
<span id="cb11-15">    </span>
<span id="cb11-16">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># can't use dplyr/dt ifelse since we won't know class type of fill_value</span></span>
<span id="cb11-17">    conditional_val <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;">ifelse</span>(direction <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;">'constant'</span>, fill_value, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>)    </span>
<span id="cb11-18">    .x <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;">ifelse</span>(condition, x, conditional_val)</span>
<span id="cb11-19">    </span>
<span id="cb11-20">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (direction <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;">'constant'</span>)</span>
<span id="cb11-21">      .x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> vctrs<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vec_fill_missing</span>(.x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">direction =</span> direction)</span>
<span id="cb11-22">    </span>
<span id="cb11-23">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">class</span>(.x) <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;">class</span>(x)</span>
<span id="cb11-24">    </span>
<span id="cb11-25">    result <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;">fun</span>(x, .x, ...)</span>
<span id="cb11-26">    </span>
<span id="cb11-27">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(na_value))</span>
<span id="cb11-28">      result[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(result)] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> na_value</span>
<span id="cb11-29">    </span>
<span id="cb11-30">    result</span>
<span id="cb11-31">  }</span></code></pre></div></div>
</div>
<p>The first example applies the function, <code>x - lag(x)</code>, to our dataset, and which in my case, I also wanted to apply within groups, which caused further problems for some of the available functions I thought would otherwise be applicable. I also show it for another type of problem, taking the cumulative sum, as well as just conditionally changing the values to zero.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">df <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;">group_by</span>(group) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb12-3"> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb12-4">   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># demo first difference</span></span>
<span id="cb12-5">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">simple_diff =</span> x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lag</span>(x),</span>
<span id="cb12-6">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cond_diff =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">conditional_slide</span>(x, cond, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> \(x, .x) x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lag</span>(.x), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">na_value =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>),</span>
<span id="cb12-7">   </span>
<span id="cb12-8">   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># demo cumulative sum</span></span>
<span id="cb12-9">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">simple_cumsum =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cumsum</span>(x),</span>
<span id="cb12-10">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cond_cumsum   =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">conditional_slide</span>(</span>
<span id="cb12-11">     x,</span>
<span id="cb12-12">     cond,</span>
<span id="cb12-13">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> \(x, .x) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cumsum</span>(.x),</span>
<span id="cb12-14">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">direction =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'constant'</span>,</span>
<span id="cb12-15">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb12-16">   ),</span>
<span id="cb12-17">   </span>
<span id="cb12-18">   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># demo fill last</span></span>
<span id="cb12-19">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">simple_fill_last =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vec_fill_missing</span>(x),</span>
<span id="cb12-20">   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cond_fill_last =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">conditional_slide</span>(</span>
<span id="cb12-21">     x,</span>
<span id="cb12-22">     cond,</span>
<span id="cb12-23">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fun =</span> \(x, .x) .x,</span>
<span id="cb12-24">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">direction =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'down'</span></span>
<span id="cb12-25">   )</span>
<span id="cb12-26"> )</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 10 × 9
# Groups:   group [2]
       x cond  group simple_diff cond_diff simple_cumsum cond_cumsum
   &lt;int&gt; &lt;lgl&gt; &lt;chr&gt;       &lt;int&gt;     &lt;dbl&gt;         &lt;int&gt;       &lt;int&gt;
 1    10 TRUE  a              NA         0            10          10
 2     6 TRUE  a              -4        -4            16          16
 3     5 FALSE a              -1        -1            21          16
 4     4 TRUE  a              -1        -2            25          20
 5     1 FALSE a              -3        -3            26          20
 6     8 TRUE  b              NA         0             8           8
 7     2 FALSE b              -6        -6            10           8
 8     7 FALSE b               5        -1            17           8
 9     9 TRUE  b               2         1            26          17
10     3 FALSE b              -6        -6            29          17
# ℹ 2 more variables: simple_fill_last &lt;int&gt;, cond_fill_last &lt;int&gt;</code></pre>
</div>
</div>
<p>This is one of those things that comes up from time to time where trying to apply a standard tool likely won’t cut it. You may find similar situations where you need to modify what’s available and create some functionality tailored to your needs.</p>
</section>
<section id="take-the-first-true" class="level2">
<h2 class="anchored" data-anchor-id="take-the-first-true">Take the first TRUE</h2>
<p>Sometimes we want the first instance of a condition. For example, we might want the position or value of the first number &gt; than some value. We’ve already investigated using <span class="pack">dplyr</span> or <span class="pack">data.table’s</span> <code>first</code>, and I won’t do so again here except to say they are both notably slower and worse on memory here. We have a few approaches we might take in base R. Using <code>which</code> would be common, but there is also <code>which.max</code>, that, when applied to logical vectors, gives the position of the first <code>TRUE</code> (<code>which.min</code> gives the position of the first <code>FALSE</code>). In addition, there is the <code>Position</code> function, which I didn’t even know about until messing with this problem.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb14-2"></span>
<span id="cb14-3">x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span>))</span>
<span id="cb14-4"></span>
<span id="cb14-5">marker <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb14-6"></span>
<span id="cb14-7">bm_first_true_1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb14-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">which     =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which</span>(x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> marker)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb14-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">which_max =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which.max</span>(x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> marker),</span>
<span id="cb14-10">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pos       =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Position</span>(\(x) x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> marker, x)</span>
<span id="cb14-11">)</span>
<span id="cb14-12"></span>
<span id="cb14-13"></span>
<span id="cb14-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># make it slightly more challenging</span></span>
<span id="cb14-15">x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e6</span>))</span>
<span id="cb14-16"></span>
<span id="cb14-17">marker <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span> </span>
<span id="cb14-18"></span>
<span id="cb14-19">bm_first_true_2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb14-20">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">which     =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which</span>(x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> marker)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb14-21">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">which_max =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which.max</span>(x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> marker),</span>
<span id="cb14-22">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pos       =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Position</span>(\(x) x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> marker, x)</span>
<span id="cb14-23">)</span></code></pre></div></div>
</div>
<p>Interestingly <code>Position</code> provides the best memory performance, but is prohibitively slower. <code>which.max</code> is probably your best bet.</p>
<div class="cell">
<div class="cell-output-display">
<div id="zfontnxddu" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#zfontnxddu table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#zfontnxddu .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#zfontnxddu .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">which</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">15µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">20µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">79.14KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">14.19</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">which_max</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">18µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">20µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">39.11KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.01</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">7.01</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">pos</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">1.986ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">2.158ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">5.58KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">109.67</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output-display">
<div id="htxcdzeboh" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#htxcdzeboh table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#htxcdzeboh .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#htxcdzeboh .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">which</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">1.44ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">1.69ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">7.63MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1400.58</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">which_max</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">1.79ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">2ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">3.81MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.18</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">700.29</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">pos</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">213.55ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">219.13ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">5.58KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">129.4</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>But not so fast? The following makes the first case come very quickly, where <code>Position</code> blows the other options out of the water! I guess if you knew this was going to be the case you could take serious advantage.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb15-2"></span>
<span id="cb15-3">x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100000</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">decreasing =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb15-4"></span>
<span id="cb15-5">x[<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;">30</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb15-6"></span>
<span id="cb15-7"></span>
<span id="cb15-8">bm_first_true_3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb15-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">which     =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which</span>(x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> marker)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>],</span>
<span id="cb15-10">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">which_max =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which.max</span>(x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> marker),</span>
<span id="cb15-11">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pos       =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Position</span>(\(x) x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> marker, x) </span>
<span id="cb15-12">)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<div id="tplcwisvdh" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#tplcwisvdh table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#tplcwisvdh .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#tplcwisvdh .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">pos_rev</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">10µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">10µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">5.58KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">which_max_rev</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">110µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">130µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">390.67KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">13.04</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">70.04</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">which_rev</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">160µs</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">220µs</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">1.14MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">22.55</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">210.09</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
<section id="group-by-filteringslicing" class="level2">
<h2 class="anchored" data-anchor-id="group-by-filteringslicing">Group by filtering/slicing</h2>
<p>The previous situation was the basis for this next demo where we utilize <code>which.max</code>. Here we want to filter in one scenario, such that if all values are zero, we drop them, and in the second, we want to only retain certain values based on a condition. In this latter case, the condition is that at least one non-zero has occurred, in which case we want to keep all of those values from that point on (even if they are zero).</p>
<p>To make things more clear, for the example data that follows, we want to drop group 1 entirely, the initial part of group 2, and retain all of group 3.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tidyverse)</span>
<span id="cb16-2"></span>
<span id="cb16-3"><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;">12345</span>)</span>
<span id="cb16-4"></span>
<span id="cb16-5">df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(</span>
<span id="cb16-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">group =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">e =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>),</span>
<span id="cb16-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">value =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb16-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>),</span>
<span id="cb16-9">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</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;">7</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)), </span>
<span id="cb16-10">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb16-11">  )</span>
<span id="cb16-12">)</span>
<span id="cb16-13"></span>
<span id="cb16-14"></span>
<span id="cb16-15">df <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb16-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(group) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb16-17">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb16-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">slice</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which.max</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>())</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 17 × 2
# Groups:   group [2]
   group value
   &lt;int&gt; &lt;dbl&gt;
 1     2     5
 2     2     2
 3     2     1
 4     2     3
 5     2     1
 6     2     4
 7     2     2
 8     3     7
 9     3     1
10     3     5
11     3    10
12     3     5
13     3     6
14     3     9
15     3     0
16     3     7
17     3     6</code></pre>
</div>
</div>
<p>In the above scenario, we take two steps to illustrate our desired outcome conceptually. Ideally though, we’d like one step, because it is just a general filtering. You might think maybe to change <code>which.max</code> to <code>which</code> and just slice, but this would remove all zeros, when we want to retain zeros after the point where at least some values are greater than zero. Using <code>row_number</code> was a way I thought to get around things.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">df <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb18-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(group) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb18-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">row_number</span>() <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;">which.max</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span>
<span id="cb18-4"></span>
<span id="cb18-5"></span>
<span id="cb18-6">bm_filter_slice <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb18-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">orig =</span> df <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb18-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(group) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb18-9">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb18-10">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">slice</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which.max</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()),</span>
<span id="cb18-11">  </span>
<span id="cb18-12">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">new =</span> df <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb18-13">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(group) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb18-14">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">row_number</span>() <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;">which.max</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span>
<span id="cb18-15">)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<div id="falthzlcin" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#falthzlcin table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#falthzlcin .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#falthzlcin .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">orig</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">2ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">2.2ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">10.25KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.11</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">new</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">6.1ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">7.1ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">9.21KB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">3.28</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>Well we got it to one operation, but now it takes longer and has no memory advantage. Are we on the wrong track? Let’s try with a realistically sized data set with a lot of groups.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1234</span>)</span>
<span id="cb19-2"></span>
<span id="cb19-3">N <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100000</span></span>
<span id="cb19-4">g <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>(N<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb19-5"></span>
<span id="cb19-6">df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(</span>
<span id="cb19-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">group =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(g, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">e =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>),</span>
<span id="cb19-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">value =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</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="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> N, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb19-9">)</span>
<span id="cb19-10"></span>
<span id="cb19-11">bm_filter_slice2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb19-12">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">orig =</span> df <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb19-13">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(group) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb19-14">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb19-15">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">slice</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which.max</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()),</span>
<span id="cb19-16">  </span>
<span id="cb19-17">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">new =</span> df <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb19-18">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(group) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb19-19">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">row_number</span>() <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;">which.max</span>(value <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span>
<span id="cb19-20">)</span></code></pre></div></div>
</div>
<p>Now we have the reverse scenario. The single filter is notably faster and more memory efficient.</p>
<div class="cell">
<div class="cell-output-display">
<div id="mtjwppbtiy" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#mtjwppbtiy table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#mtjwppbtiy .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#mtjwppbtiy .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">new</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">208.6ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">209.9ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">12.9MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">orig</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">949.8ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">949.8ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">28.3MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.53</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">2.19</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</section>
<section id="tidy-timings" class="level2">
<h2 class="anchored" data-anchor-id="tidy-timings">Tidy timings</h2>
<section id="overview" class="level3">
<h3 class="anchored" data-anchor-id="overview">Overview</h3>
<blockquote class="blockquote">
<p>This tidy timings section comes from a notably old exploration I rediscovered (I think it was originally Jan 2020), but it looks like tidyfast still has some functionality beyond dtplyr, and it doesn’t hurt to revisit. I added a result for collapse. My original timings were on a nicely suped up pc, but the following are on a year and a half old macbook with an M1 processer, and were almost 2x faster.</p>
</blockquote>
<p>Here I take a look at some timings for data processing tasks. My reason for doing so is that <span class="pack">dtplyr</span> has recently arisen from the dead, and <span class="pack">tidyfast</span> has come on the scene, so I wanted a quick reference for myself and others to see how things stack up against <span class="pack">data.table</span>.</p>
<p>So we have the following:</p>
<ul>
<li><em>Base R</em>: Just kidding. If you’re using base R approaches for this <code>aggregate</code> you will always be slower. Functions like <code>aggregate</code>, <code>tapply</code> and similar could be used in these demos, but I leave that as an exercise to the reader. I’ve done them, and it isn’t pretty.</li>
<li><em>dplyr</em>: standard data wrangling workhorse package</li>
<li><em>tidyr</em>: has some specific functionality not included in dplyr</li>
<li><em>data.table</em>: another commonly used data processing package that purports to be faster and more memory efficient (usually but not always)</li>
<li><em>tidyfast</em>: can only do a few things, but does them quickly.</li>
<li><em>collapse</em>: many replacements for base R functions.</li>
</ul>
</section>
<section id="standard-grouped-operation" class="level3">
<h3 class="anchored" data-anchor-id="standard-grouped-operation">Standard grouped operation</h3>
<p>The following demonstrates some timings from <a href="http://stackoverflow.com/questions/3505701/r-grouping-functions-sapply-vs-lapply-vs-apply-vs-tapply-vs-by-vs-aggrega/34167477#34167477">this post on stackoverflow</a>. I reproduced it on my own machine based on 50 million observations. The grouped operations that are applied are just a sum and length on a vector. As this takes several seconds to do even once, I only do it one time.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb20-2">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5e7</span></span>
<span id="cb20-3">k <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5e5</span></span>
<span id="cb20-4">x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(n)</span>
<span id="cb20-5">grp <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(k, n, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb20-6"></span>
<span id="cb20-7">timing_group_by_big <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>()</span>
<span id="cb20-8"></span>
<span id="cb20-9"></span>
<span id="cb20-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># dplyr</span></span>
<span id="cb20-11">timing_group_by_big[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dplyr"</span>]] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.time</span>({</span>
<span id="cb20-12">    df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(x, grp)</span>
<span id="cb20-13">    r.dplyr <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(df, grp), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(x), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>())</span>
<span id="cb20-14">})</span>
<span id="cb20-15"></span>
<span id="cb20-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># dtplyr</span></span>
<span id="cb20-17">timing_group_by_big[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dtplyr"</span>]] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.time</span>({</span>
<span id="cb20-18">    df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lazy_dt</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(x, grp))</span>
<span id="cb20-19">    r.dtplyr <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> df <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;">group_by</span>(grp) <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;">summarise</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(x), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>()) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">collect</span>()</span>
<span id="cb20-20">})</span>
<span id="cb20-21"></span>
<span id="cb20-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># tidyfast</span></span>
<span id="cb20-23">timing_group_by_big[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tidyfast"</span>]] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.time</span>({</span>
<span id="cb20-24">    dt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setnames</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setDT</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(x, grp)), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grp"</span>))</span>
<span id="cb20-25">    r.tidyfast <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dt_count</span>(dt, grp)</span>
<span id="cb20-26">})</span>
<span id="cb20-27"></span>
<span id="cb20-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># data.table</span></span>
<span id="cb20-29">timing_group_by_big[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data.table"</span>]] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.time</span>({</span>
<span id="cb20-30">    dt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setnames</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setDT</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(x, grp)), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grp"</span>))</span>
<span id="cb20-31">    r.data.table <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> dt[, .(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(x), .N), grp]</span>
<span id="cb20-32">})</span>
<span id="cb20-33"></span>
<span id="cb20-34"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># collapse</span></span>
<span id="cb20-35">timing_group_by_big[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"collapse"</span>]] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.time</span>({</span>
<span id="cb20-36">     df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(x, grp)</span>
<span id="cb20-37">    r.data.table <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fsummarise</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fgroup_by</span>(df, grp), <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;">fsum</span>(x),  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fnobs</span>(x))</span>
<span id="cb20-38">})</span>
<span id="cb20-39"></span>
<span id="cb20-40">timing_group_by_big <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> timing_group_by_big <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb20-41">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">do.call</span>(rbind, .) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb20-42">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb20-43">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rownames_to_column</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'package'</span>)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<div id="dhkfieosqq" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#dhkfieosqq table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#dhkfieosqq .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#dhkfieosqq .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="package" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">package</th>
<th id="elapsed" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">elapsed</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="package" style="font-family: 'Source Sans Pro'; font-weight: 400">dplyr</td>
<td class="gt_row gt_right" headers="elapsed" style="font-family: 'Source Sans Pro'; font-weight: 400">7.03</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="package" style="font-family: 'Source Sans Pro'; font-weight: 400">dtplyr</td>
<td class="gt_row gt_right" headers="elapsed" style="font-family: 'Source Sans Pro'; font-weight: 400">1.30</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="package" style="font-family: 'Source Sans Pro'; font-weight: 400">collapse</td>
<td class="gt_row gt_right" headers="elapsed" style="font-family: 'Source Sans Pro'; font-weight: 400">1.02</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="package" style="font-family: 'Source Sans Pro'; font-weight: 400">data.table</td>
<td class="gt_row gt_right" headers="elapsed" style="font-family: 'Source Sans Pro'; font-weight: 400">0.67</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="package" style="font-family: 'Source Sans Pro'; font-weight: 400">tidyfast</td>
<td class="gt_row gt_right" headers="elapsed" style="font-family: 'Source Sans Pro'; font-weight: 400">0.47</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>We can see that all options are notable improvements on <span class="pack">dplyr</span>. <span class="pack">tidyfast</span> is a little optimistic, as it can count but does not appear to do a summary operation like means or sums.</p>
</section>
<section id="count" class="level3">
<h3 class="anchored" data-anchor-id="count">Count</h3>
<p>To make things more evenly matched, we’ll just do a simple grouped count. In the following, I add a different option for <span class="pack">dplyr</span> if all we want are group sizes. In addition, you have to ‘collect’ the data for a <span class="pack">dtplyr</span> object, otherwise the resulting object is not actually a usable tibble, and we don’t want to count the timing until it actually performs the operation. You can do this with the <code>collect</code> function or <code>as_tibble</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">data</span>(flights, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">package =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nycflights13'</span>)</span>
<span id="cb21-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(flights)</span>
<span id="cb21-3"></span>
<span id="cb21-4">flights_dtp <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lazy_dt</span>(flights)</span>
<span id="cb21-5"></span>
<span id="cb21-6">flights_dt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.table</span>(flights)</span>
<span id="cb21-7"></span>
<span id="cb21-8">bm_count_flights <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bench<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mark</span>(</span>
<span id="cb21-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dplyr_base =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">count</span>(flights, arr_time),</span>
<span id="cb21-10">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dtplyr     =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">collect</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">count</span>(flights_dt, arr_time)),</span>
<span id="cb21-11">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tidyfast   =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dt_count</span>(flights_dt, arr_time),</span>
<span id="cb21-12">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data.table =</span> flights_dt[, .(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> .N), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> arr_time],</span>
<span id="cb21-13">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iterations =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>,</span>
<span id="cb21-14">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">check =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb21-15">)</span></code></pre></div></div>
</div>
<p>Here are the results. It’s important to note the memory as well as the time. The faster functions here are taking a bit more memory to do it. If dealing with very large data this could be more important if operations timings aren’t too different.</p>
<div class="cell">
<div class="cell-output-display">
<div id="ezjcsmcqjx" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#ezjcsmcqjx table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#ezjcsmcqjx .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#ezjcsmcqjx .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="expression" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">expression</th>
<th id="min" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">min</th>
<th id="median" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median</th>
<th id="mem_alloc" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_alloc</th>
<th id="median_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">median_relative</th>
<th id="mem_relative" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">mem_relative</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">data.table</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">2ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">2.4ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">9.07MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.5</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">tidyfast</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">2ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">3.3ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">9.05MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.38</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.49</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dplyr_gs</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">3.7ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">4ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">6.06MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.65</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1</td>
</tr>
<tr class="even">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dtplyr</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">3.5ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">4.2ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">9.06MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.73</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.5</td>
</tr>
<tr class="odd">
<td class="gt_row gt_left" headers="expression" style="font-family: 'Source Sans Pro'; font-weight: 400">dplyr_base</td>
<td class="gt_row gt_left" headers="min" style="font-family: 'Source Sans Pro'; font-weight: 400">9.3ms</td>
<td class="gt_row gt_left" headers="median" style="font-family: 'Source Sans Pro'; font-weight: 400">10.5ms</td>
<td class="gt_row gt_left" headers="mem_alloc" style="font-family: 'Source Sans Pro'; font-weight: 400">6.12MB</td>
<td class="gt_row gt_right" headers="median_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">4.31</td>
<td class="gt_row gt_right" headers="mem_relative" style="font-family: 'Source Sans Pro'; font-weight: 400">1.01</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
<p>Just for giggles I did the same in Python with a <span class="pack">pandas</span> <code>DataFrame</code>, and depending on how you go about it you could be notably slower than all these methods, or less than half the standard <span class="pack">dplyr</span> approach. Unfortunately I can’t reproduce it here<sup>3</sup>, but I did run it on the same machine using a <code>df.groupby().size()</code> approach to create the same type of data frame. Things get worse as you move to something not as simple, like summarizing with a custom function, even if that custom function is still simple arithmetic.</p>
<p>A lot of folks that use Python primarily still think R is slow, but that is mostly just a sign that they don’t know how to effectively program with R for data science. I know folks who use Python more, but also use tidyverse, and I use R more but also use pandas quite a bit. It’s not really a debate - tidyverse is easier, less verbose, and generally faster relative to pandas, especially for more complicated operations. If you start using tools like <span class="pack">data.table</span>, then there is really no comparison for speed and efficiency. You can run the following for comparison.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb22-2"></span>
<span id="cb22-3"></span>
<span id="cb22-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># flights = r.flights</span></span>
<span id="cb22-5">flights <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_parquet(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'data/flights.parquet'</span>)</span>
<span id="cb22-6"></span>
<span id="cb22-7">flights.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"arr_time"</span>, as_index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>).size()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>      arr_time  size
0          1.0   201
1          2.0   164
2          3.0   174
3          4.0   173
4          5.0   206
...        ...   ...
1406    2356.0   202
1407    2357.0   207
1408    2358.0   189
1409    2359.0   222
1410    2400.0   150

[1411 rows x 2 columns]</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> test(): </span>
<span id="cb24-2">  flights.groupby(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"arr_time"</span>, as_index<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>).arr_time.count()</span>
<span id="cb24-3"> </span>
<span id="cb24-4">test()</span>
<span id="cb24-5"></span>
<span id="cb24-6"></span>
<span id="cb24-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> timeit</span>
<span id="cb24-8"></span>
<span id="cb24-9">timeit.timeit() <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># see documentation</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0.004073165997397155</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb26" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb26-1">test_result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> timeit.timeit(stmt<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"test()"</span>, setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"from __main__ import test"</span>, number <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)</span>
<span id="cb26-2"></span>
<span id="cb26-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># default result is in seconds for the total number of 100 runs</span></span>
<span id="cb26-4">test_result<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ms per run </span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>3.1555674999253824</code></pre>
</div>
</div>
</section>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>Programming is a challenge, and programming in a computationally efficient manner is even harder. Depending on your situation, you may need to switch tools or just write your own to come up with the best solution.</p>


</section>


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

<ol>
<li id="fn1"><p><span class="pack">data.table</span> modifies in place, so it technically it doesn’t have anything to fill after the first run. As a comparison, I created new columns as the filled in values, and this made almost no speed/memory difference. I also tried <code>copy(dt_missing)[...]</code>, which had a minor speed hit. I also tried using <code>setkey</code> first but that made no difference. Note also that <span class="pack">data.table</span> has <code>setnafill</code>, but this apparently has no grouping argument, so is not demonstrated.↩︎</p></li>
<li id="fn2"><p>As of this writing, I’m new to the <span class="pack">collapse</span> package, and so might be missing other uses that might be more efficient.↩︎</p></li>
<li id="fn3"><p>This is because <a href="https://github.com/rstudio/reticulate/issues/1019">reticulate still has issues with M1 out of the box</a>, and even then getting it to work can be a pain.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2022,
  author = {Clark, Michael},
  title = {Programming {Odds} \&amp; {Ends}},
  date = {2022-07-25},
  url = {https://m-clark.github.io/posts/2022-07-25-programming/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2022" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2022. <span>“Programming Odds &amp; Ends.”</span> July
25. <a href="https://m-clark.github.io/posts/2022-07-25-programming/">https://m-clark.github.io/posts/2022-07-25-programming/</a>.
</div></div></section></div> ]]></description>
  <category>programming</category>
  <guid>https://m-clark.github.io/posts/2022-07-25-programming/</guid>
  <pubDate>Mon, 25 Jul 2022 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/198R_small.png" medium="image" type="image/png" height="141" width="144"/>
</item>
<item>
  <title>Deep Learning for Tabular Data</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2022-04-01-more-dl-for-tabular/</link>
  <description><![CDATA[ 





<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>In a previous post, I offered <a href="../2021-07-15-dl-for-tabular/">a summary of several articles</a> that came out over the summer of 2021 regarding the application of deep learning (DL) methods to tabular data. DL has shown astounding success in the natural language processing, computer vision, and other fields, but when it comes to the sorts of data common in other situations, especially where data is usually smaller and of mixed source and type (e.g.&nbsp;demographic, social science, biological data), results were mostly unimpressive for complex DL architectures. In particular, it did not appear that DL methods could consistently compete with, much less consistently beat, common machine learning (ML) approaches such as gradient boosting (e.g.&nbsp;XGBoost). Here I provide a bit of an update, as another few articles have come along continuing the fight.</p>
</section>
<section id="tldr-the-meta-analysis" class="level2">
<h2 class="anchored" data-anchor-id="tldr-the-meta-analysis">TLDR: the meta-analysis</h2>
<p>I collected most of the results from the summarized articles here and those covered in the previous post to see if we come to any general conclusions about which methods are best or work best in certain settings. In the following tables, I excluded those I knew to be image data, as well as datasets where I thought results were indistinguishable across all models tested (e.g.&nbsp;less than 1% difference in accuracy). This left comparisons for 92 datasets across six articles. However, it’s important to note that these were not independent datasets or studies. For example, Gorishniy et al.&nbsp;are the source of two papers and essentially the same testing situations, and other datasets were common across papers (e.g.&nbsp;Higgs Boson). In the rare situations there was a tie, I gave the nod to boosting methods as a. the whole point is to do better than those, b. they are the easier model to implement, and c.&nbsp;they are not always given the same advantages in these studies (e.g.&nbsp;pre-processing).</p>
<section id="feature-type" class="level5">
<h5 class="anchored" data-anchor-id="feature-type">Feature Type</h5>
<p>The following shows results by feature type.</p>
<ul>
<li><em>Heterogeneous</em>: at least 10% of categorical or numeric data with the rest of the other</li>
<li><em>Minimal combo</em>: means any feature inclusion of a different type. In the second table I collapse to ‘any heterogeneous’.</li>
<li><em>Boost</em>: Any boosting method (most of the time it’s XGBoost but could include lightGBM or other variant)</li>
<li><em>MLP</em>: multilayer perceptron or some variant</li>
<li><em>DL_complex</em>: A DL method more complex than MLP and which is typically the focus of the paper</li>
</ul>
<p>The results suggest that current DL approaches’ strength is mostly with purely numeric data, and for heterogeneous data, simpler MLP or Boosting will generally prevail. I initially thought that boosting would do even better with heterogeneous data, and I still suspect that with more heterogeneous data and on more equal footing, results would tilt even more.</p>
<div class="cell">
<div id="tbl-feature-type" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-feature-type-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Feature Type
</figcaption>
<div aria-describedby="tbl-feature-type-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="tosuvyvken" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
  
  
<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false" data-bgcolor="#FFFFFF">
<thead style="border-style: none;">
<tr class="gt_col_headings header" style="border-style: none; border-top-style: none; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: none; border-bottom-width: 1px; border-bottom-color: #334422; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3;">
<th id="winner_model_type" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="text-align: left; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">winner_model_type</th>
<th id="All Cat" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">All Cat</th>
<th id="All Num" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">All Num</th>
<th id="Heterogeneous" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">Heterogeneous</th>
<th id="Min. Combo" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">Min. Combo</th>
</tr>
</thead>
<tbody class="gt_table_body" style="border-style: none; border-top-style: none; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #FFFFFF;">
<tr class="odd" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">Boost</td>
<td class="gt_row gt_right" headers="All Cat" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">2</td>
<td class="gt_row gt_right" headers="All Num" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">10</td>
<td class="gt_row gt_right" headers="Heterogeneous" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">14</td>
<td class="gt_row gt_right" headers="Min. Combo" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">6</td>
</tr>
<tr class="even" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">MLP</td>
<td class="gt_row gt_right" headers="All Cat" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">2</td>
<td class="gt_row gt_right" headers="All Num" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">4</td>
<td class="gt_row gt_right" headers="Heterogeneous" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">9</td>
<td class="gt_row gt_right" headers="Min. Combo" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">11</td>
</tr>
<tr class="odd" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">DL_complex</td>
<td class="gt_row gt_right" headers="All Cat" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">0</td>
<td class="gt_row gt_right" headers="All Num" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">22</td>
<td class="gt_row gt_right" headers="Heterogeneous" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">7</td>
<td class="gt_row gt_right" headers="Min. Combo" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">5</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output-display">
<div id="rlnosnpqee" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
  
  
<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false" data-bgcolor="#FFFFFF">
<thead style="border-style: none;">
<tr class="gt_col_headings header" style="border-style: none; border-top-style: none; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: none; border-bottom-width: 1px; border-bottom-color: #334422; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3;">
<th id="winner_model_type" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="text-align: left; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">winner_model_type</th>
<th id="All Cat" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">All Cat</th>
<th id="All Num" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">All Num</th>
<th id="Any Combo" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">Any Combo</th>
</tr>
</thead>
<tbody class="gt_table_body" style="border-style: none; border-top-style: none; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #FFFFFF;">
<tr class="odd" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">Boost</td>
<td class="gt_row gt_right" headers="All Cat" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">2</td>
<td class="gt_row gt_right" headers="All Num" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">10</td>
<td class="gt_row gt_right" headers="Any Combo" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">20</td>
</tr>
<tr class="even" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">MLP</td>
<td class="gt_row gt_right" headers="All Cat" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">2</td>
<td class="gt_row gt_right" headers="All Num" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">4</td>
<td class="gt_row gt_right" headers="Any Combo" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">20</td>
</tr>
<tr class="odd" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">DL_complex</td>
<td class="gt_row gt_right" headers="All Cat" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">0</td>
<td class="gt_row gt_right" headers="All Num" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">22</td>
<td class="gt_row gt_right" headers="Any Combo" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">12</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</figure>
</div>
</div>
</section>
<section id="samplefeature-set-size" class="level5">
<h5 class="anchored" data-anchor-id="samplefeature-set-size">Sample/Feature Set Size</h5>
<p>The following suggests that complex DL methods are going to require a lot of data to perform better. This isn’t that surprising but the difference here is quite dramatic. Interestingly, MLP methods worked well for fewer features. N total in this case means total size reported (not just training).</p>
<div class="cell">
<div id="tbl-feature-size" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-feature-size-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;2: Sample Size
</figcaption>
<div aria-describedby="tbl-feature-size-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="mirdciqoyl" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
  
  
<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false" data-bgcolor="#FFFFFF">
<thead style="border-style: none;">
<tr class="gt_col_headings header" style="border-style: none; border-top-style: none; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: none; border-bottom-width: 1px; border-bottom-color: #334422; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3;">
<th id="winner_model_type" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="text-align: left; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">winner_model_type</th>
<th id="N features" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">N features</th>
<th id="N total" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">N total</th>
</tr>
</thead>
<tbody class="gt_table_body" style="border-style: none; border-top-style: none; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #FFFFFF;">
<tr class="odd" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">Boost</td>
<td class="gt_row gt_right" headers="N features" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">209</td>
<td class="gt_row gt_right" headers="N total" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">133,309</td>
</tr>
<tr class="even" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">DL_complex</td>
<td class="gt_row gt_right" headers="N features" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">207</td>
<td class="gt_row gt_right" headers="N total" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">530,976</td>
</tr>
<tr class="odd" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">MLP</td>
<td class="gt_row gt_right" headers="N features" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">114</td>
<td class="gt_row gt_right" headers="N total" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">114,164</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</figure>
</div>
</div>
</section>
<section id="target-type" class="level5">
<h5 class="anchored" data-anchor-id="target-type">Target Type</h5>
<p>In the following we compare binary (bin), multiclass (mc), and numeric (num) target results<sup>1</sup>, but there’s no strong conclusion for this. The main thing to glean from this is that these papers do not test numeric targets nearly enough. Across dozens of disciplines and countless datasets that I’ve come across in various settings, if anything, this ratio should be reversed.</p>
<div class="cell">
<div id="tbl-target" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-target-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;3: Target Type
</figcaption>
<div aria-describedby="tbl-target-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="vcdexbjhnr" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
  
  
<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false" data-bgcolor="#FFFFFF">
<thead style="border-style: none;">
<tr class="gt_col_headings header" style="border-style: none; border-top-style: none; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: none; border-bottom-width: 1px; border-bottom-color: #334422; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3;">
<th id="winner_model_type" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="text-align: left; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">winner_model_type</th>
<th id="bin" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">bin</th>
<th id="mc" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">mc</th>
<th id="num" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">num</th>
</tr>
</thead>
<tbody class="gt_table_body" style="border-style: none; border-top-style: none; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #FFFFFF;">
<tr class="odd" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">Boost</td>
<td class="gt_row gt_right" headers="bin" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">17</td>
<td class="gt_row gt_right" headers="mc" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">10</td>
<td class="gt_row gt_right" headers="num" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">5</td>
</tr>
<tr class="even" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">DL_complex</td>
<td class="gt_row gt_right" headers="bin" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">17</td>
<td class="gt_row gt_right" headers="mc" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">11</td>
<td class="gt_row gt_right" headers="num" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">6</td>
</tr>
<tr class="odd" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">MLP</td>
<td class="gt_row gt_right" headers="bin" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">10</td>
<td class="gt_row gt_right" headers="mc" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">14</td>
<td class="gt_row gt_right" headers="num" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">2</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</figure>
</div>
</div>
</section>
<section id="combinations" class="level5">
<h5 class="anchored" data-anchor-id="combinations">Combinations</h5>
<p>In the following I look at any heterogeneous, smaller data (N &lt; 200,000). A complex DL model will likely not do great in this setting.</p>
<div class="cell">
<div id="tbl-combo" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-combo-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;4: Combinations
</figcaption>
<div aria-describedby="tbl-combo-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="zwkawpqpfc" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
  
  
<table class="gt_table cell caption-top table table-sm table-striped small" data-quarto-bootstrap="false" data-bgcolor="#FFFFFF">
<thead style="border-style: none;">
<tr class="gt_col_headings header" style="border-style: none; border-top-style: none; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: none; border-bottom-width: 1px; border-bottom-color: #334422; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3;">
<th id="winner_model_type" class="gt_col_heading gt_columns_bottom_border gt_left" data-quarto-table-cell-role="th" style="text-align: left; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">winner_model_type</th>
<th id="n" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="text-align: right; border-style: none; background-color: #FFFFFF; font-size: 12px; font-weight: normal; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: bottom; padding-top: 5px; padding-bottom: 6px; padding-left: 5px; padding-right: 5px; overflow-x: hidden; font-variant-numeric: tabular-nums; color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase;" scope="col" data-bgcolor="#FFFFFF" data-valign="bottom">n</th>
</tr>
</thead>
<tbody class="gt_table_body" style="border-style: none; border-top-style: none; border-top-width: 2px; border-top-color: #D3D3D3; border-bottom-style: solid; border-bottom-width: 2px; border-bottom-color: #FFFFFF;">
<tr class="odd" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">Boost</td>
<td class="gt_row gt_right" headers="n" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">19</td>
</tr>
<tr class="even" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">DL_complex</td>
<td class="gt_row gt_right" headers="n" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">8</td>
</tr>
<tr class="odd" style="border-style: none;">
<td class="gt_row gt_left" headers="winner_model_type" style="text-align: left; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">MLP</td>
<td class="gt_row gt_right" headers="n" style="text-align: right; border-style: none; padding-top: 7px; padding-bottom: 7px; padding-left: 5px; padding-right: 5px; margin: 10px; border-top-style: solid; border-top-width: 1px; border-top-color: #D3D3D3; border-left-style: none; border-left-width: 1px; border-left-color: #D3D3D3; border-right-style: none; border-right-width: 1px; border-right-color: #D3D3D3; vertical-align: middle; overflow-x: hidden; font-variant-numeric: tabular-nums; font-family: 'Source Sans Pro'; font-weight: 400;" data-valign="middle">19</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>Now, on to the details of some of the recent results that were included.</p>
</section>
</section>
<section id="on-embeddings-for-numerical-features-in-tabular-deep-learning" class="level2">
<h2 class="anchored" data-anchor-id="on-embeddings-for-numerical-features-in-tabular-deep-learning">On Embeddings for Numerical Features in Tabular Deep Learning</h2>
<ul>
<li><em>Authors</em>: Gorishniy, Rubachev, &amp; Babenko</li>
<li><em>Year</em>: 2022</li>
<li><a href="https://arxiv.org/abs/2203.05556">Arxiv Link</a></li>
</ul>
<section id="overview" class="level3">
<h3 class="anchored" data-anchor-id="overview">Overview</h3>
<p><span class="citation" data-cites="gorishniy2022embeddings">Gorishniy et al. (2022)</span> pit several architectures against one another, such as standard multilayer perceptron (MLP), ResNet, and their own transformer approach (see <span class="citation" data-cites="gorishniy2021tabular">Gorishniy et al. (2021)</span>). Their previous work, which was summarized in my earlier post, was focused on the architecture, while here they focus on <em>embedding</em> approaches. The primary idea is to take the value of some feature and expand it to some embedding space, then use the embedding in lieu of the raw feature. It can essentially be seen as a pre-processing task.</p>
<p>One approach they use is <em>piecewise linear encoding</em> (PLE), which they at one point describe as ‘a continuous alternative to the one-hot encoding’<sup>2</sup>. Another embedding they use is basically a fourier transform.</p>
</section>
<section id="data" class="level3">
<h3 class="anchored" data-anchor-id="data">Data</h3>
<ul>
<li>12 public datasets mostly from previous works on tabular DL and Kaggle competitions.</li>
<li>Sizes were from ~10K to &gt;1M.</li>
<li>Target variables were binary, multiclass, or numeric.</li>
<li>The number of features ranged from 8 to 200.<br>
</li>
<li>9 of 12 data sets had only numeric features, two had a single categorical feature, and unfortunately, only one of these might be called truly <em>heterogeneous</em>, i.e., with a notable mix of categorical and numeric features<sup>3</sup>.</li>
</ul>
</section>
<section id="models-explored" class="level3">
<h3 class="anchored" data-anchor-id="models-explored">Models Explored</h3>
<ul>
<li><em>CatBoost</em></li>
<li><em>XGBoost</em></li>
<li><em>MLP</em>, <em>MLP*</em></li>
<li><em>ResNet</em>, <em>ResNet*</em></li>
<li><em>Transformer*</em></li>
</ul>
<p>* Using proposed embeddings</p>
</section>
<section id="quick-summary" class="level3">
<h3 class="anchored" data-anchor-id="quick-summary">Quick Summary</h3>
<ul>
<li>A mix of results with no clear/obvious winners (results are less distinguishable if one keeps to the actual precision of the performance metrics, and even less so if talking about statistical differences in performance).
<ul>
<li>Several datasets showed no practical difference across any model (e.g.&nbsp;all accuracy results within ~.01 of each other).</li>
</ul></li>
<li>Embedding-based approaches generally tend to improve over their non-embedding counter parts (e.g.&nbsp;MLP + embedding &gt; MLP), this was possibly the clearest result of the paper.</li>
<li>I’m not sure we could say the same for ResNet, where results were similar with or without embedding</li>
<li>XGBoost was best on the one truly heterogeneous dataset.</li>
</ul>
<!-- see code/dl_for_tabular/tbl_processing.rmd -->
<!-- ![Results Table](../../img/dl-for-tab/primary_results.png)  -->
<p>In general this was an interesting paper, and I liked the simple embedding approaches used. It was nice to see that they may be useful in some contexts. The fourier transform is something that analysts (including our team at <a href="https://strong.io">Strong</a>) have used in boosting, so I’m a bit curious why they don’t do Boosting + embeddings for comparison for that or both embedding types. These embeddings can be seen as a pre-processing step, so nothing would keep someone from using them for any model.</p>
<p>Another interesting aspect was how little difference there was in model performance. It seemed half the datasets showed extremely small differences between any model type.</p>
</section>
</section>
<section id="saint-improved-neural-networks-for-tabular-data-via-row-attention-and-contrastive-pre-training" class="level2">
<h2 class="anchored" data-anchor-id="saint-improved-neural-networks-for-tabular-data-via-row-attention-and-contrastive-pre-training">SAINT: Improved neural networks for tabular data via row attention and contrastive pre-training</h2>
<ul>
<li><em>Authors</em>: Somepalli, Goldblum, Schwarzschild, Bayan-Bruss, &amp; Goldstein</li>
<li><em>Year</em>: 2021</li>
<li><a href="https://arxiv.org/abs/2106.01342">Arxiv Link</a></li>
</ul>
<section id="overview-1" class="level3">
<h3 class="anchored" data-anchor-id="overview-1">Overview</h3>
<p>This paper applies BERT-style attention over rows and columns, along with embedding/data augmentation. They distinguish the standard attention over features, with intersample attention of rows. In addition, they use <em>CutMix</em> for data augmentation (originally devised for images), which basically combines pairs of observations to create a new observation<sup>4</sup>. Their model is called <em>SAINT</em>, the Self-Attention and Intersample Attention Transformer.</p>
</section>
<section id="data-1" class="level3">
<h3 class="anchored" data-anchor-id="data-1">Data</h3>
<ul>
<li>16 data sets</li>
<li>All classification, 2 multiclass</li>
<li>6 are heterogeneous, 2 notably so</li>
<li>Sizes 200 to almost 500K</li>
</ul>
</section>
<section id="models-explored-1" class="level3">
<h3 class="anchored" data-anchor-id="models-explored-1">Models Explored</h3>
<ul>
<li>Logistic Regression (!)</li>
<li>Random Forest</li>
<li>Boosting
<ul>
<li>CatBoost</li>
<li>XGBoost</li>
<li>LightGBM</li>
</ul></li>
<li>MLP</li>
<li>TabNet</li>
<li>VIME</li>
<li>TabTransformer</li>
<li>SAINT</li>
</ul>
</section>
<section id="quick-summary-1" class="level3">
<h3 class="anchored" data-anchor-id="quick-summary-1">Quick Summary</h3>
<ul>
<li><p>It seems the SAINT does quite well on some of the data, and average AUROC across all datasets is higher than XGB.</p></li>
<li><p>Main table shows only 9 datasets though, which they call ‘representative’ but it’s not clear what that means when you only have 16 to start. One dataset showed near perfect classification for all models so will not be considered. Of the 15 total remaining:</p>
<ul>
<li>SAINT wins 10 (including 3 heterogeneous)</li>
<li>Boosting wins 5 (including 2 heterogeneous)</li>
</ul></li>
<li><p>SAINT benefits from <em>data augmentation</em>. This could have been applied to any of the other models, but doesn’t appear to have been done.</p></li>
<li><p>At least they also used some form of logistic regression as a baseline, though I couldn’t find details on its implementation (e.g.&nbsp;regularization, including interactions). I don’t think this sort of simple baseline is utilized enough.</p></li>
</ul>
<p>This is an interesting result, but somewhat dampened by lack of including numeric targets and more heterogeneous data. The authors include small data settings which is great, and are careful to not generalize despite some good results, which I can appreciate.</p>
<p>I really like the fact they also compare a simple logistic regression to these models, because if you’re not able to perform notably better relative to the simplest model one could do, then why would we care? The fact that logistic regression is at times competitive and even beats boosting/SAINT methods occasionally gives me pause though. Perhaps some of these data are not sufficiently complex to be useful in distinguishing these methods? It is realistic though. While it’s best not to assume as such, sometimes a linear model is appropriate given the features and target at hand.</p>
</section>
</section>
<section id="self-attention-between-datapoints-going-beyond-individual-input-output-pairs-in-deep-learning" class="level2">
<h2 class="anchored" data-anchor-id="self-attention-between-datapoints-going-beyond-individual-input-output-pairs-in-deep-learning">Self-Attention Between Datapoints: Going Beyond Individual Input-Output Pairs in Deep Learning</h2>
<ul>
<li><em>Authors</em>: Kossen, Band, Lyle, Gomez, Rainforth, &amp; Gal</li>
<li><em>Year</em>: 2021</li>
<li><a href="https://arxiv.org/abs/2106.02584">Arxiv Link</a></li>
</ul>
<section id="overview-2" class="level3">
<h3 class="anchored" data-anchor-id="overview-2">Overview</h3>
<p>This paper introduces <em>Non-Parametric Transformers</em>, which focus on holistic processing of multiple inputs, and attempts to consider an entire dataset as input as opposed to a single row. Their model attempts to learn relations between data points to aid prediction. They use a mask to identify prediction points from the non-masked data, i.e.&nbsp;the entire <img src="https://latex.codecogs.com/png.latex?X_%7B%5Ctextrm%7Bnot%20masked%7D%7D%5Ctext%7B%20%7D"> data used to predict <img src="https://latex.codecogs.com/png.latex?X_%7B%5Ctextrm%7Bmasked%7D%7D%5Ctext%7B%20%7D">. The X matrix actually includes the target (also masked vs.&nbsp;not). At prediction, the model is able to make use of the correlations of inputs of training to ultimately make a prediction.</p>
</section>
<section id="data-2" class="level3">
<h3 class="anchored" data-anchor-id="data-2">Data</h3>
<ul>
<li>10 datasets from UCI, 2 are image (CIFAR MNIST)</li>
<li>4 binary, 2 multiclass, 4 numeric targets</li>
</ul>
</section>
<section id="models-explored-2" class="level3">
<h3 class="anchored" data-anchor-id="models-explored-2">Models Explored</h3>
<ul>
<li>NPT</li>
<li>Boosting
<ul>
<li>GB</li>
<li>XGB</li>
<li>CatBoost</li>
<li>LightGBM</li>
</ul></li>
<li>Random Forest</li>
<li>TabNet</li>
<li>Knn</li>
</ul>
</section>
<section id="quick-summary-2" class="level3">
<h3 class="anchored" data-anchor-id="quick-summary-2">Quick Summary</h3>
<ul>
<li>Good performance of these models, but not too different from best boosting model for any type of data.
<ul>
<li>NPT best on binary classification, but similar to CatBoost</li>
<li>Same as XGB and similar to MLP on multiclass</li>
<li>Boosting slightly better on numeric targets, but NPT similar</li>
</ul></li>
<li>As seen several times now, TabNet continues to underperform</li>
<li>k-nn regression worst (not surprising)</li>
</ul>
<p>When I first read the abstract where they say “We challenge a common assumption underlying most supervised deep learning: that a model makes a prediction depending only on its parameters and the features of a single input.”, I immediately was like ‘What about this, that, and those?’. The key phrase was ‘deep learning’, because the authors note later that this has a very long history in the statistical modeling realm. I was glad to see in their background of the research that they explicitly noted the models that came to my mind, like gaussian processes, kernel regression, etc. Beyond that, many are familiar with techniques like knn-regression and predictive mean matching, so it’s definitely not new to consider more than a single data point for prediction. I thought it was good of them to add k-nn regression to the model mix, even though it was not going to do well compared to the other approaches.</p>
<p>Though the author’s acknowledge a clear thread/history here, I’m not sure this result is the fundamental shift they claim, versus a further extension/expansion into the DL domain. Even techniques that may work on a single input at a time may ultimately be taking advantage of correlations among the inputs (e.g.&nbsp;spatial correlations in images). Also, automatic learning of feature interactions is standard even in basic regularized regression settings, but here their focus is on observation interactions (but see k-nn regression).</p>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>In the two reviews on DL for tabular data that I’ve done, it appears there is more work in store for DL methods applied to tabular data. While it’d be nice to have any technique that would substantially improve prediction for such settings, I do have a suspicion results are likely rosier than they are, since that is just about the case for any newly touted technique, and at least in some cases, I don’t think we’re even making apple to apple comparisons.</p>
<p>That said, I do feel like some ground has been made for DL applications for tabular data, in that architectures can now more consistently performing as well as boosting methods in certain settings, especially if we include MLP. In the end though, results don’t appear strong enough to warrant a switch from boosting for truly heterogeneous data, or even tabular data in general. I feel like someday we’ll maybe have a breakthrough, but in the meantime, we can just agree that messy data is hard stuff to model, and the best tool is whichever one works for your specific situation.</p>
</section>
<section id="guidelines-for-future-research" class="level2">
<h2 class="anchored" data-anchor-id="guidelines-for-future-research">Guidelines for future research</h2>
<p>I was thinking about what would be a convincing result, the type of setting and setup where if a DL technique was consistently performing statistically better than boosting methods, I’d be impressed. So I’ve made a list of things I’d like to see more of, and which would make for a better story if the DL method were to beat out other techniques.</p>
<ul>
<li><p>Always use heterogeneous data. For giggles let’s say 20%+ of the minority feature type.</p></li>
<li><p>Features should at least be minimally correlated, if not notably so.</p></li>
<li><p>Image data results are not interesting (why would we use boosting on this in practice?).</p></li>
<li><p>Numeric targets should at least be as much of focus as categorical targets.</p></li>
<li><p>Include ‘small’ datasets.</p></li>
<li><p>Include very structured data (e.g.&nbsp;clustered with repeated observations, geographical points, time series).</p></li>
<li><p>Use a flexible generalized additive or similar penalized regression with interactions as a baseline statistical model.</p></li>
<li><p>Maybe add survival targets to the mix.</p></li>
<li><p>If using a pre-processing step that is done outside of modeling, this likely should be applied to non-DL methods for better comparison, especially, if we’re only considering predictive accuracy and don’t care too much about interpretation.</p></li>
<li><p>Note your model variants <strong>before</strong> analyzing any data. Tweaking/torturing model architecture after results don’t pan out is akin to p-hacking in the statistical realm, and likewise wastes both researcher and reader’s time.</p></li>
<li><p>Regarding results…</p>
<ul>
<li>Don’t claim differences that you don’t have precision to do so, or at least back them up with an actual statistical test.</li>
<li>If margin of error in the metrics is overlapping, while statistically they could be different, practically they probably aren’t to most readers. Don’t make a big deal about it.</li>
<li>It is unlikely anyone will be interested in three decimal place differences for rmse/acc type metrics, and statistically, results often don’t even support two decimal precision.</li>
<li>Report how you are obtaining uncertainty in any error estimates.</li>
<li>If straightforward, try to give an estimate of total tuning/run times.</li>
</ul></li>
<li><p>With the datasets</p>
<ul>
<li>Name datasets exactly how they are named at the source you obtained them from, provide direct links</li>
<li>Provide a breakdown for both feature and target types</li>
<li>Provide clear delineation of total/training/validation/test sizes</li>
</ul></li>
</ul>



</section>


<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-gorishniy2022embeddings" class="csl-entry">
Gorishniy, Yura, Ivan Rubachev, and Artem Babenko. 2022. <span>“On Embeddings for Numerical Features in Tabular Deep Learning.”</span> <em>arXiv Preprint arXiv:2203.05556</em>.
</div>
<div id="ref-gorishniy2021tabular" class="csl-entry">
Gorishniy, Yuri, Ivan Rubachev, Valentin Khrulkov, and Artem Babenko. 2021. <span>“Revisiting Deep Learning Models for Tabular Data.”</span> <em>arXiv Preprint arXiv:2106.11959</em>.
</div>
<div id="ref-kadra2021tabular" class="csl-entry">
Kadra, Arlind, Marius Lindauer, Frank Hutter, and Josif Grabocka. 2021. <span>“Regularization Is All You Need: Simple Neural Nets Can Excel on Tabular Data.”</span> <em>arXiv Preprint arXiv:2106.11189</em>.
</div>
<div id="ref-shwartz2021tabular" class="csl-entry">
Shwartz-Ziv, Ravid, and Amitai Armon. 2021. <span>“Tabular Data: Deep Learning Is Not All You Need.”</span> <em>arXiv Preprint arXiv:2106.03253</em>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>I don’t refer to numeric targets as ‘regression’ because that’s silly for so many reasons. 😄↩︎</p></li>
<li id="fn2"><p>A quick look suggests it’s not too dissimilar from a <a href="https://en.wikipedia.org/wiki/B-spline#Definition">b-spline</a>.↩︎</p></li>
<li id="fn3"><p>I’ll let you go ahead and make your own prediction about which method was best on that data set.↩︎</p></li>
<li id="fn4"><p>It’s not clear to me how well this CutUp approach would actually preserve feature correlations. My gut tells me the feature correlations of this approach would be reduced relative to the observed, since the variability of the new observations is likely reduced. This ultimately may not matter for predictive purposes or their ultimate use in embeddings. However, I wonder if something like SMOTE, random (bootstrap) sampling, other DL methods like autoencoders, or similar approaches might do the same or better.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2022,
  author = {Clark, Michael},
  title = {Deep {Learning} for {Tabular} {Data}},
  date = {2022-05-01},
  url = {https://m-clark.github.io/posts/2022-04-01-more-dl-for-tabular/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2022" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2022. <span>“Deep Learning for Tabular Data.”</span> May
1. <a href="https://m-clark.github.io/posts/2022-04-01-more-dl-for-tabular/">https://m-clark.github.io/posts/2022-04-01-more-dl-for-tabular/</a>.
</div></div></section></div> ]]></description>
  <category>deep learning</category>
  <category>machine learning</category>
  <guid>https://m-clark.github.io/posts/2022-04-01-more-dl-for-tabular/</guid>
  <pubDate>Sun, 01 May 2022 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/nnet.png" medium="image" type="image/png" height="120" width="144"/>
</item>
<item>
  <title>Double Descent</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2021-10-30-double-descent/</link>
  <description><![CDATA[ 





<p>A co-worker passed along a recent article <span class="citation" data-cites="dar2021farewell">(Dar et al. 2021)</span> on the topic of <em>double descent</em> in machine learning. I figured I’d summarize some key points I came across while perusing it and some referenced articles. In addition, I’ll provide an accessible example demonstrating the phenomenon.</p>
<section id="what-is-double-descent" class="level2">
<h2 class="anchored" data-anchor-id="what-is-double-descent">What is double descent?</h2>
<section id="bias-variance-trade-off" class="level3">
<h3 class="anchored" data-anchor-id="bias-variance-trade-off">Bias-variance trade-off</h3>
<p>To understand double descent you have to revisit the concept of the <em>bias-variance trade-off</em>. Without going into too much detail, the main idea with it is that having an overly complex model leads to <em>overfitting</em> the training data, which results in worse prediction on new data, at least relative to what simpler models would have done. The classic figure looks like the following, where blue is the <em>training error</em> and the red is the <em>test error</em>. Thin lines represent one path of complexity (e.g.&nbsp;across a random sample of the data), while the thicker lines are the average at a particular point of model complexity.</p>
<p><img src="https://m-clark.github.io/img/double-descent/biasvar2.svg" class="img-fluid"></p>
<p>If we don’t have a sufficiently complex model, both training and test error will be poor, the case of <em>underfitting</em>. Our model is a poor approximation of the true underlying function, and predicts poorly on data both seen and unseen. When we have too much model complexity relative to the size of our data (e.g.&nbsp;more covariates, nonlinear effects, interactions, etc.), we pass into the overfit situation. Essentially, while our model function would result in a decrease in error with the data it’s trained on (lower bias as it better approximates the true underlying function), with too much complexity, you’d also eventually have notable changes in prediction (high variance) with any slight deviation in the underlying training data. We can even get to the point where we fit the training data perfectly, but it will be overly susceptible to the noise in the data, and not do well with unseen observations.</p>
<p>To combat this, we usually attempt to find a balance between overly simple and overly complex models. This would be the point where test error is among its lowest point for a desirable level of complexity (e.g.&nbsp;around 20-25 df in the figure above), before it begins to rise again. This may be accomplished more explicitly, for example, picking a model through cross-validation, or more implicitly, for example, through regularization (<span class="citation" data-cites="belkin2019reconciling">Belkin et al. (2019)</span>). For more detail on the bias-variance trade-off, you can look at the exposition in the main article noted above, <a href="https://m-clark.github.io/introduction-to-machine-learning/concepts.html#bias-variance-tradeoff">my document here</a>, or any number of places, as it is an extremely well-known idea in machine learning.</p>
</section>
<section id="double-descent" class="level3">
<h3 class="anchored" data-anchor-id="double-descent">Double Descent</h3>
<p>The funny thing is, it turns out that the above actually only applies to a specific scenario, one which we will call <em>underparameterized</em> models. We can simplify this notion by just thinking of the case where the number of our parameters to estimate is less than or equal to the number of observations we have to work with. Nowadays though, it’s not uncommon to have what we’d call <em>overparameterized</em> models, such as random forests and neural networks, sometimes with even billions of parameters, far exceeding the data size. In this scenario, when we revisit the trade-off, something unusual happens!</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://m-clark.github.io/img/double-descent/double_descent_concept.png" class="img-fluid figure-img"></p>
<figcaption>Figure from <span class="citation" data-cites="dar2021farewell">Dar et al. (2021)</span></figcaption>
</figure>
</div>
<p>Such models may have near zero training error, yet do well on unseen data. As we increase complexity, we see something like a second bias-variance trade-off beyond the point where the data is perfectly fit (interpolated). This point is where model complexity (e.g.&nbsp;in terms of number of parameters) <em>p</em> equals the number of observations <em>N</em>, and this is where the realm of the overparameterized models begins. Now test error begins to drop again with increasing complexity.</p>
</section>
</section>
<section id="an-example" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="an-example">An example</h2>
<p>I thought it would be amusing to try this with the classic <code>mtcars</code> data set available in base R. With this data, our goal will be to predict fuel consumption in miles per gallon (<code>mpg</code>). First we will split the data into training and test components. We create a model where our number of parameters (<code>p</code>), in this case standard regression coefficients, will equal the number of observations (<code>N</code>). Some of the more technically savvy will know that if the number of features and/or parameters to estimate <code>p</code> equals the number of observations <code>N</code>, a standard linear regression model will fit the data perfectly<sup>1</sup>, demonstrated below.</p>

<div class="no-row-height column-margin column-container"><div class="">
<p>If not familiar, the <code>mtcars</code> object is a data frame that comprises fuel consumption and 10 aspects of automobile design and performance for 32 automobiles (1973–74 models).</p>
</div></div><div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1">nc <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ncol</span>(mtcars) </span>
<span id="cb1-2">nr <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> nc</span>
<span id="cb1-3">fit_perfect <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lm</span>(mpg <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> ., mtcars[<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>nr, ])</span>
<span id="cb1-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># summary(fit_perfect) # not shown, all inferential estimates are NaN</span></span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-10-30-double-descent/index_files/figure-html/vis-fit-perfect-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Now let’s look at the test error, our prediction on the unseen data we didn’t use in fitting the model. When we do, we see the usual bias-variance trade-off. Our generalizability capabilities have plummeted, as we have overfit the training data and were unable to accommodate unseen observations. We are even predicting negative mpg in some cases!</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-10-30-double-descent/index_files/figure-html/vis-fit-perfect-test-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<section id="p-n" class="level3">
<h3 class="anchored" data-anchor-id="p-n">p ≤ N</h3>
<p>Let’s extend the demonstration more fully. We now create models of increasing complexity, starting with an intercept only model (i.e.&nbsp;just using the mean for prediction), to one where all other columns (10) in the data are predictors. Here I repeatedly sampled <code>mtcars</code> of size <img src="https://latex.codecogs.com/png.latex?N%20=%2010"> for training, the remainder for test, and also shuffled the columns each time, doing so for a total of 250 times<sup>2</sup>. Here is the result- the classic bias variance trade-off curve. The larger dot shows the test error minimum, at about 3 covariates (plus intercept). The vertical line denotes our point of interpolation.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://m-clark.github.io/img/double-descent/dd_mtcars_under.svg" class="img-fluid figure-img"></p>
<figcaption>Double Descent in the underparameterized setting.</figcaption>
</figure>
</div>
</section>
<section id="p-n-1" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="p-n-1">p &gt; N</h3>
<p>So with one of the simpler data sets around we were able to demonstrate the bias-variance trade-off clearly. But now let’s try overparameterized models! We don’t need anything fancy or complicated to do this, so for our purposes, I’m just going to add cubic spline basis expansions for the <code>wt</code>, <code>disp</code>, and <code>hp</code> features<sup>3</sup>. This will definitely be enough to put us in a situation where we have more parameters than data, i.e.&nbsp;p &gt; N, but doesn’t make things too abstract<sup>4</sup>.</p>
<p>The basic linear model approach we might typically use fails to estimate the additional parameters in this situation, so we need a different estimator. Some are familiar with penalized regression techniques such as <em>lasso</em> and <em>ridge</em> regression, and we could use those here. However, I’ll use <em>ridgeless regression</em>, as depicted in <span class="citation" data-cites="hastie2019surprises">Hastie et al. (2019)</span>, and which, like ridge regression, is a straightforward variant of the usual least squares regression<sup>5</sup>. I estimate the coefficients/weights on the training data, and make predictions for the training and test set, calculating their respective errors. Here is an example of the primary function used.</p>
<div class="cell" data-code_folding="true">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">fit_ridgeless <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(X_train, y, X_test, y_test){</span>
<span id="cb2-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># get the coefficient estimates</span></span>
<span id="cb2-3">  b <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pseudo_inv</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crossprod</span>(X_train)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%*%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crossprod</span>(X_train, y)</span>
<span id="cb2-4">  </span>
<span id="cb2-5">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># get training/test predictions</span></span>
<span id="cb2-6">  predictions_train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> X_train <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%*%</span> b</span>
<span id="cb2-7">  predictions_test  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> X_test <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%*%</span> b</span>
<span id="cb2-8">  </span>
<span id="cb2-9">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># get training/test error</span></span>
<span id="cb2-10">  rmse_train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sqrt</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>((y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> predictions_train[,<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;">2</span>))</span>
<span id="cb2-11">  rmse_test  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sqrt</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>((y_test <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> predictions_test[,<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;">2</span>))</span>
<span id="cb2-12">  </span>
<span id="cb2-13">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># return result</span></span>
<span id="cb2-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb2-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b =</span> b,</span>
<span id="cb2-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">predictions_train =</span> predictions_train,</span>
<span id="cb2-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">predictions_test  =</span> predictions_test,</span>
<span id="cb2-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rmse_train =</span> rmse_train,</span>
<span id="cb2-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rmse_test  =</span> rmse_test</span>
<span id="cb2-20">  )</span>
<span id="cb2-21">}</span></code></pre></div></div>
</div>
<p>We can test the function as follows with as little as 10 observations, where p (all predictor coefficients plus intercept = 11 parameters) is greater than N (10). This demonstrates that the ridgeless approach can provide an estimate for all the parameters (unlike the standard <code>lm</code> function), and we also see very low training error, but relatively high test error (in terms of the root mean square error.)</p>
<div class="cell" data-code_folding="true">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span></span>
<span id="cb3-2"></span>
<span id="cb3-3">X <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, mtcars[, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]))</span>
<span id="cb3-4">y <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> mtcars<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>mpg <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># mpg is the first column</span></span>
<span id="cb3-5"></span>
<span id="cb3-6">X_train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> X[<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>n, ]</span>
<span id="cb3-7">y_train <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> mtcars<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>mpg[<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>n]</span>
<span id="cb3-8">X_test  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> X[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n),]</span>
<span id="cb3-9">y_test  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> y[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>n)]</span>
<span id="cb3-10"></span>
<span id="cb3-11">result <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fit_ridgeless</span>(X_train, y_train, X_test, y_test)</span></code></pre></div></div>
</div>
<div class="cell">
<div id="tbl-test-fit-ridgeless" class="cell quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl quarto-uncaptioned" id="tbl-test-fit-ridgeless-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1
</figcaption>
<div aria-describedby="tbl-test-fit-ridgeless-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div id="suklkmbrjh" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#suklkmbrjh table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

#suklkmbrjh .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#suklkmbrjh .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="b" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">b</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_right" headers="b" style="font-family: 'Source Sans Pro'; font-weight: 400">0.84</td>
</tr>
<tr class="even">
<td class="gt_row gt_right" headers="b" style="font-family: 'Source Sans Pro'; font-weight: 400">−1.69</td>
</tr>
<tr class="odd">
<td class="gt_row gt_right" headers="b" style="font-family: 'Source Sans Pro'; font-weight: 400">0.08</td>
</tr>
<tr class="even">
<td class="gt_row gt_right" headers="b" style="font-family: 'Source Sans Pro'; font-weight: 400">−0.08</td>
</tr>
<tr class="odd">
<td class="gt_row gt_right" headers="b" style="font-family: 'Source Sans Pro'; font-weight: 400">2.76</td>
</tr>
<tr class="even">
<td class="gt_row gt_right" headers="b" style="font-family: 'Source Sans Pro'; font-weight: 400">−1.29</td>
</tr>
<tr class="odd">
<td class="gt_row gt_right" headers="b" style="font-family: 'Source Sans Pro'; font-weight: 400">0.24</td>
</tr>
<tr class="even">
<td class="gt_row gt_right" headers="b" style="font-family: 'Source Sans Pro'; font-weight: 400">2.32</td>
</tr>
<tr class="odd">
<td class="gt_row gt_right" headers="b" style="font-family: 'Source Sans Pro'; font-weight: 400">3.26</td>
</tr>
<tr class="even">
<td class="gt_row gt_right" headers="b" style="font-family: 'Source Sans Pro'; font-weight: 400">2.26</td>
</tr>
<tr class="odd">
<td class="gt_row gt_right" headers="b" style="font-family: 'Source Sans Pro'; font-weight: 400">0.66</td>
</tr>
</tbody>
</table>

</div>
</div>
<div class="cell-output-display">
<div id="yptjkdwked" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
<style>@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
#yptjkdwked table {
  font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

#yptjkdwked .gt_table {
  display: table;
  border-collapse: collapse;
  line-height: normal;
  margin-left: auto;
  margin-right: auto;
  color: #333333;
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
  background-color: #FFFFFF;
  width: auto;
  border-top-style: none;
  border-top-width: 2px;
  border-top-color: #A8A8A8;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #A8A8A8;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
}

#yptjkdwked .gt_caption {
  padding-top: 4px;
  padding-bottom: 4px;
}

#yptjkdwked .gt_title {
  color: #333333;
  font-size: 125%;
  font-weight: initial;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-color: #FFFFFF;
  border-bottom-width: 0;
}

#yptjkdwked .gt_subtitle {
  color: #333333;
  font-size: 85%;
  font-weight: initial;
  padding-top: 3px;
  padding-bottom: 5px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-color: #FFFFFF;
  border-top-width: 0;
}

#yptjkdwked .gt_heading {
  background-color: #FFFFFF;
  text-align: left;
  border-bottom-color: #FFFFFF;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#yptjkdwked .gt_bottom_border {
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#yptjkdwked .gt_col_headings {
  border-top-style: none;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
}

#yptjkdwked .gt_col_heading {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 12px;
  font-weight: normal;
  text-transform: inherit;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 6px;
  padding-left: 5px;
  padding-right: 5px;
  overflow-x: hidden;
}

#yptjkdwked .gt_column_spanner_outer {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 12px;
  font-weight: normal;
  text-transform: inherit;
  padding-top: 0;
  padding-bottom: 0;
  padding-left: 4px;
  padding-right: 4px;
}

#yptjkdwked .gt_column_spanner_outer:first-child {
  padding-left: 0;
}

#yptjkdwked .gt_column_spanner_outer:last-child {
  padding-right: 0;
}

#yptjkdwked .gt_column_spanner {
  border-bottom-style: none;
  border-bottom-width: 1px;
  border-bottom-color: #334422;
  vertical-align: bottom;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow-x: hidden;
  display: inline-block;
  width: 100%;
}

#yptjkdwked .gt_spanner_row {
  border-bottom-style: hidden;
}

#yptjkdwked .gt_group_heading {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  text-align: left;
}

#yptjkdwked .gt_empty_group_heading {
  padding: 0.5px;
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  border-top-style: solid;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  vertical-align: middle;
}

#yptjkdwked .gt_from_md > :first-child {
  margin-top: 0;
}

#yptjkdwked .gt_from_md > :last-child {
  margin-bottom: 0;
}

#yptjkdwked .gt_row {
  padding-top: 7px;
  padding-bottom: 7px;
  padding-left: 5px;
  padding-right: 5px;
  margin: 10px;
  border-top-style: solid;
  border-top-width: 1px;
  border-top-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 1px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 1px;
  border-right-color: #D3D3D3;
  vertical-align: middle;
  overflow-x: hidden;
}

#yptjkdwked .gt_stub {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
}

#yptjkdwked .gt_stub_row_group {
  color: #333333;
  background-color: #FFFFFF;
  font-size: 100%;
  font-weight: initial;
  text-transform: inherit;
  border-right-style: solid;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
  padding-left: 5px;
  padding-right: 5px;
  vertical-align: top;
}

#yptjkdwked .gt_row_group_first td {
  border-top-width: 2px;
}

#yptjkdwked .gt_row_group_first th {
  border-top-width: 2px;
}

#yptjkdwked .gt_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#yptjkdwked .gt_first_summary_row {
  border-top-style: solid;
  border-top-color: #D3D3D3;
}

#yptjkdwked .gt_first_summary_row.thick {
  border-top-width: 2px;
}

#yptjkdwked .gt_last_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
}

#yptjkdwked .gt_grand_summary_row {
  color: #333333;
  background-color: #FFFFFF;
  text-transform: inherit;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
}

#yptjkdwked .gt_first_grand_summary_row {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-top-style: double;
  border-top-width: 6px;
  border-top-color: #D3D3D3;
}

#yptjkdwked .gt_last_grand_summary_row_top {
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 5px;
  padding-right: 5px;
  border-bottom-style: double;
  border-bottom-width: 6px;
  border-bottom-color: #D3D3D3;
}

#yptjkdwked .gt_striped {
  background-color: rgba(128, 128, 128, 0.05);
}

#yptjkdwked .gt_table_body {
  border-top-style: none;
  border-top-width: 2px;
  border-top-color: #D3D3D3;
  border-bottom-style: solid;
  border-bottom-width: 2px;
  border-bottom-color: #FFFFFF;
}

#yptjkdwked .gt_footnotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#yptjkdwked .gt_footnote {
  margin: 0px;
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#yptjkdwked .gt_sourcenotes {
  color: #333333;
  background-color: #FFFFFF;
  border-bottom-style: none;
  border-bottom-width: 2px;
  border-bottom-color: #D3D3D3;
  border-left-style: none;
  border-left-width: 2px;
  border-left-color: #D3D3D3;
  border-right-style: none;
  border-right-width: 2px;
  border-right-color: #D3D3D3;
}

#yptjkdwked .gt_sourcenote {
  font-size: 90%;
  padding-top: 4px;
  padding-bottom: 4px;
  padding-left: 5px;
  padding-right: 5px;
}

#yptjkdwked .gt_left {
  text-align: left;
}

#yptjkdwked .gt_center {
  text-align: center;
}

#yptjkdwked .gt_right {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#yptjkdwked .gt_font_normal {
  font-weight: normal;
}

#yptjkdwked .gt_font_bold {
  font-weight: bold;
}

#yptjkdwked .gt_font_italic {
  font-style: italic;
}

#yptjkdwked .gt_super {
  font-size: 65%;
}

#yptjkdwked .gt_footnote_marks {
  font-size: 75%;
  vertical-align: 0.4em;
  position: initial;
}

#yptjkdwked .gt_asterisk {
  font-size: 100%;
  vertical-align: 0;
}

#yptjkdwked .gt_indent_1 {
  text-indent: 5px;
}

#yptjkdwked .gt_indent_2 {
  text-indent: 10px;
}

#yptjkdwked .gt_indent_3 {
  text-indent: 15px;
}

#yptjkdwked .gt_indent_4 {
  text-indent: 20px;
}

#yptjkdwked .gt_indent_5 {
  text-indent: 25px;
}
</style>

<table class="gt_table caption-top table table-sm table-striped small" data-quarto-bootstrap="false">
<thead>
<tr class="gt_col_headings header">
<th id="rmse_train" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">rmse_train</th>
<th id="rmse_test" class="gt_col_heading gt_columns_bottom_border gt_right" data-quarto-table-cell-role="th" style="color: #A9A9A9; font-family: 'Source Sans Pro'; text-transform: uppercase" scope="col">rmse_test</th>
</tr>
</thead>
<tbody class="gt_table_body">
<tr class="odd">
<td class="gt_row gt_right" headers="rmse_train" style="font-family: 'Source Sans Pro'; font-weight: 400">0.05</td>
<td class="gt_row gt_right" headers="rmse_test" style="font-family: 'Source Sans Pro'; font-weight: 400">5.79</td>
</tr>
</tbody>
</table>

</div>
</div>
</div>
</figure>
</div>
</div>
<p>If we do this for more complex models (max linear features, plus each additional set of features associated with a cubic spline basis expansions), we obtain the following. Now we see the second descent in test error takes form!</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://m-clark.github.io/img/double-descent/dd_mtcars_over.svg" class="img-fluid figure-img"></p>
<figcaption>Double Descent in the overparameterized setting.</figcaption>
</figure>
</div>
<p>Putting our results together gives us the double descent curve.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://m-clark.github.io/img/double-descent/dd_mtcars.svg" class="img-fluid figure-img"></p>
<figcaption>Double Descent in the overparameterized setting.</figcaption>
</figure>
</div>

<div class="no-row-height column-margin column-container"><div class="">
<p>Note that this all holds for the most part with classification problems, including multiclass (or multivariate/class targets).</p>
</div></div><p>We not only see the double descent pattern, but we can also note that the global test error minimum occurs with the model with the most parameters. The gray dot is the lowest test error with the underparameterized settings, while the dark red is the global test error minimum.</p>
</section>
</section>
<section id="why-does-this-happen" class="level2">
<h2 class="anchored" data-anchor-id="why-does-this-happen">Why does this happen?</h2>
<p>Understanding the double descent phenomenon is an area of active research, and there are some technical issues we won’t cover here. However, we can note a couple things more broadly. When we’re in the underparameterized situation, we ultimately begin to force features that have no association with the target to fit the data anyway. Once you move beyond the point of where these features are useful, test error begins to rise again, until the point of interpolation where test error is even worse than guessing (or just guessing in the classification case).</p>
<p>Beyond the interpolation point, all models we potentially employ using this estimation technique will have the capacity to fit the training data perfectly, i.e.&nbsp;zero bias. This allows us to fit the remaining noise in the data with the additional features employed by the more complex models. There is no guarantee that among the models you fit that the lowest test error will be found relative to the underparameterized setting. However, the lowest test error to be found is ‘out there’ somewhere<sup>6</sup>. So adding complexity will potentially allow you to find improved test error.</p>
<p>Another way to put it is that we have a single class of models to consider, and under and overparameterized are special cases of that more general class. Any one of these might result in the lowest test error. The overparameterized models, which may contain complex nonlinearities and interactions, are likely to be more compatible with the data than the simpler models<sup>7</sup>. So odds are good that at least one of them will have a smaller test error as well. In any case, restricting ourselves to the underparameterized setting is definitely no guarantee that we will find the most performant model.</p>
<p>One caveat is that the model we used is an example of ‘implicit’ regularization, one in which there is no hyper-parameter to set (or discover through cross-validation), like with ridge and lasso. With other techniques (e.g.&nbsp;optimally chosen ridge regression estimator) we may still be able to achieve optimal test error without complete interpolation, and show a reduced peak.</p>
<p><span class="citation" data-cites="dar2021farewell">Dar et al. (2021)</span> note that in the overparameterized setting, we can distinguish the signal part of the error term that reduces as a function of N/p, where the noise part of the error term is a function of p/N. In addition, there is a portion of test error related to model misspecification, which will always decrease with overparameterization. In addition, one must consider both feature correlations as well as correlations among observations. Having more complex covariance structure doesn’t negate the double descent phenomenon, but they suggest that, for example, cases where there is low effective dimension within these additional features will more readily display the double descent.</p>
<p>Another issue is that in any given situation it is difficult to know where in the realm of available models we exist presently. So additional complexity, or even additional data, may in fact hurt performance <span class="citation" data-cites="nakkiran2019deep">(Nakkiran et al. 2019)</span>.</p>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>The double descent phenomenon is a quite surprising scenario, especially for those who have only heard of the classical bias-variance trade off. There is still much to learn regarding it, but such research is off and running. For practical purposes, it is worth keeping it in mind to aid us in model selection and thinking about our modeling strategies in general.</p>
<!-- [^ridgeless]:  -->



</section>


<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-belkin2019reconciling" class="csl-entry">
Belkin, Mikhail, Daniel Hsu, Siyuan Ma, and Soumik Mandal. 2019. <span>“Reconciling Modern Machine-Learning Practice and the Classical Bias–Variance Trade-Off.”</span> <em>Proceedings of the National Academy of Sciences</em> 116 (32): 15849–54.
</div>
<div id="ref-dar2021farewell" class="csl-entry">
Dar, Yehuda, Vidya Muthukumar, and Richard G Baraniuk. 2021. <span>“A Farewell to the Bias-Variance Tradeoff? An Overview of the Theory of Overparameterized Machine Learning.”</span> <em>arXiv Preprint arXiv:2109.02355</em>.
</div>
<div id="ref-hastie2019surprises" class="csl-entry">
Hastie, Trevor, Andrea Montanari, Saharon Rosset, and Ryan J Tibshirani. 2019. <span>“Surprises in High-Dimensional Ridgeless Least Squares Interpolation.”</span> <em>arXiv Preprint arXiv:1903.08560</em>.
</div>
<div id="ref-nakkiran2019deep" class="csl-entry">
Nakkiran, Preetum, Gal Kaplun, Yamini Bansal, Tristan Yang, Boaz Barak, and Ilya Sutskever. 2019. <span>“Deep Double Descent: Where Bigger Models and More Data Hurt.”</span> <em>arXiv Preprint arXiv:1912.02292</em>.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>R<sup>2</sup> = 1 in the standard linear model setting.↩︎</p></li>
<li id="fn2"><p>Note that the intercept term is added after data shuffling so when p = 1 it is the intercept only model, i.e.&nbsp;guessing the mean.↩︎</p></li>
<li id="fn3"><p>I used <span class="pack" style="">mgcv</span> to so this, then added them in whole for each term to the previously shuffled model matrix. These columns are not shuffled. By default these will add 10 columns each to the model matrix.↩︎</p></li>
<li id="fn4"><p>For more on generalized additive models, see <a href="https://m-clark.github.io/generalized-additive-models/">my document</a>.↩︎</p></li>
<li id="fn5"><p>Ridgeless regression has the same form as the ‘normal’ equations for least squares, but instead of <img src="https://latex.codecogs.com/png.latex?%5Cbeta%20%5Csim%20(X%5ETX)%5E%7B-1%7D%20%5Ccdot%20X%5ETy">, we have <img src="https://latex.codecogs.com/png.latex?%5Cbeta%20%5Csim%20(X%5ETX)%5E%7B+%7D%20%5Ccdot%20X%5ETy"> where the first part is the pseudo-inverse of <img src="https://latex.codecogs.com/png.latex?X">. It is similar to equations for ridge regression (see my demo <a href="https://m-clark.github.io/models-by-example/penalized-maximum-likelihood.html#l2-ridge-regularization">here</a>) and can be seen as an approximation to it as the ridge penalty tends toward zero.↩︎</p></li>
<li id="fn6"><p>Fox Mulder told me so.↩︎</p></li>
<li id="fn7"><p>Because nature is just funny that way.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2021,
  author = {Clark, Michael},
  title = {Double {Descent}},
  date = {2021-11-13},
  url = {https://m-clark.github.io/posts/2021-10-30-double-descent/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2021" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2021. <span>“Double Descent.”</span> November 13. <a href="https://m-clark.github.io/posts/2021-10-30-double-descent/">https://m-clark.github.io/posts/2021-10-30-double-descent/</a>.
</div></div></section></div> ]]></description>
  <category>deep learning</category>
  <category>machine learning</category>
  <guid>https://m-clark.github.io/posts/2021-10-30-double-descent/</guid>
  <pubDate>Sat, 13 Nov 2021 05:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/double-descent/dd_mtcars.png" medium="image" type="image/png" height="86" width="144"/>
</item>
<item>
  <title>This is definitely not all you need</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2021-07-15-dl-for-tabular/</link>
  <description><![CDATA[ 





<section id="motivation" class="level2">
<h2 class="anchored" data-anchor-id="motivation">Motivation</h2>
<p>I’ve been a little perplexed at the lack of attention of deep learning (DL) toward what I consider to be ‘default’ data in my world, often referred to as <em>tabular data</em>, where typically we have a two dimensional input of observations (rows) and features (columns) and inputs are of varying type, scale and source. Despite the ubiquity of such data in data science generally, and despite momentous advances in areas like computer vision and natural language processing, at this time, it’s not very clear what the status of DL for tabular data is.</p>
<p>There have been developments in the area recently though, with some modeling approaches, such as TabNet, gaining traction. In June of 2021, I actually came across three papers on <a href="arxiv.org">Arxiv</a> that were making related claims about the efficacy of DL for tabular data. As in many academic and practical (and life) pursuits, results of these studies are nuanced, so I thought I’d help myself and others by summarizing here.</p>
</section>
<section id="goal" class="level2">
<h2 class="anchored" data-anchor-id="goal">Goal</h2>
<p>I want to know if, e.g.&nbsp;time and/or resources are limited, whether it will be worth diving into a DL model if I have a satisfactory simpler/easier one ready to implement that does pretty well. Perhaps this answer is already, ‘if it ain’t broke, don’t fix it’, but given the advancements in other data domains, it would be good to assess what the current state of DL with tabular data is.</p>
</section>
<section id="caveats" class="level2">
<h2 class="anchored" data-anchor-id="caveats">Caveats</h2>
<ul>
<li>I’m not going to do more than give a cursory summary of the articles, and provide no in-depth explanation of the models. For more detail, see the corresponding articles and references for the models therein. You are not going to learn how to use TabNet, NODE, transformers, etc., for tabular data.</li>
<li>There are other decent articles on the topic not covered here. Some are referenced in these more recent offerings, so feel free to peruse.</li>
</ul>
</section>
<section id="quick-take" class="level2">
<h2 class="anchored" data-anchor-id="quick-take">Quick Take</h2>
<p>In case you don’t want any detail, here’s a quick summary based on my impressions from these articles. Right now, if you want to use DL on tabular data, don’t make a fuss of it. A simple architecture, even a standard multi-layer perceptron, will likely do as well as more complicated ones. In general though, the amount of effort put into prep/tuning may not be worth it for many typical tabular data settings, for example, relative to a suitably flexible statistical model (e.g.&nbsp;GAMM) or a default fast boosting implementation like XGBoost. However, DL models are already thinking ‘big data’, so for very large data situations, a DL model might make a great choice, as others may not be computationally very viable. It also will not be surprising at all that in the near future some big hurdle may be overcome as we saw with DL applications in other fields, in which case some form of DL may be ‘all you need’.</p>
<p>Now, on to the rest!</p>
</section>
<section id="tabular-data-deep-learning-is-not-all-you-need" class="level2">
<h2 class="anchored" data-anchor-id="tabular-data-deep-learning-is-not-all-you-need">Tabular Data: Deep Learning is Not All You Need</h2>
<section id="paper-info" class="level3">
<h3 class="anchored" data-anchor-id="paper-info">Paper Info</h3>
<ul>
<li><em>Who</em>: Shwartz-Ziv &amp; Armon</li>
<li><em>Where</em>: Intel</li>
<li><em>When</em>: 2021-06-21 V1</li>
<li><a href="https://arxiv.org/pdf/2106.03253v1.pdf">Arxiv Link</a></li>
</ul>
</section>
<section id="from-the-abstract" class="level3">
<h3 class="anchored" data-anchor-id="from-the-abstract">From the Abstract</h3>
<blockquote class="blockquote">
<p>We analyze the deep models proposed in four recent papers across eleven datasets, nine of which were used in these papers, to answer these questions. We show that in most cases, each model performs best on the datasets used in its respective paper but significantly worse on other datasets. Moreover, our study shows that XGBoost (Chen and Guestrin, 2016) usually outperforms the deep models on these datasets. Furthermore, we demonstrate that the hyperparameter search process was much shorter for XGBoost.</p>
</blockquote>
</section>
<section id="overview" class="level3">
<h3 class="anchored" data-anchor-id="overview">Overview</h3>
<p>For each model they used the data that was implemented in the original model papers by the authors (e.g.&nbsp;the dataset used in the TabNet article), and also used their suggested parameter settings. They tested all the models against their own data, plus the other papers’ data, plus two additional data sets that were not used in any of the original papers.</p>
</section>
<section id="data" class="level3">
<h3 class="anchored" data-anchor-id="data">Data</h3>
<p>They use eleven total datasets. Nine datasets are those used in the original papers on TabNet, DNF-Net, and NODE, drawing three datasets from each paper. Additionally, Shwartz-Ziv &amp; Armon use two Kaggle datasets not used in any of those papers. Sample sizes ranged from 7k to 1M, 10-2000 features, with two being numeric targets, while the other target variables ranged from 2-7 classes. Datasets are described in detail in the paper along with links to the source (all publicly available).</p>
</section>
<section id="models-explored" class="level3">
<h3 class="anchored" data-anchor-id="models-explored">Models Explored</h3>
<p>Brief summaries of the DL models are found in the paper.</p>
<ul>
<li><em>XGBoost</em></li>
<li><em>TabNet</em></li>
<li><em>Neural Oblivious Decision Ensembles</em> (NODE)</li>
<li><em>DNF-Net</em></li>
<li><em>1D-CNN</em></li>
</ul>
</section>
<section id="quick-summary" class="level3">
<h3 class="anchored" data-anchor-id="quick-summary">Quick Summary</h3>
<section id="not-counting-the-ensemble-methods" class="level5">
<h5 class="anchored" data-anchor-id="not-counting-the-ensemble-methods">Not counting the ensemble methods…</h5>
<ul>
<li>TabNet did best on all of its own data sets, but was not the best model on any other.</li>
<li>NODE each did best on 2 of its own 3 data sets, but not on any other.</li>
<li>DNF-Net best on one of its own 3 data sets, but not on any other.</li>
<li>XGBoost was best on the remaining 5 datasets.</li>
</ul>
</section>
<section id="counting-the-ensemble-methods" class="level5">
<h5 class="anchored" data-anchor-id="counting-the-ensemble-methods">Counting the ensemble methods…</h5>
<ul>
<li>TabNet did best on 2 of its own 3 data sets, but was not the best model on any other.</li>
<li>DNF-Net and NODE each did best on one of its own 3 data sets, but not on any other.</li>
<li>XGBoost was best on one dataset.</li>
</ul>
<p>Of those, XGB was notably better on ‘unseen’ data, and comparable to the best performing ensemble. A simple ensemble was also very performant. From the paper:</p>
<blockquote class="blockquote">
<p>The ensemble of all the models was the best model with 2.32% average relative increase, XGBoost was the second best with 3.4%, 1D-CNN had 7.5%, TabNet had 10.5%, DNF-Net had 11.8% and NODE had 14.2% (see Tables 2 and 3 in the appendix for full results).</p>
</blockquote>
<p>As a side note, XGBoost + DL was best, but that defeats the purpose in my opinion. Presumably any notably more complicated setting will be potentially better with enough complexity, but unless there is an obvious way on how to add such complexity, it’s mostly an academic exercise. However, as the authors note, if search is automated, maybe the complexity of combining the models is less of an issue.</p>
</section>
</section>
<section id="other-stuff" class="level3">
<h3 class="anchored" data-anchor-id="other-stuff">Other stuff</h3>
<section id="kudos" class="level5">
<h5 class="anchored" data-anchor-id="kudos">Kudos</h5>
<p>The authors cite the <a href="https://en.wikipedia.org/wiki/No_free_lunch_theorem">No Free Lunch theorem</a> in the second paragraph, something that appears to be lost on many (most?) of these types of papers touting small increases in performance for some given modeling approach.</p>
</section>
<section id="issues" class="level5">
<h5 class="anchored" data-anchor-id="issues">Issues</h5>
<p>There are always things like training process/settings that are difficult to fully replicate. By the time authors publish any paper, unless exact records are kept, the iterations (including discussions that rule out various paths) are largely lost to time. This isn’t a knock on this paper, just something to keep in mind.</p>
</section>
<section id="opinion" class="level5">
<h5 class="anchored" data-anchor-id="opinion">Opinion</h5>
<p>I liked this one in general. They start by giving the competing models their best chance with their own settings and data, which was processed and trained in the same way. Even then, those models still either didn’t perform best, and/or performed relatively poorly on any other dataset.</p>
</section>
</section>
</section>
<section id="regularization-is-all-you-need-simple-neural-nets-can-excel-on-tabular-data" class="level2">
<h2 class="anchored" data-anchor-id="regularization-is-all-you-need-simple-neural-nets-can-excel-on-tabular-data">Regularization is all you Need: Simple Neural Nets can Excel on Tabular Data</h2>
<section id="paper-info-1" class="level3">
<h3 class="anchored" data-anchor-id="paper-info-1">Paper Info</h3>
<ul>
<li><em>Who</em>: Kadra et al.</li>
<li><em>Where</em>: U of Freiburg, Leibniz U (Germany)</li>
<li><em>When</em>: 2021-06-06 V1</li>
<li><a href="https://arxiv.org/pdf/2106.11189.pdf4">Arxiv Link</a></li>
</ul>
</section>
<section id="from-the-abstract-1" class="level3">
<h3 class="anchored" data-anchor-id="from-the-abstract-1">From the Abstract</h3>
<blockquote class="blockquote">
<p>Tabular datasets are the last “unconquered castle” for deep learning… In this paper, we hypothesize that the key to boosting the performance of neural networks lies in rethinking the joint and simultaneous application of a large set of modern regularization techniques. As a result, we propose regularizing plain Multilayer Perceptron (MLP) networks by searching for the optimal combination/cocktail of 13 regularization techniques for each dataset using a joint optimization over the decision on which regularizers to apply and their subsidiary hyperparameters.</p>
</blockquote>
<blockquote class="blockquote">
<p>We empirically assess the impact of these regularization cocktails for MLPs on a large-scale empirical study comprising 40 tabular datasets and demonstrate that (i) well-regularized plain MLPs significantly outperform recent state-of-the-art specialized neural network architectures, and (ii) they even outperform strong traditional ML methods, such as XGBoost.</p>
</blockquote>
<blockquote class="blockquote">
<p>We emphasize that some of these publications claim to outperform Gradient Boosted Decision Trees (GDBT) [1, 37], and other papers explicitly stress that their neural networks do not outperform GBDT on tabular datasets [38, 22]. In contrast, we do not propose a new kind of neural architecture, but a novel paradigm for learning a combination of regularization methods.**</p>
</blockquote>
</section>
<section id="overview-1" class="level3">
<h3 class="anchored" data-anchor-id="overview-1">Overview</h3>
<p>This data is more about exploring regularization techniques (e.g.&nbsp;data augmentation, model averaging via dropout) rather than suggesting any particular model is superior. Even in the second paragraph they state their results do not suggest a performance gain over boosting methods. Their focus is on potentially improving DL for tabular data through regularization with two hypotheses:</p>
<ul>
<li>Regularization cocktails outperform state-of-the-art deep learning architectures on tabular datasets.</li>
<li>Regularization cocktails outperform Gradient-Boosted Decision Trees, as the most commonly used traditional ML method for tabular data.</li>
</ul>
</section>
<section id="data-1" class="level3">
<h3 class="anchored" data-anchor-id="data-1">Data</h3>
<p>Forty total datasets ranging from as little as ~400 observations to over 400k, and between 4 and 2000 features. All were categorical targets, with about half binary. All available at openml.org with target ID provided.</p>
</section>
<section id="models-explored-1" class="level3">
<h3 class="anchored" data-anchor-id="models-explored-1">Models Explored</h3>
<p>Comparison models:</p>
<ul>
<li><em>TabNet</em>: (with author’s proposed defaults)</li>
<li><em>NODE</em>: (with author’s proposed defaults)</li>
<li><em>Autogluon</em>: Tabular: can use other techniques but restricted to ensembles of neural nets for this demo</li>
<li><em>ASK-GBDT</em>: GB via Auto-sklearn (Note this tool comes from one of the authors )</li>
<li><em>XGBoost</em>: Original implementation</li>
<li><em>MLP</em>: Multilayer Perceptron - 9 layers with 512 hidden units each.</li>
<li><em>MLP+D</em>: MLP with Dropout</li>
<li><em>MLP+C</em>: MLP with regularization cocktail</li>
</ul>
</section>
<section id="quick-summary-1" class="level3">
<h3 class="anchored" data-anchor-id="quick-summary-1">Quick Summary</h3>
<ul>
<li>To begin, their regularization cocktail approach is the clear winner on these datasets, having one outright on over 40% of them (based on table 2).</li>
<li>Standard XGB performed best (or tied for best) 8 of the 40 data sets, while it or ASK-GBDT were best for 12 datasets combined.</li>
<li>Simple MLP was best once, while MLP with dropout was best 5 times, while the cocktail method was best in general, across 19 datasets.</li>
<li>The ‘fancy’ DL models were the worst performers across the board. TabNet never performed best, and NODE only did once, but the latter also repeatedly failed due to memory issues or run-time limitations (this memory issue was mentioned in the previous paper also).</li>
<li>Head-to-head, the cocktail beat the standard XGB 26 out of 38 times with three ties. So it wins 65% of the time against XGB, 70% against ASK-GBDT, but 60% against either (i.e.&nbsp;some XGB approach).</li>
</ul>
</section>
<section id="other-stuff-1" class="level3">
<h3 class="anchored" data-anchor-id="other-stuff-1">Other Stuff</h3>
<section id="kudos-1" class="level5">
<h5 class="anchored" data-anchor-id="kudos-1">Kudos</h5>
<ul>
<li>Recognize that tabular data is understudied in mainstream DL literature</li>
<li>They used a lot of datasets</li>
<li>They look at the simplest DL models for comparison</li>
</ul>
</section>
<section id="issues-1" class="level5">
<h5 class="anchored" data-anchor-id="issues-1">Issues</h5>
<ul>
<li><p>I wonder why there was not a single numeric outcome among so many datasets. Furthermore, some of the data are image classification (e.g.&nbsp;Fashion-MNIST), so I’m not sure why they’re included. I wouldn’t use a ‘tabular’ technique when standard computer vision approaches already work so well.</p></li>
<li><p>I’m not familiar with the augmentation techniques they mention, which were devised for image classification, but there have been some used for tabular data for a couple decades at this point that were not mentioned, including simple upsampling, or imputation methods (e.g.&nbsp;SMOTE). That’s not a beef with the article at all, I’ve long wondered why people haven’t been using data augmentation for tabular data given it’s success elsewhere (including for tabular data!).</p></li>
<li><p>They use a standard t-tests of ranks, but if we’re going to use this sort of approach, we’d maybe want to adjust for all the tests done, and probably for all pairwise comparisons (they show such a table for the regularization methods). Depending on the approach and cutoff, the XGB vs.&nbsp;Cocktail difference may not be significant.</p></li>
<li><p>Also, I couldn’t duplicate these p-values with R’s default settings for Wilcoxon signed rank tests, and there does in fact seem to be inconsistency between the detailed results and Wilcoxon summaries. For example, in the regularization tests of Table 9, <code>Cocktail</code> vs.&nbsp;<code>WD</code> and <code>DO</code> shows two ties in the first four data sets, yet only 1 tie is reported in the comparison chart for both (Figure 4). For the models, Table 2 show 3 ties of <code>XGB</code> &amp; the <code>Cocktail</code>, with 1 for <code>ASK-G</code> and <code>Cocktail</code>, but 2 and 0 are reported for their Wilcoxon tests. It’s not clear what they did for NODE with all the NAs. I do not believe these discrepancies, nor adjusting for multiple comparisons, will change the results (I re-did those myself).</p></li>
</ul>
</section>
<section id="opinion-1" class="level5">
<h5 class="anchored" data-anchor-id="opinion-1">Opinion</h5>
<p>If we ignore the regularization focus and just look at the model comparisons, I’m not overly convinced we have a straightforward victory for cocktail vs.&nbsp;GB as implied in the conclusion. Results appear to be in favor of their proposed method, but not enough to be a near-guarantee in a particular setting, so we’re back to square one of just using the easier/faster/better tool. I’m also not sure who was questioning the use of regularization for neural networks or modeling in general, so the comparison to any model without some form of regularization isn’t as interesting to me. What is interesting to me is that we have another round of evidence that the fancier DL models like TabNet do not perform that well relative to GB or simpler DL architectures.</p>
</section>
</section>
</section>
<section id="revisiting-deep-learning-models-for-tabular-data" class="level2">
<h2 class="anchored" data-anchor-id="revisiting-deep-learning-models-for-tabular-data">Revisiting Deep Learning Models for Tabular Data</h2>
<section id="paper-info-2" class="level3">
<h3 class="anchored" data-anchor-id="paper-info-2">Paper Info</h3>
<ul>
<li><em>Who</em>: Yury Gorishniy, Ivan Rubachev, Valentin Khrulkov, Artem Babenko</li>
<li><em>Where</em>: Yandex (Russia)</li>
<li><em>When</em>: 2021-06-22</li>
<li><a href="https://arxiv.org/abs/2106.11959">Arxiv Link</a></li>
<li><a href="https://github.com/yandex-research/rtdl">Source code</a></li>
</ul>
</section>
<section id="from-the-abstract-2" class="level3">
<h3 class="anchored" data-anchor-id="from-the-abstract-2">From the Abstract</h3>
<blockquote class="blockquote">
<p>The necessity of deep learning for tabular data is still an unanswered question addressed by a large number of research efforts. The recent literature on tabular DL proposes several deep architectures reported to be superior to traditional “shallow” models like Gradient Boosted Decision Trees. However, since existing works often use different benchmarks and tuning protocols, it is unclear if the proposed models universally outperform GBDT. Moreover, the models are often not compared to each other, therefore, it is challenging to identify the best deep model for practitioners.</p>
</blockquote>
<blockquote class="blockquote">
<p>In this work, we start from a thorough review of the main families of DL models recently developed for tabular data. We carefully tune and evaluate them on a wide range of datasets and reveal two significant findings. First, we show that the choice between GBDT and DL models highly depends on data and there is still no universally superior solution. Second, we demonstrate that a simple ResNet-like architecture is a surprisingly effective baseline, which outperforms most of the sophisticated models from the DL literature. Finally, we design a simple adaptation of the Transformer architecture for tabular data that becomes a new strong DL baseline and reduces the gap between GBDT and DL models on datasets where GBDT dominates.</p>
</blockquote>
</section>
<section id="overview-2" class="level3">
<h3 class="anchored" data-anchor-id="overview-2">Overview</h3>
<p>This paper compares different models on a variety of datasets. They are interested in the GB vs.&nbsp;DL debate, but like the previous paper, also interested in how well a simpler DL architecture might perform, and what steps might help the more complicated ones do better.</p>
</section>
<section id="data-2" class="level3">
<h3 class="anchored" data-anchor-id="data-2">Data</h3>
<p>They have 11 datasets with a mix of binary, multiclass and numeric targets. Sizes range from 20K to 1M+. There appears to be some overlap with the first paper (e.g.&nbsp;Higgs, Cover type).</p>
</section>
<section id="models-explored-2" class="level3">
<h3 class="anchored" data-anchor-id="models-explored-2">Models Explored</h3>
<section id="baselines" class="level5">
<h5 class="anchored" data-anchor-id="baselines">‘Baselines’</h5>
<ul>
<li><em>XGBoost</em></li>
<li><em>CatBoost</em></li>
<li><em>MLP</em></li>
<li><em>ResNet</em></li>
</ul>
</section>
<section id="dl-comparisons" class="level5">
<h5 class="anchored" data-anchor-id="dl-comparisons">DL Comparisons</h5>
<ul>
<li><em>SNN</em></li>
<li><em>NODE</em></li>
<li><em>TabNet</em></li>
<li><em>GrowNet</em></li>
<li><em>DCN V2</em></li>
<li><em>AutoInt</em></li>
</ul>
<p>In addition, they look at ensembles of these models, but this is not of interest to me for this post.</p>
</section>
</section>
<section id="quick-summary-2" class="level3">
<h3 class="anchored" data-anchor-id="quick-summary-2">Quick Summary</h3>
<p>Note that these refer to the ‘single model’ results, not the results for ensembles.</p>
<ul>
<li><p>Some form of boosting performed best on 4 of the 11 datasets.</p></li>
<li><p>ResNet was best on four classification tasks, but not once for numeric targets.</p></li>
<li><p>At this point you won’t be surprised at what doesn’t perform as well- TabNet, NODE, and similar. TabNet, DCN, and GrowNet were never the best performer, and the other three were best one time a piece.</p></li>
<li><p>MLP did not perform best on any data, however the authors note that it ‘is often on par or even better than some of the recently proposed DL models’.</p></li>
<li><p>They also looked at models with a ‘simple’ transformer architecture. Their results suggest better performance than the other DL models, and similar performance to ResNet.</p></li>
</ul>
</section>
<section id="other-stuff-2" class="level3">
<h3 class="anchored" data-anchor-id="other-stuff-2">Other Stuff</h3>
<section id="kudos-2" class="level5">
<h5 class="anchored" data-anchor-id="kudos-2">Kudos</h5>
<ul>
<li><p>Sharing the source code!</p></li>
<li><p>Recognizing that results at this point are complex at best given the lack of standard datasets</p></li>
</ul>
</section>
<section id="issues-2" class="level5">
<h5 class="anchored" data-anchor-id="issues-2">Issues</h5>
<ul>
<li>They note a distinction between <em>heterogeneous</em> vs.&nbsp;other types of data. They call data heterogeneous if the predictors are of mixed data types (e.g.&nbsp;categorical, numeric, count), while something like pixel data would be <em>homogeneous</em> because all the columns are essentially the same type. The latter isn’t as interesting to me for this sort enterprise, and I think the former is what most are thinking about for ‘tabular’ data, otherwise we’d just call it what it is (e.g.&nbsp;image or text data), and modeling/estimation is generally quite a bit easier when all the data is the same type. I do think it’s important that they point out that GB is better with heterogeneous data, and I think if you only look at such data, you’d likely see GB methods still outperforming or at worst on par with the best DL methods.</li>
</ul>
</section>
<section id="opinion-2" class="level5">
<h5 class="anchored" data-anchor-id="opinion-2">Opinion</h5>
<p>These results seem consistent with others at this point. Complex DL isn’t helping, and simpler architectures, even standard MLP show good performance. In the end, we still don’t have any clear winner over GB methods.</p>
</section>
</section>
</section>
<section id="overall-assessment" class="level2">
<h2 class="anchored" data-anchor-id="overall-assessment">Overall Assessment</h2>
<p>These papers put together are helpful in painting a picture of where we are at present with deep learning for tabular data, especially with mixed data types. In this setting, it seems that more complicated DL models do not seem to have any obvious gain over simpler architectures, which themselves do not consistently beat boosting methods. It may also be the case that for data of mixed data types/sources, boosting is still the standard to beat.</p>
<p>Even though these articles are geared toward comparisons to GB/XGBoost, in several settings I’ve applied them, I typically do not necessarily have appreciably greater success compared to a default setting random forest (e.g.&nbsp;from the <span class="pack" style="">ranger</span> package in R), or sufficiently flexible statistical model. Unfortunately this comparison is lacking from the papers, and would have been nice to have, especially for smaller data settings where such models are still very viable. I think a viable fast model, preferably one without any tuning required (or which simply is taken off the shelf) should be the baseline.</p>
<p>In that light, for tabular data I think one should maybe start with a baseline of a penalized regression with appropriate interactions (e.g.&nbsp;ridge/lasso), or a more flexible penalized approach (GAMM) as a baseline, the latter especially, as it can at least automatically incorporate nonlinear relationships, and tools like <span class="pack" style="">mgcv</span> or <span class="pack" style="">gpboost</span> in R can do so with very large data (1 million +) in a matter of seconds. In settings of relatively higher dimensions, interactions and nonlinearities should be prevalent enough such that basis function, tree, and DL models should be superior. Whether they are practically so is the key concern even in those settings. With smaller, noisier data of less dimension, I suspect the tuning/time effort with present day DL models for tabular data will likely not be worth it. This may change very soon however, so such an assumption should be regularly checked.</p>
<p><br> <br></p>
<p>last updated: 2025-01-02</p>
<p>Neural Net image source from <a href="https://uc-r.github.io/2018/04/09/feedforward-deep-models/">UC Business Analytics R Programming Guide</a></p>



</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-gorishniy2021tabular" class="csl-entry">
Gorishniy, Yuri, Ivan Rubachev, Valentin Khrulkov, and Artem Babenko. 2021. <span>“Revisiting Deep Learning Models for Tabular Data.”</span> <em>arXiv Preprint arXiv:2106.11959</em>.
</div>
<div id="ref-kadra2021tabular" class="csl-entry">
Kadra, Arlind, Marius Lindauer, Frank Hutter, and Josif Grabocka. 2021. <span>“Regularization Is All You Need: Simple Neural Nets Can Excel on Tabular Data.”</span> <em>arXiv Preprint arXiv:2106.11189</em>.
</div>
<div id="ref-shwartz2021tabular" class="csl-entry">
Shwartz-Ziv, Ravid, and Amitai Armon. 2021. <span>“Tabular Data: Deep Learning Is Not All You Need.”</span> <em>arXiv Preprint arXiv:2106.03253</em>.
</div>
</div></section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2021,
  author = {Clark, Michael},
  title = {This Is Definitely Not All You Need},
  date = {2021-07-19},
  url = {https://m-clark.github.io/posts/2021-07-15-dl-for-tabular/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2021" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2021. <span>“This Is Definitely Not All You
Need.”</span> July 19. <a href="https://m-clark.github.io/posts/2021-07-15-dl-for-tabular/">https://m-clark.github.io/posts/2021-07-15-dl-for-tabular/</a>.
</div></div></section></div> ]]></description>
  <category>deep learning</category>
  <category>machine learning</category>
  <guid>https://m-clark.github.io/posts/2021-07-15-dl-for-tabular/</guid>
  <pubDate>Mon, 19 Jul 2021 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/dl-for-tab/deep_nn.png" medium="image" type="image/png" height="104" width="144"/>
</item>
<item>
  <title>Practical Bayes Part I</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>NB: This post was revisited when updating the website early 2025, and some changes were required. Attempts to keep things consistent were made, but if you feel you’ve found an issue, please post it at <a href="http://github.com/m-clark/m-clark.github.io/issues">GitHub</a>.</p>
</blockquote>
<section id="overview" class="level1">
<h1>Overview</h1>
<p><img src="https://m-clark.github.io/img/r_and_stan.png" style="display:block; margin: 0 auto; width: 50%"></p>
<p><br></p>
<p>Bayesian analysis takes some getting used to, but offers great advantages once you get into it. While it can be difficult to get started, it typically should not take much to repeat an analysis one is already familiar with, say a standard regression with some (common) additional complexity like a binary outcome, interactions, random effects, etc. What’s great is that <span style="color: #b2001d;"><strong>Stan</strong></span>, a programming language for Bayesian analysis, has come a very long way, and provides a means for (relatively) fast computation. What’s more, applied analysts do not need to know the Stan programming language to do common and even notably complicated models. Packages like <span class="pack" style="">rstanarm</span> and <span class="pack" style="">brms</span>, coupled with additional tools like <span class="pack" style="">bayesplot</span>, <span class="pack" style="">tidybayes</span>, and more, make getting and exploring results even easier than the R packages one already uses.</p>
<p>One of the advantages of doing Bayesian analysis with these tools is that there are many ways to diagnose model issues, problems, and failures. This is great! Traditional analysis can often be notably more difficult in this regard, or at least typically has fewer ready tools to work with, and often there can be serious model deficiencies without much notification or, if there is, there might be little one can do about it. On the other hand, current Bayesian packages are providing diagnostic information as a default part of results, have ready visualizations to explore issues, and more.</p>
<div class="colum-margin">
<p>This is part one of two posts on doing practical modeling with R and Stan in an applied fashion. Due to unforeseen circumstances (and plenty of procrastination), the bulk of the content of these posts was created many months before actual posting. It’s hoped that most of this will still be applicable and have the conceptual continuity as originally intended, but apologies in advance if some parts seem a little disjointed, off topic, etc.</p>
</div>
</section>
<section id="the-stated-problem" class="level1">
<h1>The Stated Problem</h1>
<div style="text-align: center">
<p><i class="far fa-question-circle fa-5x" style="padding: 20px; color: #ff5500BF"></i></p>
</div>
<p>This is all great in general. However, in consulting I saw a consistent issue among clients starting out with Bayesian analysis and Stan packages. Someone has a standard model, e.g.&nbsp;a basic regression or mixed model, but is getting problematic warnings, messages, or errors. When they look up how to solve this problem, the documentation, forums, and other outlets, while great resources for the initiated, often overwhelm newer and/or more applied users, as they are too technical, assume a great deal of background knowledge, are even under-explained (especially in the case of interpreting visualizations), and even suggest things that aren’t typically possible (e.g.&nbsp;getting better data/model). What seems a straightforward suggestion to a more advanced user or developer, may not be even close to that for many applied analysts, and they can be left a bit deflated by their experience.</p>
<p>In the beginning of Stan’s ascension, the majority of people using Stan/<span class="pack" style="">rstan</span> were more technically inclined, coded in Stan directly, and, when problems arose, they were willing to do a lot of extra work to solve the problems (reading technical articles, developing pseudo-expertise with various techniques, and more). But tools like <span class="pack" style="">rstanarm</span> and <span class="pack" style="">brms</span> make running Bayesian models as <a href="https://m-clark.github.io/easy-bayes/">easy to do</a> as using base R functions and other non-Bayesian packages, and as Bayesian analysis has become more widely used, accepted, and presented, this has opened the Bayesian approach to practically anyone that wants to do it.</p>
<p>I personally don’t think one needs to be an expert in Bayesian analysis to enjoy its benefits for common models, even if difficulties come up. Nor do I think an exhaustive search through forums, technical articles, function documentation, and more is necessary to deal issues that arise often. So this is an attempt at a practical guide and one-stop shop for dealing with the most common issues that arise, interpreting results of diagnostics, and summarizing the options one can take. <span style="color: #ff5500"><strong>The goal here is to provide some practical, not perfect(!), suggestions on how to go about your applied Bayesian modeling.</strong></span></p>
</section>
<section id="audience" class="level1">
<h1>Audience</h1>
<div style="text-align: center;">
<p><i class="fas fa-users fa-5x" style="color: #ff5500BF"></i><i class="fas fa-users fa-5x" style="color: #ff5500"></i><i class="fas fa-users fa-5x" style="color: #ff5500BF"></i></p>
</div>
<p><br></p>
<p>Here is the presumed audience for this post:</p>
<ul>
<li>Wants to conduct Bayesian analysis</li>
<li>Is not going to code anything in Stan directly (i.e.&nbsp;will use a specific package like <span class="pack" style="">rstanarm</span> or <span class="pack" style="">brms</span>)</li>
<li>Is not a statistician, nor desires deep technical insights about Bayesian analysis (at least not yet!)</li>
<li>Is already having to learn a new tool/functions/possibly a whole system of inference</li>
<li>Has probably never used the <code>control</code> argument for any model</li>
</ul>
<p>While you can do a Bayesian analysis just for the heck of it, you really need to understand a few key ideas to take advantage of what it offers. Some things you do need to know in order to use it on a basic level:</p>
<ul>
<li>The distributions: priors, likelihood, posterior, posterior predictive</li>
<li>Iterative sampling to estimate parameters. Even a cursory understanding of maximum likelihood would probably be enough.</li>
</ul>
<p>You can obtain this basic info from my document <a href="m-clark.github.io/bayesian-basics/">Bayesian Basics</a>.</p>
</section>
<section id="outline" class="level1">
<h1>Outline</h1>
<p>Here is what we’re going to do:</p>
<ul>
<li>Discuss some of the more common problems</li>
<li>Explain conceptually what they indicate</li>
<li>Provide quick solutions that should work most of the time</li>
<li>Outline a practical approach for future endeavors (<a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/">Part II</a>)</li>
</ul>
<p>Each section discusses a particular problem and ends with a general recommendation, and potentially, specific links to look further into the issue.</p>
</section>
<section id="installation-issues" class="level1">
<h1>Installation issues</h1>
<p>Your first hurdle is installation, so let’s start there. Applied users will use <span class="pack" style="">rstanarm</span>, <span class="pack" style="">brms</span>, or other higher level interfaces to the Stan programming language. These tools use Stan, but Stan itself requires compilation to C++. This means that to run a basic regression with <span class="pack" style="">brms</span>, you’ll likely be depending on multiple languages and packages for it to work. When using these packages, here is a high-level view of how things work:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Crightarrow%5Cquad"> Package interprets your R code (<span class="pack" style="">brms</span>, <span class="pack" style="">rstanarm</span>)</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cquad%5Crightarrow%5Cquad"> Model is translated to Stan (or use <span class="pack" style="">rstan</span> with Stan code)</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cquad%5Cquad%5Crightarrow%5Cquad"> Compiled to C++ (requires compiler)</p>
<p>In general, installing the package you want to use will install the appropriate dependencies, and that should be enough as far as your interactive R part goes. In some cases it may not be. If you have issues, it’s maybe best to install <span class="pack" style="">rstan</span> first, then your package of choice. Issues beyond that may indicate an issue with the compiler, at which point you’ll want to consult the forums.</p>
<section id="mac" class="level3">
<h3 class="anchored" data-anchor-id="mac">Mac</h3>
<p>To be nice about it, Mac’s Catalina OS was a problematic release to say the least. For our purposes, this meant that there was a period of time where Stan wasn’t viable for many users without extensive workarounds, and issues seemingly arose with every update. This was not specific to Stan, or R, by the way<sup>1</sup>. Then R 4.0 came along and helped some things, but also resulted in new issues. That said, the Stan community were excellent at helping people here, and many of the issues were ultimately resolved by the end of 2020.</p>
<p>Now that Big Sur has been out for a while I get the sense that things have been better there, or at least there aren’t four separate dedicated threads trying to deal with the various problems arising. My own recent luck has been without installation issues on Macs with either OS.</p>
<p><a href="https://discourse.mc-stan.org/search?q=Big%20Sur">Search Mac Issues on Stan Forums</a></p>
</section>
<section id="windows" class="level3">
<h3 class="anchored" data-anchor-id="windows">Windows</h3>
<p>I rarely had installation issues on Windows’ releases, though haven’t had to use it lately. It does require <a href="https://cran.r-project.org/bin/windows/Rtools/">rtools</a> to be installed, which is good to install for R with Windows anyway. If you are starting out, I would install it, then <span class="pack" style="">rstan</span>, then your package of choice (e.g.&nbsp;<span class="pack" style="">brms</span>). Again though, if you have issues, the Stan community will be very helpful.</p>
<p><a href="https://discourse.mc-stan.org/search?q=windows">Search Windows Issues on Stan Forums</a></p>
</section>
<section id="linux" class="level3">
<h3 class="anchored" data-anchor-id="linux">Linux</h3>
<p>I’ve only used Stan with Linux in a cluster computing environment. I generally have not had issues, but it’s not something I’ve done recently, and I don’t have any basic Linux desktop experience. Applied users also need cluster computing on occasion, it’s just that the problems will likely require IT support in that case. Again though, plenty of Stan folks are willing to help.</p>
<p><a href="https://discourse.mc-stan.org/search?q=Linux">Search Linux Issues on Stan Forums</a></p>
</section>
<section id="other-programming-languages-besides-r" class="level3">
<h3 class="anchored" data-anchor-id="other-programming-languages-besides-r">Other programming languages besides R</h3>
<p>If you’re using Stan with Python, Stata, Julia, etc., then you’re using the Stan language directly, and you’re likely already very familiar with the forums and dealing with a variety of issues. That’s not to say that you won’t find something useful here, it’s just that I have nothing to offer you regarding those platforms specifically.</p>
</section>
</section>
<section id="example-data" class="level1">
<h1>Example data</h1>
<div style="text-align: center">
<p><i class="fas fa-database fa-5x" style="padding: 20px; color: #ff5500BF"></i></p>
</div>
<p><br></p>
<p>To start out, I’m going to create some data for us to run some basic models with. To make things interesting, the true underlying model has categorical and continuous covariates, interactions, nonlinear relationships, random effects (observations are clustered in groups), and some variables are collinear. You can skip these details if uninterested, but note that we will be purposely using under- and over-fitted models relative to this one to see what happens.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tidyverse)</span>
<span id="cb1-2"></span>
<span id="cb1-3">create_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(<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;">1000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ng =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1234</span>) {</span>
<span id="cb1-4">  </span>
<span id="cb1-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(seed)</span>
<span id="cb1-6">  </span>
<span id="cb1-7">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the model matrix</span></span>
<span id="cb1-8">  X_mm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(</span>
<span id="cb1-9">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a standard binary</span></span>
<span id="cb1-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">binary_1 =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</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;">1</span>, N, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>),                      </span>
<span id="cb1-11">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a relatively rare categorical</span></span>
<span id="cb1-12">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">binary_2 =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</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;">1</span>, N, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prob =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">05</span>, .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span>)),  </span>
<span id="cb1-13">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># two partly collinear numeric</span></span>
<span id="cb1-14">    mvtnorm<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rmvnorm</span>(N,</span>
<span id="cb1-15">                     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mean =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>),</span>
<span id="cb1-16">                     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sigma =</span> lazerhawk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">create_corr</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">max =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>)))</span>
<span id="cb1-17">  )</span>
<span id="cb1-18">  </span>
<span id="cb1-19">  X_mm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(</span>
<span id="cb1-20">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># intercept</span></span>
<span id="cb1-21">    <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb1-22">    X_mm,</span>
<span id="cb1-23">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># a cubic effect</span></span>
<span id="cb1-24">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">poly</span>(X_mm[,<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;">3</span>))[,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>],</span>
<span id="cb1-25">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># interaction of binary variables</span></span>
<span id="cb1-26">    X_mm[,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>X_mm[,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], </span>
<span id="cb1-27">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># interaction of binary 2 with numeric 1</span></span>
<span id="cb1-28">    X_mm[,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>X_mm[,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>]</span>
<span id="cb1-29">  )</span>
<span id="cb1-30">  </span>
<span id="cb1-31">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># add names</span></span>
<span id="cb1-32">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">colnames</span>(X_mm) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb1-33">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Intercept'</span>,</span>
<span id="cb1-34">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b1'</span>,</span>
<span id="cb1-35">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b2'</span>,</span>
<span id="cb1-36">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x1'</span>,</span>
<span id="cb1-37">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x2'</span>,</span>
<span id="cb1-38">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x3'</span>,</span>
<span id="cb1-39">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x3_sq'</span>,</span>
<span id="cb1-40">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x3_cub'</span>,</span>
<span id="cb1-41">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b1_b2'</span>,</span>
<span id="cb1-42">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b2_x1'</span></span>
<span id="cb1-43">  )</span>
<span id="cb1-44">  </span>
<span id="cb1-45">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># coefficients</span></span>
<span id="cb1-46">  beta <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb1-47">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3.0</span>,   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># intercept</span></span>
<span id="cb1-48">     .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># b1</span></span>
<span id="cb1-49">    <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># b2</span></span>
<span id="cb1-50">     .<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;"># x1</span></span>
<span id="cb1-51">     .<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;"># x2</span></span>
<span id="cb1-52">     .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span> ,  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># x3 </span></span>
<span id="cb1-53">     .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>,   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># x3_sq</span></span>
<span id="cb1-54">    <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>,   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># x3_cub</span></span>
<span id="cb1-55">     .<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;"># b1_b2 </span></span>
<span id="cb1-56">    <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="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># b2_x1</span></span>
<span id="cb1-57">  )</span>
<span id="cb1-58">  </span>
<span id="cb1-59">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># create target variable/linear predictor</span></span>
<span id="cb1-60">  y <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> X_mm <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%*%</span> beta</span>
<span id="cb1-61">  </span>
<span id="cb1-62">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># add random effect</span></span>
<span id="cb1-63">  groups <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>ng, N, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> T))</span>
<span id="cb1-64">  </span>
<span id="cb1-65">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># random effect sd = .5</span></span>
<span id="cb1-66">  re <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(ng, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sd =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)[groups]  </span>
<span id="cb1-67">  </span>
<span id="cb1-68">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># add re and residual noise with sd = 1</span></span>
<span id="cb1-69">  y <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> re <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(N)</span>
<span id="cb1-70">  y <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(y, groups)</span>
<span id="cb1-71">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">colnames</span>(y) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'y'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'group'</span>)</span>
<span id="cb1-72">  </span>
<span id="cb1-73">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tibble</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(X_mm, y))</span>
<span id="cb1-74">}</span></code></pre></div></div>
</div>
<p>If you want to check that the parameters are recovered, you can run something like the following.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">dat <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">create_data</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;">10000</span>)</span>
<span id="cb2-2"></span>
<span id="cb2-3">mod <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> lme4<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lmer</span>(y <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>group <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>group), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(dat[,<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]))</span>
<span id="cb2-4"></span>
<span id="cb2-5">mixedup<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise_model</span>(mod, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ci =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># or just summary(mod)</span></span></code></pre></div></div>
</div>
<p>We do not need much data for our purposes so we’ll set the total sample size to 1000. We’ll drop unnecessary columns (e.g.&nbsp;we’d normally specify interactions via the formula rather than create the columns explicitly), and also make our binary covariates explicit factors, which will make things easier when we want to visualize grouped effects later.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># create the primary data frame</span></span>
<span id="cb3-2"></span>
<span id="cb3-3">main_df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> </span>
<span id="cb3-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">create_data</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;">1000</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb3-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tibble</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb3-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(group, b1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>x3, y) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb3-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb3-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b1 =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(b1),   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># will help with visuals</span></span>
<span id="cb3-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b2 =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(b2)</span>
<span id="cb3-10">  )</span>
<span id="cb3-11"></span>
<span id="cb3-12">main_df</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 1,000 × 7
   group b1    b2         x1      x2     x3     y
   &lt;dbl&gt; &lt;fct&gt; &lt;fct&gt;   &lt;dbl&gt;   &lt;dbl&gt;  &lt;dbl&gt; &lt;dbl&gt;
 1     1 1     1      0.155   0.145  -1.84   4.01
 2     1 1     1     -0.356   1.33   -0.604  3.84
 3     1 1     1     -0.329   0.488  -0.441  3.37
 4     1 1     1      1.08   -1.50    1.00   3.80
 5     1 0     1     -0.563  -1.07   -0.150  1.81
 6     1 1     1     -0.0694 -0.229  -0.387  4.54
 7     1 0     1      0.374   0.606   2.04   4.17
 8     1 0     1      2.06   -0.266   0.168  1.83
 9     2 0     0      0.278   0.0559  1.04   1.58
10     2 1     0      0.184   0.230   0.174  3.56
# ℹ 990 more rows</code></pre>
</div>
</div>
</section>
<section id="essential-steps-for-practical-modeling" class="level1">
<h1>Essential Steps for Practical Modeling</h1>
<div style="text-align: center">
<p><i class="fa fa-shoe-prints fa-5x" style="padding: 20px; color: #ff5500BF"></i></p>
</div>
<p><br></p>
<p>Once data is in hand there are basic steps to take for a practical modeling approach with Stan tools.</p>
<section id="use-standarddefault-priors-for-the-model" class="level5">
<h5 class="anchored" data-anchor-id="use-standarddefault-priors-for-the-model">Use standard/default priors for the model</h5>
<ul>
<li>For common regression models, normal or student t for the (fixed effect) coefficients. You will have to explicitly set this if using <span class="pack" style="">brms</span>, but <span class="pack" style="">rstanarm</span> will have viable defaults already.</li>
<li>Use (half) normal/student-t for variances (esp.&nbsp;hierarchical models). Defaults are usually fine.</li>
<li>Otherwise, look at the <a href="https://github.com/stan-dev/stan/wiki/Prior-Choice-Recommendations">recommendations</a>.</li>
<li>See <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/">Part II</a> for more on choosing priors.</li>
</ul>
</section>
<section id="build-models-in-increasing-complexity" class="level5">
<h5 class="anchored" data-anchor-id="build-models-in-increasing-complexity">Build models in increasing complexity</h5>
<ul>
<li>It’s a good idea not to start with the ‘final’ model, especially in complex settings. If the fitting has issues with simpler models, things will only get worse with more complex models.</li>
<li>Getting model settings squared away earlier will save time later (e.g.&nbsp;setting number of iterations, other options).</li>
</ul>
</section>
<section id="examine-convergence-via-rhat-ess-visualization" class="level5">
<h5 class="anchored" data-anchor-id="examine-convergence-via-rhat-ess-visualization">Examine convergence via Rhat, ESS, visualization</h5>
<ul>
<li>If you run the model and get no warnings or messages, you are okay to proceed to summarize and visualize it in my opinion. Any remaining issues, e.g.&nbsp;poor prediction, are likely to not have obvious solutions, other than things like getting better data, adding additional covariates, revising theory, etc.</li>
<li>Diagnostic plots are the main tool to explore issues that come from warnings.</li>
</ul>
</section>
<section id="examine-model-effectiveness-visually" class="level5">
<h5 class="anchored" data-anchor-id="examine-model-effectiveness-visually">Examine model effectiveness visually</h5>
<ul>
<li><p>There are entire packages at your disposal for visualizing model results such as <span class="pack" style="">bayesplot</span>, <span class="pack" style="">tidybayes</span>, etc. However, standard plots can be called from <span class="pack" style="">rstanarm</span> or <span class="pack" style="">brms</span> functions, which are wrappers for <span class="pack" style="">bayesplot</span> functions.</p></li>
<li><p><a href="https://mc-stan.org/bayesplot/reference/PPC-overview.html">Posterior predictive checks</a> are a fundamental part of Bayesian analysis.</p></li>
<li><p>Avoid using approaches that are merely substitutes for the null hypothesis test you would have done in the non-Bayesian setting (e.g.&nbsp;using <a href="https://statmodeling.stat.columbia.edu/2019/09/10/i-hate-bayes-factors-when-theyre-used-for-null-hypothesis-significance-testing/">bayes factors</a>).</p></li>
</ul>
</section>
<section id="compare-models-using-loo-posterior-probabilities-of-models" class="level5">
<h5 class="anchored" data-anchor-id="compare-models-using-loo-posterior-probabilities-of-models">Compare models using loo, posterior probabilities of models</h5>
<ul>
<li><p>Compare models via predictive capabilities (<em>l</em>eave-<em>o</em>ne-<em>o</em>ut approaches, see <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/">Part II</a>).</p></li>
<li><p>There is no ‘best’ model in Bayesian approach or otherwise. Consider model averaging for final predictions.</p></li>
<li><p>It is not necessary to automatically prefer simpler models, though it may make things easier to do so in some contexts.</p></li>
</ul>
<p>Assuming you have no problems in the above process, you have more or less fulfilled the basic requirements to do standard analyses in Bayesian form. Great!</p>
</section>
</section>
<section id="warnings-what-they-mean-and-what-to-do-about-them" class="level1 page-columns page-full">
<h1>Warnings, What They Mean, and What to do About Them</h1>
<div style="text-align: center">
<p><i class="fas fa-exclamation-triangle fa-5x" style="padding: 20px; color: #ff5500BF"></i></p>
</div>
<p>Of course, if it was always that easy, we wouldn’t be posting this. There are a few warnings that you’re bound to come across at some point in modeling with the Stan ecosystem. We’ll cover these, as well as the most common solutions.</p>
<p>Primary reference: <a href="https://mc-stan.org/misc/warnings.html">Brief Guide to Stan’s Warnings</a></p>
<section id="rhat-effective-sample-size" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="rhat-effective-sample-size">Rhat &amp; Effective Sample Size</h2>
<p>We will start with a simple standard regression model that we know is not adequate. We will use default priors<sup>2</sup> and run very few iterations.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># no priors, no complexity, all default settings, few iterations</span></span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(brms)</span>
<span id="cb5-3"></span>
<span id="cb5-4">model_start_100 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(</span>
<span id="cb5-5">  y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> b1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x3, </span>
<span id="cb5-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> main_df,</span>
<span id="cb5-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>,</span>
<span id="cb5-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">verbose =</span> F,</span>
<span id="cb5-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span></span>
<span id="cb5-10">)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: The largest R-hat is 1.1, indicating chains have not mixed.
Running the chains for more iterations may help. See
https://mc-stan.org/misc/warnings.html#r-hat</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: Bulk Effective Samples Size (ESS) is too low, indicating posterior means and medians may be unreliable.
Running the chains for more iterations may help. See
https://mc-stan.org/misc/warnings.html#bulk-ess</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: Tail Effective Samples Size (ESS) is too low, indicating posterior variances and tail quantiles may be unreliable.
Running the chains for more iterations may help. See
https://mc-stan.org/misc/warnings.html#tail-ess</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summary</span>(model_start_100)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: y ~ b1 + b2 + x1 + x2 + x3 
   Data: main_df (Number of observations: 1000) 
  Draws: 4 chains, each with iter = 100; warmup = 50; thin = 1;
         total post-warmup draws = 200

Regression Coefficients:
          Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept     2.72      0.15     2.44     3.00 1.10       36      144
b11           0.83      0.06     0.71     0.94 1.01      140      115
b21          -0.12      0.15    -0.41     0.15 1.10       35       82
x1            0.03      0.03    -0.04     0.09 1.00      310      239
x2           -0.04      0.03    -0.10     0.02 1.00      355      237
x3            0.28      0.03     0.22     0.35 1.04      349      132

Further Distributional Parameters:
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma     1.10      0.02     1.06     1.15 1.00      220      145

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).</code></pre>
</div>
</div>

<div class="no-row-height column-margin column-container"><div class="">
<p>As is common in other R models, for factors, the effect is the stated category vs.&nbsp;the reference. Since we only have binary variables, b11 is show the level 1 vs.&nbsp;level 0 (reference) for the first binary covariate.</p>
</div></div><p>The warnings about Rhat and effective sample size (ESS) are likely to pop up if you use default iterations for more complex models. They mostly regard the efficiency of the sampling process, and whether you have enough samples to have stable parameter estimates. Ideally Rhat is close to 1.0, and ESS is at least a notable percentage of the total posterior samples (e.g.&nbsp;50%).</p>
<p>The fix for these warnings is usually simple, just let the model run for more iterations beyond your warmup. The default is 2000 iterations, with warmup half of that. Warmup iterations are not used in calculation of parameter estimates, so you can just increase the number of iterations relative to it, or increase both by only increasing the <code>iter</code> argument.</p>
<p>In the following, we plot the estimated values across each iteration for each chain, called a <em>trace plot</em>, as well as the <em>density plot</em> of the values from the entire chain. From this we could see that things might be problematic (e.g.&nbsp;we’d want more symmetric density plots for the regression coefficients), but only if you are used to looking at these things, so it will take some practice.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pars =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x1'</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'combo'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/model-start-trace-dens-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>To get some intuition for what you would expect, just plot a series from a normal distribution.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">ggplot2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">qplot</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">geom =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'line'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/rnorm-trace-dens-1.png" class="img-fluid figure-img" style="width:50.0%"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1">ggplot2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">qplot</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;">rnorm</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">geom =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'density'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/rnorm-trace-dens-2.png" class="img-fluid figure-img" style="width:50.0%"></p>
</figure>
</div>
</div>
</div>
<p>Other plots allow us to look at the same sorts of things from a different perspective, or break out results by each chain.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'areas'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/area-violin-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pars =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x1'</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'violin'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/area-violin-2.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>While things seem okay, if we single out a particular chain, we might think otherwise. In this case, the <code>Intercept</code> and <code>b2</code> coefficients may be problematic, given they do not seem to vary as much as the others (chain 2 for example, but also for other chains).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">highlight =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'trace_highlight'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/trace-highlight-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Some suggest to look at <em>rank plots</em> instead of traditional trace plots. Really, all we’ve changed is looking for something ‘fuzzy’, to looking for something ‘approximately uniform’, so my opinion is that it’s not much of an improvement visually or intuitively. In general, histograms, which are variants of bar charts, are rarely an improvement for any visualization. If you do use it, you can use an overlay approach to see if the ranks are mixing, but this looks a lot like what I’d be looking for from a trace plot.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb17-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pars =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x1'</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'rank_hist'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/rank-plots-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><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;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pars =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b1'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b2'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x1'</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'rank_overlay'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/rank-plots-2.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="some-details" class="level2">
<h2 class="anchored" data-anchor-id="some-details">Some details</h2>
<p>A little more detail will possibly provide additional understanding, and also some guidance, when looking at your own results.</p>
<section id="rhat" class="level3">
<h3 class="anchored" data-anchor-id="rhat">Rhat</h3>
<p>The <img src="https://latex.codecogs.com/png.latex?%5Chat%7BR%7D"> (or Rhat) statistic measures the ratio of the average variance of samples within each chain to the variance of the pooled samples across chains. If all chains are at equilibrium, these will be the same and <img src="https://latex.codecogs.com/png.latex?%5Chat%7BR%7D"> will be 1.0. If the chains have not converged to a common distribution, the <img src="https://latex.codecogs.com/png.latex?%5Chat%7BR%7D"> statistic will be greater than one.</p>
<p><strong>What we want</strong>: values near 1.0 (&lt; 1 okay) and less than 1.05</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'rhat'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/rhat-plot-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="ess" class="level3">
<h3 class="anchored" data-anchor-id="ess">ESS</h3>
<p>Effective sample size is an estimate of the effective number of independent draws from the posterior distribution of the parameter of interest. Because the draws within a chain are not independent if there is autocorrelation, the effective sample size will typically be smaller than the total number of iterations, but the calculation of this statistic is bit more art than science, and can even be greater than the number of posterior draws. Note also that the plot is based on slightly different values than reported by the <span class="pack" style="">brms</span> summary function.</p>
<ul>
<li><em>Bulk ESS</em>: ESS for the mean/median (<code>n_eff</code> in <span class="pack" style="">rstanarm</span>). Tells us whether the parameter estimates are stable.</li>
<li><em>Tail ESS</em>: ESS for the 5% and 95% quantiles. Tells us whether the interval estimates for the parameters are stable. Tail-ESS can help diagnose problems due to different scales of the chains and slow mixing in the tails.</li>
</ul>
<p><strong>What we want</strong>: ESS &gt; 10% percent of total posterior samples for sure, but &gt; 50% is best. At least 100 is desired for decent estimates of autocorrelation. For Bulk-ESS we want &gt; 100 times the number of chains.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'neff'</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># &lt; .1 problem</span></span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/neff-plot-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="trace-plot" class="level3">
<h3 class="anchored" data-anchor-id="trace-plot">Trace plot</h3>
<p>Shows the estimated parameter values at each iteration. In general you would like a random bouncing around an average value.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'trace'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/trace-plot-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p><strong>What we want</strong>: Something like random normal draws over a series. Trace plots in general should look ‘grassy’, or like a ‘fuzzy caterpillar’, which might not be very descriptive, but deviations are usually striking and obvious in my experience. If you see chains that look like they are getting stuck around certain estimates, or separating from one another, this would indicate a serious problem. If the chains are not converging with one another, you were probably already getting warnings and messages.</p>
</section>
<section id="density-plot" class="level3">
<h3 class="anchored" data-anchor-id="density-plot">Density plot</h3>
<p>Shows the density of the posterior draws for the parameters.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dens'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/dens-plot-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p><strong>What we want</strong>: For the density plots of regression coefficients, these should be roughly normal looking. For variance parameters you may see skewness, especially if the estimate is relatively near zero with smaller data sets. In general, we would not want to see long tails or bimodality for the typical parameters of interest with models you’d be doing with <span class="pack" style="">rstanarm</span> and <span class="pack" style="">brms</span>.</p>
</section>
<section id="rank-plot" class="level3">
<h3 class="anchored" data-anchor-id="rank-plot">Rank plot</h3>
<p>From <span class="pack" style="">bayesplot</span> help file:</p>
<blockquote class="blockquote">
<p>Whereas traditional trace plots visualize how the chains mix over the course of sampling, rank histograms visualize how the values from the chains mix together in terms of ranking. An ideal plot would show the rankings mixing or overlapping in a uniform distribution.</p>
</blockquote>
<div class="cell">
<div class="code-copy-outer-scaffold"><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"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'rank_hist'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/rank-plot-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p><strong>What we want</strong>: Uniform distribution, a good mixing of lines for the overlay version.</p>
</section>
<section id="acf-plot" class="level3">
<h3 class="anchored" data-anchor-id="acf-plot">ACF plot</h3>
<p>The <em>acf</em>, or <em>autocorrelation</em> function plot, is exactly the same thing you’d visualize for any time series. It is a plot of a series of correlations of a parameter with specific lags of itself. <em>Autocorrelation does not bias estimates</em>, but increased autocorrelation may suggest a more inefficient/slower exploration of the parameter space. At lag zero, the series estimates are perfectly correlated with themselves, so that’s where the plot usually starts.</p>
<p><strong>What we want</strong>: Quick drop off, but not really that important. By the time you find it’s an issue, your model has already run.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">mcmc_plot</span>(model_start_100, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'acf'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/acf-plot-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="efficiency-plots" class="level3">
<h3 class="anchored" data-anchor-id="efficiency-plots">Efficiency plots</h3>
<p>I have seen these often recommended, but I’m not aware of a package does them, though it seems they may make their way to <span class="pack" style="">shinystan</span> at some point. Aki Vehtari has supplied a walk-through and some code (see the <a href="Resources">resources section</a> below), but there isn’t really documentation for the functions, and they likely won’t work outside of <span class="pack" style="">rstan</span> objects, or at least I had limited success with applying them to <span class="pack" style="">brms</span> objects. Furthermore, these are getting into waters that are beyond what I’d expect applied users to be wading through.</p>
</section>
<section id="solution-for-rhatess-warnings" class="level3">
<h3 class="anchored" data-anchor-id="solution-for-rhatess-warnings">Solution for Rhat/ESS warnings</h3>
<p>To summarize, the general solution to Rhat and ESS warnings is simply to do more iterations (relative to the warmup). To keep posterior samples and model objects from becoming unwieldy in size<sup>3</sup>, consider thinning also. Thinning saves only a select amount of the available posterior samples. For example, setting <code>thin = 10</code> means only every tenth sample will be saved. This will also reduce autocorrelation, as the draws retained after thinning are not as correlated with one another as successive draws would be. However, if you thin too much, you may not have enough for effective sample size.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># default with 4 chains, 1000 warmup 2000 total = 4*(2000 - 1000) = 4000 post-warmup draws</span></span>
<span id="cb25-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(model)</span>
<span id="cb25-3"></span>
<span id="cb25-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 4*(4000 - 2000) = 8000 posterior draws</span></span>
<span id="cb25-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(model, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">warmup =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4000</span>)</span>
<span id="cb25-6"></span>
<span id="cb25-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 4*(4000 - 2000)/8 = 1000 posterior draws</span></span>
<span id="cb25-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(model, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">warmup =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">thin =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>)</span></code></pre></div></div>
</div>
</section>
</section>
<section id="bfmi-low" class="level2">
<h2 class="anchored" data-anchor-id="bfmi-low">BFMI low</h2>
<p>You may see a warning that says some number of chains had an ‘estimated Bayesian Fraction of Missing Information (BFMI) that was too low’. This implies that the adaptation phase of the Markov Chains did not turn out well, and those chains likely did not explore the posterior distribution efficiently. For more details on this diagnostic, you can see <a href="https://arxiv.org/abs/1604.00695">Betancourt’s article</a>, but this will almost surely be too technical for many applied and even more advanced users.</p>
<p>In this case, the problem here is often remedied by just adding more iterations. I typically keep to 1000 posterior samples, which makes for nicer visualizations of distributions without creating relatively large model objects. However, you may need more to get a satisfactory result.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">model_start <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">update</span>(</span>
<span id="cb26-2">  model_start_100,</span>
<span id="cb26-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">warmup =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2000</span>,</span>
<span id="cb26-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2250</span>,      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 1000 posterior draws</span></span>
<span id="cb26-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cores =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,</span>
<span id="cb26-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span></span>
<span id="cb26-7">) </span></code></pre></div></div>
</div>
<p>In this case, we no longer have any warnings, and even one of our more problematic coefficients looks fine now.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb27-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summary</span>(model_start)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: y ~ b1 + b2 + x1 + x2 + x3 
   Data: main_df (Number of observations: 1000) 
  Draws: 4 chains, each with iter = 2250; warmup = 2000; thin = 1;
         total post-warmup draws = 1000

Regression Coefficients:
          Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept     2.72      0.20     2.32     3.10 1.00     1583      938
b11           0.83      0.07     0.69     0.97 1.00     1711      895
b21          -0.12      0.20    -0.50     0.29 1.01     1509      864
x1            0.03      0.03    -0.04     0.10 1.00     1504      947
x2           -0.03      0.04    -0.11     0.05 1.00     1279      803
x3            0.28      0.04     0.21     0.35 1.00     1136      810

Further Distributional Parameters:
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma     1.11      0.02     1.06     1.15 1.00     1357      735

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb29" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb29-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(model_start, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">par =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b2'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/model-start-checks-show-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<section id="solution-for-low-bfmi" class="level4">
<h4 class="anchored" data-anchor-id="solution-for-low-bfmi">Solution for low BFMI</h4>
<p>If there aren’t other serious problems, add more iterations to deal with low BFMI. In some cases, switching from a heavy-tailed prior (e.g.&nbsp;student t) to something else (e.g.&nbsp;normal) would be helpful, but some other approaches typically would involve having to write Stan code directly to <a href="https://mc-stan.org/docs/2_18/stan-users-guide/reparameterization-section.html">reparameterize the model</a>. Otherwise, you may need to approach it similarly to the problem of divergent transitions.</p>
</section>
</section>
<section id="tree-depth" class="level2">
<h2 class="anchored" data-anchor-id="tree-depth">Tree Depth</h2>
<p>Tree depth is a more technical warning that has to do with the details of Hamiltonian Monte Carlo. Practically speaking:</p>
<blockquote class="blockquote">
<p>Lack of convergence and hitting the maximum number of leapfrog steps (equivalently maximum tree depth) are indicative of improper posteriors ~ Stan User Guide</p>
</blockquote>
<p>Sometimes you’ll get a warning about hitting maximum tree depth, and without getting overly technical, the fix is easy enough. Just set the maximum higher.</p>
<section id="solution-for-max-tree-depth" class="level4">
<h4 class="anchored" data-anchor-id="solution-for-max-tree-depth">Solution for max tree depth</h4>
<p>Use the <code>control</code> argument to increase the value beyond the default of 10.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">model_update_treedepth <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">update</span>(</span>
<span id="cb30-2">  model,</span>
<span id="cb30-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">control =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">max_tree_depth =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>)</span>
<span id="cb30-4">)</span></code></pre></div></div>
</div>
</section>
</section>
<section id="divergent-transitions" class="level2">
<h2 class="anchored" data-anchor-id="divergent-transitions">Divergent Transitions</h2>
<p><em>Divergent transitions</em> are a technical issue that indicates something may be notably wrong with the data or model (<a href="https://mc-stan.org/docs/2_24/reference-manual/divergent-transitions.html">technical details</a>). They indicate that the sampling process has ‘gone off the rails’, and that the divergent iteration’s results, and anything based on them (i.e.&nbsp;subsequent draws, parameter estimates), can’t be trusted. Unlike the other problems we’ve discussed, this is more difficult to navigate.</p>
<p>Why might this happen?</p>
<ul>
<li>insufficient data for the model’s complexity</li>
<li>poor model</li>
<li>high collinearity</li>
<li>improper or otherwise problematic priors</li>
<li>separability (logistic regression)</li>
<li>any number of other things</li>
</ul>
<p>As an example, I’ll make an overly complex model with only a small random sample of the data, improper priors, and use very few warmups/iterations.</p>
<div class="cell" data-cache.extra="12">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb31" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb31-1">model_problem <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(</span>
<span id="cb31-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bf</span>(</span>
<span id="cb31-3">    y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> b1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>b2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x3<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>group),</span>
<span id="cb31-4">    sigma <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>b2</span>
<span id="cb31-5">  ),</span>
<span id="cb31-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data   =</span> main_df <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;">slice_sample</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prop =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>),</span>
<span id="cb31-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> student,</span>
<span id="cb31-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cores  =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,</span>
<span id="cb31-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">warmup =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb31-10">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter   =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1005</span>,</span>
<span id="cb31-11">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">thin   =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,</span>
<span id="cb31-12">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed   =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span></span>
<span id="cb31-13">)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: There were 206 divergent transitions after warmup. See
https://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
to find out why this is a problem and how to eliminate them.</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: Examine the pairs() plot to diagnose sampling problems</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: The largest R-hat is 2.21, indicating chains have not mixed.
Running the chains for more iterations may help. See
https://mc-stan.org/misc/warnings.html#r-hat</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: Bulk Effective Samples Size (ESS) is too low, indicating posterior means and medians may be unreliable.
Running the chains for more iterations may help. See
https://mc-stan.org/misc/warnings.html#bulk-ess</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: Tail Effective Samples Size (ESS) is too low, indicating posterior variances and tail quantiles may be unreliable.
Running the chains for more iterations may help. See
https://mc-stan.org/misc/warnings.html#tail-ess</code></pre>
</div>
</div>
<p><br></p>
<p>So what do we do in this case? Well let’s start with visual inspection.</p>
<section id="visualization-pairs-plot" class="level4">
<h4 class="anchored" data-anchor-id="visualization-pairs-plot">Visualization: Pairs plot</h4>
<p>A diagnostic tool that is typically suggested to look at with divergent transitions is the <span class="emph" style="">pairs plot</span>. It is just a scatterplot matrix of the parameters estimates (and log posterior value), but it suffers from a few issues. The plot is slow to render even with few parameters, and simply too unwieldy to use for many typical modeling situations. If you somehow knew in advance which parameters were causing issues, you could narrow it down by only looking at those parameters. But if you knew which parameters were the problem, you wouldn’t need the pairs plot.</p>
<p>Another issue is that it isn’t what you think it is at first glance. The upper diagonal is not just the flipped coordinates of the lower diagonal like every other scatterplot matrix you’ve seen. The chains are split such that half are used for the above diagonal plots, and the other for the lower, with the split being based on the amount of numerical error (above or below the median). I suspect this may not help applied users interpret things, but the gist is, that if your red points show up only on the upper diagonal, changing the <code>adapt_delta</code> part of the control argument may help (see below), otherwise it likely won’t<sup>4</sup>.</p>
<p>Let’s take a look at the pairs plot anyway. I’ll use <code>hex</code> bins instead of standard points because the point plots have no transparency by default. In addition, we’ll use a density plot on the diagonal, instead of the histogram.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb37" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb37-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcmc_plot</span>(</span>
<span id="cb37-2">  model_problem,</span>
<span id="cb37-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pars =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b_b11'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b_b21'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b_x1'</span>),</span>
<span id="cb37-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pairs'</span>,</span>
<span id="cb37-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">diag_fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dens'</span>,</span>
<span id="cb37-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">off_diag_fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'hex'</span>,</span>
<span id="cb37-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fixed =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb37-8">)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/pairs-plot-model-start-complex-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>With problematic cases, what you might see on the off-diagonal plots is some sort of ‘funneling’, which would indicate where the sampler is getting stuck in the parameter space. However, this visual notion isn’t defined well, as it may be happening without being obvious, displaying just a bump, or just some weird patterns as above. But you’ll also regularly see correlated parameters, but it’s unclear whether these might necessarily be a problem in a given situation.</p>
<p>For the initial model we ran, the pairs plot for all parameters takes several seconds to produce, and even with the hex option, it is still difficult to parse without closer inspection. It shows the intercept and <code>b2</code> parameters to be notably correlated, possibly indirectly due to the poor priors.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">mcmc_plot</span>(</span>
<span id="cb38-2">  model_start_100,</span>
<span id="cb38-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pairs'</span>,</span>
<span id="cb38-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">off_diag_fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'hex'</span>,</span>
<span id="cb38-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">diag_fun =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dens'</span></span>
<span id="cb38-6">)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/pairs-plot-model-start-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p><strong>What we want</strong>: Roughly little correlation among parameters, mostly symmetric densities for typical regression parameters.</p>
</section>
<section id="visualization-parallel-coordinates-plot" class="level4">
<h4 class="anchored" data-anchor-id="visualization-parallel-coordinates-plot">Visualization: Parallel Coordinates Plot</h4>
<p>It is also suggested to look at parallel coordinates plots, but unfortunately there are issues with these plots as well. The order of the variable/parameter axis is arbitrary, and yet the order can definitely influence your perception of any patterns. Also, unless everything is on similar scales, they simply aren’t going to be very useful, but even if you scale your data in some fashion, the estimates given divergent transitions may be notably beyond a reasonable scale.</p>
<p>As in our pairs plot, we’d be looking for a pattern among the divergences, specifically a concentration for a parameter where the lines seemingly converge to a point. If this isn’t the case, the divergences are probably false positives<sup>5</sup>. I had to add some <span class="pack" style="">ggplot</span> options to help this to be more legible, and you will likely have to as well. In the following, you might think the <code>b_sigma_x1</code> coefficient for dispersion is a problem, which might suggest we need to rethink the prior for it. In reality it’s likely just that it’s being estimated to be near zero, as it should be, especially since non-divergent transitions are also bouncing around that value. For the most part we don’t see much pattern here.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb39" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb39-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcmc_parcoord</span>(</span>
<span id="cb39-2">  model_problem,</span>
<span id="cb39-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pars =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vars</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matches</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'^b'</span>)),</span>
<span id="cb39-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, </span>
<span id="cb39-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">01</span>,</span>
<span id="cb39-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">np =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nuts_params</span>(model_problem),  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># without this div trans won't be highlighted</span></span>
<span id="cb39-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">np_style =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parcoord_style_np</span>(</span>
<span id="cb39-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">div_color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#ff5500"</span>,</span>
<span id="cb39-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">div_size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb39-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">div_alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb39-11">  )</span>
<span id="cb39-12">) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb39-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">guides</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">guide_axis</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n.dodge =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb39-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span>(</span>
<span id="cb39-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">axis.text.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_text</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>),</span>
<span id="cb39-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">panel.grid.major.x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">element_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#00AAFF80'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb39-17">  )</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/index_files/figure-html/par-coord-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p><strong>What we want</strong>: Roughly no obvious pattern. If the divergence lines are not showing any particular concentration, it could be that these are false positives.</p>
</section>
<section id="solution-for-divergent-transitions" class="level4">
<h4 class="anchored" data-anchor-id="solution-for-divergent-transitions">Solution for divergent transitions</h4>
<p>Unfortunately the solution to divergent transitions is usually not straightforward. The typical starting point for solving the problem of divergent transitions is to use the control argument to increase <code>adapt_delta</code>, for example, from .80 to .99<sup>6</sup>, and let your model have more warmup/total iterations, which is the primary issue here. In the cases I see for myself and clients, increasing <code>adapt_delta</code> rarely helps, but it doesn’t hurt to try. I often will just start with it increased for more complex models, just to save messing with it later.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">model <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(..., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">control =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">adapt_delta =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">99</span>))</span></code></pre></div></div>
</div>
<p>Aside from that you will have to look more deeply, including issues with priors, model specification, and more. I find this problem often comes from poor data (e.g.&nbsp;not scaled, possible separation in logistic models, etc.), combined with a complex model (e.g.&nbsp;complicated random effects structure), and beyond that, the priors may need to be amended. You should at least not have uniform priors for any parameter, and as we’ll see in <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/">Part II</a>, you can use a simulation approach to help choose better priors. Often these data and prior checks are a better approach to solving the problem than doing something after the fact. You may also need to simplify the model to better deal with your data nuances. As an example, for mixed models, it may be that some variance components are not necessary.</p>
<p>Some solutions offered on the forums assume you are coding in Stan directly, such as reparameterizing your model, using specific types of priors, etc. If you are writing Stan code rather than using a modeling package, you definitely need to double check it, as typos or other mistakes can certainly result in a problematic model. However, this post is for those using modeling packages, so I will not offer such remedies, and they are usually not obvious anyway.</p>
</section>
</section>
<section id="other-messages" class="level2">
<h2 class="anchored" data-anchor-id="other-messages">Other messages</h2>
<p>Certain builds of <span class="pack" style="">rstan</span> for some types of settings (e.g.&nbsp;specific operating systems) will often have warnings or other messages. Sometimes it looks like a bunch of gobbledygook, which is typically something happening at the C++ level. If your model runs and produces output despite these messages, you can typically ignore them in most cases. Even then, you should look it up on the forums just to be sure.</p>
<section id="parser-warnings" class="level3">
<h3 class="anchored" data-anchor-id="parser-warnings">Parser warnings</h3>
<p>Parser warnings are either a deprecation warning, or another more serious kind (Jacobian). The latter will not happen if you’re using higher level interfaces (e.g.&nbsp;<span class="pack" style="">brms</span>), rather than programming in Stan directly. The other kind, deprecation warnings, are not something you can do anything about, but the developer of the package will likely need to make minor changes to the code to avoid them in the future. I’ve never seen parser warnings from using <span class="pack" style="">rstanarm</span> or <span class="pack" style="">brms</span>.</p>
</section>
<section id="compilation-warnings" class="level3">
<h3 class="anchored" data-anchor-id="compilation-warnings">Compilation warnings</h3>
<p>Compiler warnings happen regularly and indicate something going on at the compiler level, typically that something in Stan is being compiled but not used. You can ignore these.</p>
</section>
<section id="package-warnings" class="level3">
<h3 class="anchored" data-anchor-id="package-warnings">Package warnings</h3>
<p>Like any good package, when things go unexpectedly, or just to be informative, modeling packages like <span class="pack" style="">rstanarm</span> and <span class="pack" style="">brms</span> will provide you messages or warnings. These do not have to do with the Stan part of things. For example, <span class="pack" style="">brms</span> will warn you that it will drop cases with missing values.</p>
<blockquote class="blockquote">
<p><code>Rows containing NAs were excluded from the model.</code></p>
</blockquote>
<p>Some issues can be more subtle. For example, you may get a message that the model is compiling but then nothing happens. This might be because of a typo in a distribution name for your priors, or some similar goof<sup>7</sup>.</p>
</section>
<section id="solutions-for-other-messages" class="level3">
<h3 class="anchored" data-anchor-id="solutions-for-other-messages">Solutions for other messages</h3>
<p>If you are using a package to interface with Stan and not having an issue with the model (i.e.&nbsp;it runs, converges), these messages can largely be ignored, unless it is a warning from the package itself, which typically should be investigated.</p>
</section>
</section>
<section id="model-comparison-problems" class="level2">
<h2 class="anchored" data-anchor-id="model-comparison-problems">Model Comparison Problems</h2>
<p>For a discussion of loo and related issues, see <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/">Part II</a>.</p>
</section>
</section>
<section id="other-issues" class="level1">
<h1>Other Issues</h1>
<section id="but-its-slow" class="level2">
<h2 class="anchored" data-anchor-id="but-its-slow">But it’s slow!</h2>
<p>Another problem people seem to be concerned with is the speed of the analysis. If you have a lot of data, or more to the point, a lot of parameters, your model can be very slow. For standard models with <span class="pack" style="">rstanarm</span> and <span class="pack" style="">brms</span>, there may be no real benefit doing it Bayesian style if you have millions of data points and simpler models. If your model is only taking a couple minutes, then you really have nothing to complain about- watch some YouTube or something while it runs. If your model takes on the order of hours, work with less data or simpler models until you have your modeling code, plots, etc. squared away. At that point you can run your primary analysis and wait it out. A slow model may also be indicative of a poorly specified/understood model, so you may have to think hard about how you are approaching the problem.</p>
<section id="solutions-for-a-slow-model" class="level3">
<h3 class="anchored" data-anchor-id="solutions-for-a-slow-model">Solutions for a slow model</h3>
<ul>
<li>For any model, Bayesian or otherwise, doing things like standardizing, logging or other variable transformations will put parameters in more reasonable domains, resulting in a more manageable estimation process. For example, if you standardize predictors, then the coefficients are on similar scales and a <code>Normal(0, 1)</code> prior can typically be applied.</li>
<li>Using more informative priors can avoid exploring areas of the posterior that aren’t going to lead to plausible results. We will show how to do this in <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/">Part II</a>.</li>
<li>Use less iterations if there are no other issues.</li>
<li>If possible, work with less data or simpler models until ready for the full model.</li>
<li>If possible, work with a different version of the model that can still answer the question of interest. For example, if an ordinal model is causing a lot of issues, and you’re not interested in category specific probabilities, just treat the target variable as numeric<sup>8</sup>.</li>
<li>Stop fishing/p-hacking/torturing your data so that you don’t have to run dozens of models. You’re likely not to care if the models takes hours if you only run them once or twice.</li>
</ul>
<!-- so that distill can know this isn't part of the previous list -->
<p><br></p>
</section>
</section>
<section id="shinystan" class="level2">
<h2 class="anchored" data-anchor-id="shinystan">shinystan</h2>
<p>The <span class="pack" style="">shinystan</span> package makes exploring model diagnostics actually fun! Using <span class="func" style="">launch_shinystan</span> on a model opens a browser window, providing interactive visualizations to help you see what’s going on with it. You can look at many of the previous plots, plus a few others we haven’t shown.</p>
<p>Unfortunately the documentation in the browser doesn’t really tell you what to look for in these plots. The glossary contains information that is likely overly technical for applied users, and if there is a problem, there’s not really a whole lot to go on. In addition, some plots are difficult to use (e.g.&nbsp;trying to assess whether overlapping histograms are similar), or are probably only useful if you have very obvious problem (e.g.&nbsp;lots of divergent transitions). As an example, consider the tree depth plots. What would be good here?</p>
<p><img src="https://m-clark.github.io/img/howtobayes/max_treedepth.png" style="display:block; margin: 0 auto; width: 100%"></p>
<p>The documentation tells you the value should be somewhere between 0 and whatever <code>max_treedepth</code> is set at. If they are ‘large’, the documentation states the problem could be due to different things, but the solutions are to either reparameterize of the model (probably not possible unless using Stan code directly), or just increase the value. It doesn’t seem to tell you what those plots are supposed to look like, and unfortunately that severely limits their utility. The divergence and energy plots are similarly under-explained. Many refer users to Betancourt’s wonderful articles on the details, but these are far too technical for those not already steeped in the approach<sup>9</sup>.</p>
<p>All that said, luckily there is a nice <a href="https://mc-stan.org/bayesplot/articles/visual-mcmc-diagnostics.html">walkthrough</a> if you do have a hankering to go down that path, and provides more details on the statistics and what you should be looking for in the visualizations.</p>
</section>
</section>
<section id="summary-the-practical-approach-to-dealing-with-model-problems" class="level1">
<h1>Summary: The Practical Approach to Dealing with Model Problems</h1>
<p>For applied analysts, you can do a couple things when faced with warnings or just otherwise assessing the model integrity. I would suggest first focusing on the density and trace plots for parameters. You can then examine other visualizations that might be appropriate to the problem, and take the appropriate steps outlined above to try and solve those issues. Pay extra attention to parameters with relatively low effective sample sizes, as these are the ones the model is struggling to estimate.</p>
<p>Many of the problems can be solved by increasing the warmup and total number of iterations. After that, setting control parameters may be enough. For more serious issues, you may need to try different priors or even a different model. If none of the above solves your problems, you may be trying too complex of a model for your data, have a data-specific problem, or some other issue.</p>
<p>In general, doing Bayesian analysis can be easy, and hopefully it will be for you. Many common problems have simple solutions, and the more serious ones will only make you a better Bayesian though the efforts you take to solve them. Rather than see them as a nuisance, see them as a learning opportunity, and you’ll enjoy your results even more when you finally resolve them. Remember that you may not be in your comfort zone, and that’s okay! Things will come around eventually, and you’ll solve these problems more easily in the future!</p>
<p>On to <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/">PART II: Do Bayes Better</a>.</p>
</section>
<section id="resources" class="level1">
<h1>Resources</h1>
<section id="general" class="level2">
<h2 class="anchored" data-anchor-id="general">General</h2>
<ul>
<li><p><a href="https://avehtari.github.io/">Aki Vehtari’s website</a> has demos and explanation for things like model comparison, Rhat/Neff, and more.</p></li>
<li><p><a href="https://mc-stan.org/bayesplot/articles/visual-mcmc-diagnostics.html">bayesplot Vignette for Diagnostic Plots</a></p></li>
<li><p><a href="https://jrnold.github.io/bayesian_notes/">Jeffrey Arnold’s Bayesian Notes</a> has nice examples of many models and good summaries otherwise.</p></li>
</ul>
<p><a href="m-clark.github.io/bayesian-basics/">Bayesian Basics</a>, an applied overview of Bayesian analysis with Stan as the backdrop.</p>
</section>
<section id="priors" class="level2">
<h2 class="anchored" data-anchor-id="priors">Priors</h2>
<p><a href="https://github.com/stan-dev/stan/wiki/Prior-Choice-Recommendations">Prior Choice Recommendations</a> by the Stan group.</p>
<ul>
<li><a href="https://cran.r-project.org/web/packages/rstanarm/vignettes/priors.html">rstanarm vignette</a></li>
</ul>
</section>
<section id="rhatess" class="level2">
<h2 class="anchored" data-anchor-id="rhatess">Rhat/ESS</h2>
<ul>
<li><p><a href="https://mc-stan.org/docs/2_24/reference-manual/effective-sample-size-section.html">Stan Reference on Effective Sample Size</a></p></li>
<li><p><a href="https://projecteuclid.org/euclid.ba/1593828229">Vehtari et al.&nbsp;on Rank plots</a> for details.</p></li>
<li><p><a href="https://avehtari.github.io/rhat_ess/rhat_ess.html">Vehtari’s appendix for the above</a> (probably more accessible)</p></li>
<li><p><a href="https://github.com/avehtari/rhat_ess/blob/master/code/monitorplot.R">Vehtari’s code for efficiency plots</a>, <a href="https://github.com/avehtari/rhat_ess/blob/master/code/monitornew.R">Code for functions</a></p></li>
</ul>
</section>
<section id="divergence" class="level2">
<h2 class="anchored" data-anchor-id="divergence">Divergence</h2>
<ul>
<li><p><a href="https://mc-stan.org/docs/2_24/reference-manual/divergent-transitions.html">Stan Reference on Divergent Transitions</a></p></li>
<li><p><a href="https://discourse.mc-stan.org/t/divergent-transitions-a-primer/17099">Divergent Transitions A Primer</a></p></li>
<li><p><a href="https://mc-stan.org/users/documentation/case-studies/divergences_and_bias.html">Case study: Divergences and Bias</a></p></li>
</ul>
</section>
<section id="other-warnings" class="level2">
<h2 class="anchored" data-anchor-id="other-warnings">Other warnings</h2>
<ul>
<li><a href="https://mc-stan.org/misc/warnings.html#preruntime-warnings">Brief Guide to Stan’s Warnings</a></li>
</ul>
</section>
<section id="visual-diagnostics" class="level2">
<h2 class="anchored" data-anchor-id="visual-diagnostics">Visual diagnostics</h2>
<ul>
<li><a href="https://mc-stan.org/bayesplot/articles/visual-mcmc-diagnostics.html">Visual MCMC diagnostics</a></li>
</ul>
</section>
<section id="misc" class="level2">
<h2 class="anchored" data-anchor-id="misc">Misc</h2>
<ul>
<li><p><a href="https://statmodeling.stat.columbia.edu/2020/10/21/model-takes-many-hours-to-fit-and-chains-dont-converge-what-to-do-my-advice-on-first-steps/">Gelman’s advice for slow models</a></p></li>
<li><p><a href="https://cran.r-project.org/web/packages/brms/">brms vignettes</a></p></li>
<li><p><a href="http://mc-stan.org/cmdstanr/articles/cmdstanr.html">Use CmdStan to save memory</a></p></li>
<li><p><a href="https://mc-stan.org/users/documentation/case-studies">Stan case studies</a></p></li>
</ul>


</section>
</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>I will spare the details of my opinions, which are almost entirely negative.↩︎</p></li>
<li id="fn2"><p>For this model, they are uniform/improper priors for the regression coefficients and half-t for the residual variance. You can always use <span class="func" style="">prior_summary</span> on a <span class="pack" style="">brms</span> model to see this.↩︎</p></li>
<li id="fn3"><p>With more posterior samples comes slower visualizations and possibly other computations.↩︎</p></li>
<li id="fn4"><p>Another issue is that you could change how the chains are split and it could potentially dramatically change the how the pattern of divergent transitions looks.↩︎</p></li>
<li id="fn5"><p>This seems counter to the common suggestion on forums and GitHub issues that even 1 divergent transition renders results suspect. I’ve never seen results meaningfully change for something with just a couple divergent transitions to one that has none, and often when there are that few, even rerunning the model will result in no divergences.↩︎</p></li>
<li id="fn6"><p>In my experience, there isn’t a need to guess some value between .80 and .99 as the time differences are typically not great, say between .9, .95, and .99, unless your model already takes a very long time. Also, if it doesn’t work at .99, it won’t at .9999 either.↩︎</p></li>
<li id="fn7"><p>I’m definitely not speaking from experience here or anything! Nomral distributions do exist, I’m sure of it! 😬↩︎</p></li>
<li id="fn8"><p>It is often suggested in the Stan world to reparameterize models. However, this advice doesn’t really apply in the case of using <span class="pack" style="">rstanarm</span> or <span class="pack" style="">brms</span> (i.e.&nbsp;where you aren’t writing Stan code directly), and it assumes a level of statistical expertise many would not have, or even if they do, the route to respecifying the model may not be obvious.↩︎</p></li>
<li id="fn9"><p>Betancourt, whose work I admire greatly, typically makes my head spin.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2021,
  author = {Clark, Michael},
  title = {Practical {Bayes} {Part} {I}},
  date = {2021-02-28},
  url = {https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2021" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2021. <span>“Practical Bayes Part I.”</span> February
28. <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/">https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/</a>.
</div></div></section></div> ]]></description>
  <category>bayesian</category>
  <guid>https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/</guid>
  <pubDate>Sun, 28 Feb 2021 05:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/r_and_stan.png" medium="image" type="image/png" height="53" width="144"/>
</item>
<item>
  <title>Practical Bayes Part II</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>NB: This post was revisited when updating the website early 2025, and some changes were required. Attempts to keep things consistent were made, but if you feel you’ve found an issue, please post it at <a href="http://github.com/m-clark/m-clark.github.io/issues">GitHub</a>.</p>
</blockquote>
<section id="overview" class="level1 page-columns page-full">
<h1>Overview</h1>
<p>In <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/">Part I</a>, we talked about the basics one can do to run a Bayesian model with a high-level Stan package like <span class="pack" style="">brms</span>, and what to do if there is a problem. But it might be nice if we could take steps to avoid the problems in the first place, and what’s more, our model might still be inadequate without any warnings, and we’ll still need to inspect diagnostics regardless. So let’s engage in some better practices you can use every time to help things run more smoothly, and get more from your models after you’ve run them.</p>

<div class="no-row-height column-margin column-container"><div class="">
<p>This is part two of two posts on doing practical modeling with R and Stan in an applied fashion. Due to unforeseen circumstances (and plenty of procrastination), the bulk of the content of these posts was created many months before actual posting. It’s hoped that most of this will still be applicable and have the conceptual continuity as originally intended, but apologies in advance if some parts seem a little disjointed, off topic, etc.</p>
</div></div><section id="outline-for-better-bayesian-analysis" class="level2">
<h2 class="anchored" data-anchor-id="outline-for-better-bayesian-analysis">Outline for Better Bayesian Analysis</h2>
<p>We’ll cover the following steps in more detail, but here is a general outline.</p>
<ul>
<li>First generate ‘fake data’ to assess viability of our priors</li>
<li>With adequate priors, start with a simple, but plausible model</li>
<li>For simple models you likely do not need many iterations, and for debugging/troubleshooting, starting with few iterations can possibly give you a sense of whether there will be problems<sup>1</sup>. If you are doing standard GLM or simpler versions of common extensions, even the defaults are likely overkill. For example, a basic linear regression should converge almost immediately.</li>
<li>If you have problems at this point, see <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/">Part I</a></li>
</ul>
<!-- -->
<ul>
<li>Explore and Visualize the Model Results
<ul>
<li>Visualize covariate relationships</li>
<li>Assess model effectiveness
<ul>
<li>Use posterior predictive checks</li>
<li>Other avenues</li>
</ul></li>
</ul></li>
<li>Prediction and Model Comparisons
<ul>
<li>Get basic predictions for observations of interest</li>
<li>Explore a more viable model
<ul>
<li>Add interactions</li>
<li>Add nonlinear relations</li>
<li>Account for other structure (e.g.&nbsp;random effects)</li>
</ul></li>
<li>Compare and/or average models</li>
<li>Use cross-validation to better assess performance</li>
</ul></li>
</ul>
<p>We’ll now demonstrate these steps.</p>
</section>
</section>
<section id="example-data" class="level1">
<h1>Example data</h1>
<p><a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/">As in Part I</a>, I’m going to create some data for us to run some basic models with, the same as Part I. As a reminder, the true underlying model has categorical and continuous covariates, interactions, nonlinear relationships, random effects (observations are clustered in groups), and some variables are collinear.</p>
<p>For our purposes so we’ll create a data frame with the total sample size of 1000.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># create the primary data frame</span></span>
<span id="cb1-2"></span>
<span id="cb1-3">main_df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> </span>
<span id="cb1-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">create_data</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;">1000</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_tibble</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(group, b1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>x3, y) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb1-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b1 =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(b1),   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># will help with visuals</span></span>
<span id="cb1-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b2 =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(b2)</span>
<span id="cb1-10">  )</span></code></pre></div></div>
</div>
</section>
<section id="simulate-from-priors" class="level1">
<h1>Simulate from priors</h1>
<p>A good initial step in Bayesian analysis is to think about and produce some viable priors for the parameters. But the obvious question is, what priors should we choose? Thankfully, for standard models there is not much guesswork involved. Bayesian analysis has been around a long time, so the bulk of the work in determining suitable priors for standard models has been done for you. Even default settings should not affect things much, especially for <span class="pack" style="">rstanarm</span>, which has some basic defaults that are informed by the data. However, due to the flexibility of the <span class="pack" style="">brms</span> modeling functions, some priors are unspecified and left ‘flat’ (i.e.&nbsp;uniform), which is something we definitely don’t want. And even defaults could still cause problems for more complex situations. So how might we choose better ones?</p>
<p>The basic idea here is to generate parameters (e.g.&nbsp;regression coefficients) based on their corresponding prior distributions, predict data based on those prior draws, and then compare the predictions to our observed target variable that we are attempting to understand.</p>
<p>Thankfully, the <span class="pack" style="">brms</span> package makes this very easy to do. We will check the following types of priors, that range from default settings to increasing specification for all parameters of interest.</p>
<div class="cell">
<div class="cell-output-display">
<div class="datatables html-widget html-fill-item" id="htmlwidget-b00327701f375583695d" style="width:100%;height:auto;"></div>
<script type="application/json" data-for="htmlwidget-b00327701f375583695d">{"x":{"filter":"none","vertical":false,"data":[["Note:","Regression coefficients:","Intercept:","Variances:"],["similar to brms","uniform","default","default"],["similar to rstanarm","normal, diffuse","default","default"],["similar to rstanarm","normal","default","default"],["If data is standardized, this would be very reasonable","Normal(0, 1)","default","default"],["restricts range of intercept to more plausible values","Normal(0, 1)","mean of `y` (~3)","default"],["restricts range of sigma to more plausible values","Normal(0, 1)","based on mean of `y` (~3)","based on sd of `y` (~1)"]],"container":"<table class=\"display\">\n  <thead>\n    <tr>\n      <th> <\/th>\n      <th>Prior set 0<\/th>\n      <th>Prior set 1<\/th>\n      <th>Prior set 2<\/th>\n      <th>Prior set 3<\/th>\n      <th>Prior set 4<\/th>\n      <th>Prior set 5<\/th>\n    <\/tr>\n  <\/thead>\n<\/table>","options":{"dom":"t","autoWidth":true,"columnDefs":[{"targets":0,"orderable":false},{"orderable":false,"targets":0},{"name":" ","targets":0},{"name":"Prior set 0","targets":1},{"name":"Prior set 1","targets":2},{"name":"Prior set 2","targets":3},{"name":"Prior set 3","targets":4},{"name":"Prior set 4","targets":5},{"name":"Prior set 5","targets":6}],"scrollX":true,"order":[],"orderClasses":false,"rowCallback":"function(row, data, displayNum, displayIndex, dataIndex) {\nvar value=data[-1]; $(this.api().cell(row, -1).node()).css({'white-space':'nowrap'});\nvar value=data[0]; $(this.api().cell(row, 0).node()).css({'white-space':'nowrap'});\nvar value=data[1]; $(this.api().cell(row, 1).node()).css({'white-space':'nowrap'});\nvar value=data[2]; $(this.api().cell(row, 2).node()).css({'white-space':'nowrap'});\nvar value=data[3]; $(this.api().cell(row, 3).node()).css({'white-space':'nowrap'});\nvar value=data[4]; $(this.api().cell(row, 4).node()).css({'white-space':'nowrap'});\nvar value=data[5]; $(this.api().cell(row, 5).node()).css({'white-space':'nowrap'});\nvar value=data[0]; $(this.api().cell(row, 0).node()).css({'font-weight':'bold','text-align':'left'});\n}"},"selection":{"mode":"multiple","selected":null,"target":"row","selectable":null}},"evals":["options.rowCallback"],"jsHooks":[]}</script>
</div>
</div>
<p>We can use <span class="func" style="">pp_check</span> to examine the prior-generated data versus the observed target <code>y</code>, but I wait to show them all together at the end. Note the argument <code>sample_prior</code>, which we set to <code>'only'</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(brms)</span>
<span id="cb2-2"></span>
<span id="cb2-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># essentially the same as the defaults</span></span>
<span id="cb2-4">pr_uniform <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uniform</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;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lb =</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;">100</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ub =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b'</span>)</span>
<span id="cb2-5"></span>
<span id="cb2-6">model_default_prior <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(</span>
<span id="cb2-7">  y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> b1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x3, </span>
<span id="cb2-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> main_df,</span>
<span id="cb2-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>,</span>
<span id="cb2-10">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sample_prior =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'only'</span>,</span>
<span id="cb2-11">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prior =</span> pr_uniform</span>
<span id="cb2-12">)</span>
<span id="cb2-13"></span>
<span id="cb2-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pp_check(model_default_prior, ndraws = 50)</span></span>
<span id="cb2-15"></span>
<span id="cb2-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># diffuse normal for reg coefficients 'b'</span></span>
<span id="cb2-17">pr_norm_b_0_10 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">normal</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b'</span>)</span>
<span id="cb2-18"></span>
<span id="cb2-19">model_0_norm_b_0_10 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(</span>
<span id="cb2-20">  y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> b1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x3, </span>
<span id="cb2-21">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> main_df,</span>
<span id="cb2-22">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>,</span>
<span id="cb2-23">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sample_prior =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'only'</span>,</span>
<span id="cb2-24">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prior =</span> pr_norm_b_0_10</span>
<span id="cb2-25">)</span>
<span id="cb2-26"></span>
<span id="cb2-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pp_check(model_0_norm_b_0_10, ndraws = 50)</span></span>
<span id="cb2-28"></span>
<span id="cb2-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># rstanarm-like prior</span></span>
<span id="cb2-30">pr_auto <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> sjstats<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">auto_prior</span>(</span>
<span id="cb2-31">  y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> b1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x3,</span>
<span id="cb2-32">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> main_df,</span>
<span id="cb2-33">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">gaussian =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb2-34">)</span>
<span id="cb2-35"></span>
<span id="cb2-36">model_auto_prior <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(</span>
<span id="cb2-37">  y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> b1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x3, </span>
<span id="cb2-38">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> main_df,</span>
<span id="cb2-39">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>,</span>
<span id="cb2-40">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sample_prior =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'only'</span>,</span>
<span id="cb2-41">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prior =</span> pr_auto</span>
<span id="cb2-42">)</span>
<span id="cb2-43"></span>
<span id="cb2-44"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pp_check(model_auto_prior, ndraws = 50)</span></span>
<span id="cb2-45"></span>
<span id="cb2-46"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Since we have standardized data, Normal(0, 1) is reasonable for reg coefs</span></span>
<span id="cb2-47">pr_norm_b_0_1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">normal</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b'</span>)</span>
<span id="cb2-48"></span>
<span id="cb2-49">model_0_norm_b_0_1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(</span>
<span id="cb2-50">  y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> b1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x3, </span>
<span id="cb2-51">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> main_df,</span>
<span id="cb2-52">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>,</span>
<span id="cb2-53">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sample_prior =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'only'</span>,</span>
<span id="cb2-54">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prior =</span> pr_norm_b_0_1</span>
<span id="cb2-55">)</span>
<span id="cb2-56"></span>
<span id="cb2-57"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pp_check(model_0_norm_b_0_1, ndraws = 50)</span></span>
<span id="cb2-58"></span>
<span id="cb2-59"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Now we add one for the intercept based on the mean of y</span></span>
<span id="cb2-60">pr_norm_b_norm_int <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb2-61">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">normal</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">class =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b'</span>),</span>
<span id="cb2-62">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">normal</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;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">class =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Intercept'</span>)</span>
<span id="cb2-63">)</span>
<span id="cb2-64"></span>
<span id="cb2-65">model_0_norm_b_0_1_norm_Int <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(</span>
<span id="cb2-66">  y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> b1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x3, </span>
<span id="cb2-67">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> main_df,</span>
<span id="cb2-68">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>,</span>
<span id="cb2-69">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sample_prior =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'only'</span>,</span>
<span id="cb2-70">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prior =</span> pr_norm_b_norm_int</span>
<span id="cb2-71">)</span>
<span id="cb2-72"></span>
<span id="cb2-73"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pp_check(model_0_norm_b_0_1_norm_Int, ndraws = 50)</span></span>
<span id="cb2-74"></span>
<span id="cb2-75"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Now add a prior for sigma based on the sd of y</span></span>
<span id="cb2-76">pr_norm_b_norm_int_t_sigma <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb2-77">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">normal</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">class =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b'</span>),</span>
<span id="cb2-78">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">normal</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;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">class =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Intercept'</span>),</span>
<span id="cb2-79">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">student_t</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;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">class =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'sigma'</span>) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># first value is deg of freedom</span></span>
<span id="cb2-80">)</span>
<span id="cb2-81"></span>
<span id="cb2-82">model_0_norm_b_0_1_norm_Int_sigma <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(</span>
<span id="cb2-83">  y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> b1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x3, </span>
<span id="cb2-84">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> main_df,</span>
<span id="cb2-85">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>,</span>
<span id="cb2-86">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sample_prior =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'only'</span>,</span>
<span id="cb2-87">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prior =</span> pr_norm_b_norm_int_t_sigma</span>
<span id="cb2-88">)</span>
<span id="cb2-89"></span>
<span id="cb2-90"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pp_check(model_0_norm_b_0_1_norm_Int_sigma, ndraws = 50)</span></span></code></pre></div></div>
</div>
<p>The following plot shows the model predictions based on priors only. We restrict the range of values for display purposes, so note that some of these settings would actually generate more extreme results. For example, the default prior setting could generate values into the <img src="https://latex.codecogs.com/png.latex?%5Cpm"> 500 and beyond. I also mark the boundaries of the observed target variable with the vertical lines.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/proposed-priors-plot-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>We can see in the visualization that the left side using defaults or notably diffuse priors results in nonsensical ranges for our target variable. When we actually run the model, this means we’d explore possible (the space of) parameter values that aren’t going to be useful for prediction. We would likely still should come to the same conclusions, it’s just that we might need many more iterations, and as we know from <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/">Part I</a>, not having enough iterations can lead to many warnings.</p>
<p>So given that our target variable is between -2 and 8, it seems that just adding some basic, data-informed information to our priors resulted in more plausible results. This will generally help our models be more efficient and better behaved. Note that if all else fails, you can use a convenience function like <span class="func" style="">auto_prior</span> demonstrated above.</p>
</section>
<section id="summarizing-a-model" class="level1">
<h1>Summarizing a Model</h1>
<p>Now let’s run a baseline model, one that’s simple but plausible. Given that there will eventually be other complexities added to the model, I’ll go ahead and add some iterations, and increase <code>adapt_delta</code> and <code>max_treedepth</code> now to make the code reusable.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(brms)</span>
<span id="cb3-2"></span>
<span id="cb3-3">pr <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb3-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">normal</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">class =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b'</span>),</span>
<span id="cb3-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">student_t</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;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">class =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'sigma'</span>),</span>
<span id="cb3-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">student_t</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;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">class =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'sd'</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># prior for random intercept std dev</span></span>
<span id="cb3-7">)</span>
<span id="cb3-8"></span>
<span id="cb3-9">model_baseline <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">brm</span>(</span>
<span id="cb3-10">  y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> b1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x1 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> x3 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> group), </span>
<span id="cb3-11">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data    =</span> main_df,</span>
<span id="cb3-12">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">warmup  =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5000</span>,</span>
<span id="cb3-13">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">iter    =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6000</span>,</span>
<span id="cb3-14">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">thin    =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,</span>
<span id="cb3-15">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prior   =</span> pr, </span>
<span id="cb3-16">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cores   =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,</span>
<span id="cb3-17">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed    =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1234</span>, </span>
<span id="cb3-18">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">control =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(</span>
<span id="cb3-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">adapt_delta   =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">95</span>,</span>
<span id="cb3-20">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">max_treedepth =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span></span>
<span id="cb3-21">  ),</span>
<span id="cb3-22">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">save_pars =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">save_pars</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">all =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># potentially allows for more  more post-processing functionality</span></span>
<span id="cb3-23">)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summary</span>(model_baseline)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: y ~ b1 + b2 + x1 + x2 + x3 + (1 | group) 
   Data: main_df (Number of observations: 1000) 
  Draws: 4 chains, each with iter = 6000; warmup = 5000; thin = 4;
         total post-warmup draws = 1000

Multilevel Hyperparameters:
~group (Number of levels: 100) 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)     0.87      0.07     0.74     1.02 1.00      710      782

Regression Coefficients:
          Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept     2.69      0.21     2.28     3.10 1.00      691      811
b11           0.80      0.07     0.67     0.93 1.00      918      955
b21          -0.14      0.18    -0.51     0.22 1.00      798      878
x1            0.03      0.03    -0.03     0.10 1.01      792      869
x2           -0.03      0.04    -0.10     0.05 1.00      994      990
x3            0.27      0.04     0.19     0.34 1.00     1013      967

Further Distributional Parameters:
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma     1.03      0.02     0.99     1.08 1.00      969      986

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).</code></pre>
</div>
</div>
<p>For reporting purposes, generally all you need are the <code>Estimate</code> and lower and upper bounds. You might also mention that the basic diagnostics suggested no problems, but you’ll still want to explore this a bit for yourself (as in <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/">Part I</a>). If you want a visual approach to these basic results, you can use something like the following types of plots.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcmc_plot</span>(model_baseline, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'areas'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/model-baseline-summary-plots-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcmc_plot</span>(model_baseline, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'intervals'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/model-baseline-summary-plots-2.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>The <span class="pack" style="">tidybayes</span> package offers some nice options as well. It takes a bit of getting used to, but can be very handy. As an example, the following gives a visual sense of the probability of regression coefficient values beyond a chosen point of interest, in this case, arbitrarily chosen as <code>abs(.25)</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tidybayes)</span>
<span id="cb8-2"></span>
<span id="cb8-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># get_variables(model_baseline) %&gt;% as_tibble() # to see variable names as required for plotting.</span></span>
<span id="cb8-4"></span>
<span id="cb8-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># grab fixed effects - intercept</span></span>
<span id="cb8-6">tidy_plot_data_fe <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> model_baseline <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb8-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">spread_draws</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">^b_(b|x).*</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">regex =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb8-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(b_b11<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>b_x3, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'coefficient'</span>)</span>
<span id="cb8-9"></span>
<span id="cb8-10">tidy_plot_data_fe <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb8-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">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;">y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rev</span>(coefficient), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> value)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb8-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_vline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xintercept =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>.<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</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;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'gray92'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb8-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">stat_dotsinterval</span>(</span>
<span id="cb8-14">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">stat</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abs</span>(x) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>)),</span>
<span id="cb8-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">quantiles =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>,</span>
<span id="cb8-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">point_color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#b2001d'</span>,</span>
<span id="cb8-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">interval_color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#b2001d'</span>,</span>
<span id="cb8-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">interval_alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span></span>
<span id="cb8-19">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb8-20">  scico<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale_fill_scico_d</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">begin =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">end =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb8-21">  <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;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb8-22">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">guides</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'none'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb8-23">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_clean</span>()</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/tidybayesdemo-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<section id="check-priors" class="level2">
<h2 class="anchored" data-anchor-id="check-priors">Check Priors</h2>
<p>Though we did some work to select our prior distributions beforehand, we might still be concerned about how influential our priors were. So how can we check whether our priors were informative? The following uses the <span class="pack" style="">bayestestR</span> package to do a simple check of whether the posterior standard deviation is greater than 10% of the prior standard deviation<sup>2</sup>. Having an informative prior isn’t really a problem in my opinion, unless it’s more informative than you wanted. For example, shrinkage of a coefficient towards zero will generally help avoid overfitting.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prior_summary</span>(model_baseline)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>                  prior     class      coef group resp dpar nlpar lb ub
           normal(0, 1)         b                                      
           normal(0, 1)         b       b11                            
           normal(0, 1)         b       b21                            
           normal(0, 1)         b        x1                            
           normal(0, 1)         b        x2                            
           normal(0, 1)         b        x3                            
 student_t(3, 2.9, 2.5) Intercept                                      
    student_t(10, 1, 1)        sd                                  0   
    student_t(10, 1, 1)        sd           group                  0   
    student_t(10, 1, 1)        sd Intercept group                  0   
    student_t(10, 1, 1)     sigma                                  0   
       source
         user
 (vectorized)
 (vectorized)
 (vectorized)
 (vectorized)
 (vectorized)
      default
         user
 (vectorized)
 (vectorized)
         user</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1">bayestestR<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">check_prior</span>(model_baseline)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>    Parameter Prior_Quality
1 b_Intercept uninformative
2       b_b11 uninformative
3       b_b21   informative
4        b_x1 uninformative
5        b_x2 uninformative
6        b_x3 uninformative</code></pre>
</div>
</div>
<p>These results suggest that we might be more informative, but for the intercept, which we largely aren’t too worried about, and for the factor that is highly unbalanced (<code>b2</code>), but which has no obvious solution. I personally would be fine with this result, especially since we took initial care in choosing these priors. If you really wanted to, you could change the priors that were informative.</p>
</section>
<section id="explore-and-visualize-results" class="level2">
<h2 class="anchored" data-anchor-id="explore-and-visualize-results">Explore and Visualize Results</h2>
<p>Now that we are feeling pretty good about the results we have, we can explore the model further. We can plot covariate effects easily with <span class="pack" style="">brms</span>. The <span class="func" style="">conditional_effects</span> function is what we want here. I show results for one effect below. Without interactions or other things going, on they aren’t very interesting, but it’s a useful tool nonetheless. We’ll come back to this later.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">conditional_effects</span>(model_baseline, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b2'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/model-start-explore-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>We can also use the <span class="func" style="">hypothesis</span> function to test for specific types of effects. By default they provide a one-sided probability and uncertainty interval. For starters, we can just duplicate what we saw in the previous summary for the <code>b2</code> effect. The only benefit is to easily obtain the one-sided p-value (e.g.&nbsp;that <code>b2</code> is less than zero) and the corresponding <em>evidence ratio</em>, which is just <code>p/(1-p)</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">hypothesis</span>(model_baseline, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b21 &lt; 0'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Hypothesis Tests for class b:
  Hypothesis Estimate Est.Error CI.Lower CI.Upper Evid.Ratio Post.Prob Star
1  (b21) &lt; 0    -0.14      0.18    -0.45     0.16       3.46      0.78     
---
'CI': 90%-CI for one-sided and 95%-CI for two-sided hypotheses.
'*': For one-sided hypotheses, the posterior probability exceeds 95%;
for two-sided hypotheses, the value tested against lies outside the 95%-CI.
Posterior probabilities of point hypotheses assume equal prior probabilities.</code></pre>
</div>
</div>
<p>But we can really try anything, which is the power of this function. As an example, the following tests whether the combined effect of our categorical covariates is greater than twice the value of the <code>x1</code> effect<sup>3</sup>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">hypothesis</span>(model_baseline, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'abs(b11) + abs(b21) &gt; 2*x1'</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Hypothesis Tests for class b:
                Hypothesis Estimate Est.Error CI.Lower CI.Upper Evid.Ratio
1 (abs(b11)+abs(b21... &gt; 0     0.92      0.17     0.67     1.22        Inf
  Post.Prob Star
1         1    *
---
'CI': 90%-CI for one-sided and 95%-CI for two-sided hypotheses.
'*': For one-sided hypotheses, the posterior probability exceeds 95%;
for two-sided hypotheses, the value tested against lies outside the 95%-CI.
Posterior probabilities of point hypotheses assume equal prior probabilities.</code></pre>
</div>
</div>
<p>One should get used to whatever tools are available for further understanding covariate effects or other parameters. This will likely lead to some of the more interesting discussion of your findings, or at least, notably more interesting than a standard regression table.</p>
</section>
<section id="model-effectiveness" class="level2">
<h2 class="anchored" data-anchor-id="model-effectiveness">Model Effectiveness</h2>
<p>It is one thing to look at specific effects. but a natural question to ask is how useful our model actually is as a whole. This then suggests we need to know how to define such utility. Such an assessment definitely cannot be made with something like ‘statistical significance’. Science of any kind is nothing without prediction, so we we can start there.</p>
<section id="posterior-predictive-checks" class="level3">
<h3 class="anchored" data-anchor-id="posterior-predictive-checks">Posterior predictive checks</h3>
<p>Posterior predictive checks are a key component of Bayesian analysis. The prior checks we did before are just a special case of this. Here we instead use the posterior distributions of parameters to generate the data, and compare this model-implied/synthetic data to what we actually observe. Doing so can give insight to where the model succeeds and fails.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">pp_check</span>(model_baseline, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ndraws =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/model-baseline-ppcheck-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><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;">pp_check</span>(model_baseline, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ndraws =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'error_scatter_avg'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/model-baseline-ppcheck-2.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>In this case, we see good alignment between model and data, and no obvious pattern to the types of errors we are getting. It is often the case that we see that the model does not capture the most extreme values well, but that’s not terribly surprising. With simulated data, our situation is more pristine to begin with, but you generally can’t expect such a clean result in practice.</p>
<p>As an example, consider predictions with and without random effects. Including the cluster-specific effects for prediction appear to do better with the capturing the tails.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/model-baseline-ppcheck-re-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>We can use the same approach to look at specific statistical measures of interest. For example, the following suggests our model is pretty good at capturing the minimum value, but typically underestimates the maximum value, which we noted earlier, is not especially unexpected in practice, particularly with smaller sample data.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">pp_check</span>(model_baseline, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ndraws =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'stat'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stat=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'median'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/model-baseline-ppcheck-med-max-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><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;">pp_check</span>(model_baseline, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ndraws =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'stat'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stat =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'max'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/model-baseline-ppcheck-med-max-2.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>We can define any function to use for our posterior predictive check. The following shows how to examine the 10th and 90th quantiles. Minimum and maximum values are unlikely to be captured very well due to their inherent variability, so looking at less extreme quantiles (e.g.&nbsp;10<sup>th</sup> or 90<sup>th</sup> percentile) might be a better way to assess whether the model captures the tails of a distribution.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">q10 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(y) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">quantile</span>(y, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)</span>
<span id="cb22-2">q90 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(y) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">quantile</span>(y, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span>)</span>
<span id="cb22-3"></span>
<span id="cb22-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pp_check</span>(model_baseline, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ndraws =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'stat'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stat =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'q90'</span>)</span>
<span id="cb22-5"></span>
<span id="cb22-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pp_check</span>(model_baseline, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ndraws =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'stat_2d'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stat =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'q10'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'q90'</span>))</span></code></pre></div></div>
</div>
</section>
<section id="bayes-r-squared" class="level3">
<h3 class="anchored" data-anchor-id="bayes-r-squared">Bayes R-squared</h3>
<p>In this modeling scenario, we can examine the amount of variance accounted for in the target variable by the covariates. I don’t really recommend this beyond linear models that assume a normal distribution for the target, but people like to report it. Conceptually, it is simply a (squared) correlation of fitted values with the observed target values, so can be seen as descriptive statistic. Since we are Bayesians, we also get a ready-made interval for it, as it is based on the posterior predictive distribution. But to stress the complexity in trying to assess this, in this mixed model we can obtain the result with the random effect included (conditional) or without (unconditional). Both are reasonable ways to express the statistic, but the one including the group effect naturally will be superior, assuming the group-level variance is notable in the first place.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bayes_R2</span>(model_baseline)                   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># random effects included</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>    Estimate  Est.Error      Q2.5     Q97.5
R2 0.4812032 0.01781973 0.4445528 0.5148587</code></pre>
</div>
<div class="code-copy-outer-scaffold"><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;">bayes_R2</span>(model_baseline, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">re_formula =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># random effects not included</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>    Estimate  Est.Error       Q2.5    Q97.5
R2 0.1161024 0.01498238 0.08729654 0.144502</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb27-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># performance::r2_bayes(model_baseline)    # performance package provides both</span></span></code></pre></div></div>
</div>
<p>To show the limitation of R<sup>2</sup>, I rerun the model using a restrictive prior on the intercept. Intercepts for the resulting models are different but the other fixed effects are basically the same. The R<sup>2</sup> suggests equal performance of both models.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">model</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">R2</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Est.Error</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Q2.5</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Q97.5</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">baseline</td>
<td style="text-align: right;">0.116</td>
<td style="text-align: right;">0.015</td>
<td style="text-align: right;">0.087</td>
<td style="text-align: right;">0.145</td>
</tr>
<tr class="even">
<td style="text-align: left;">modified</td>
<td style="text-align: right;">0.116</td>
<td style="text-align: right;">0.014</td>
<td style="text-align: right;">0.089</td>
<td style="text-align: right;">0.143</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>However, a posterior predictive check shows clearly the failure of the modified model to capture the data.</p>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/r2-not-pp-check-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>A variant of R<sup>2</sup>, the ‘LOO’ R<sup>2</sup>, is also available via the <span class="func" style="">loo_R2</span> function. LOO stands for <em>leave-one-out</em>, as in leave-one-out cross-validation. It’s based on the residuals from the leave one out predictions. You can think of it as a better way to obtain an adjusted R<sup>2</sup> in this setting. The results suggests that the LOO R<sup>2</sup> actually picks up the difference in models, and would be lower for the modified model, even if we included the random effects.</p>
<p>For more on Bayesian R<sup>2</sup>, see the resources section</p>
</section>
</section>
</section>
<section id="prediction-model-comparison" class="level1">
<h1>Prediction &amp; Model Comparison</h1>
<p>In general, a model is judged most by whether it has practical value. Even if we think a model is effective, there still might be another model that can do better. So it can be a good idea to have a couple of models to compare with one another. And one of the best ways to compare them is via prediction, especially by predicting on data the model wasn’t trained on to begin with.</p>
<p>For our demonstration, we will add two new models. The first adds interactions, the second adds a nonlinear relationship for one of the variables to that model, and is the closest to the underlying data generating mechanism.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">model_interact <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">update</span>(</span>
<span id="cb28-2">  model_baseline,</span>
<span id="cb28-3">  . <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> b1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>b2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>x1,</span>
<span id="cb28-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cores =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,</span>
<span id="cb28-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed  =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1234</span></span>
<span id="cb28-6">)</span>
<span id="cb28-7"></span>
<span id="cb28-8">model_interact_nonlin <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">update</span>(</span>
<span id="cb28-9">  model_interact,</span>
<span id="cb28-10">  . <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="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(x3),</span>
<span id="cb28-11">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cores =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>,</span>
<span id="cb28-12">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed  =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1234</span></span>
<span id="cb28-13">)</span></code></pre></div></div>
</div>
<section id="basic-prediction" class="level2">
<h2 class="anchored" data-anchor-id="basic-prediction">Basic prediction</h2>
<p>With models in hand, let’s look at our basic predictive capabilities. We can get fitted values which include ‘confidence’ intervals, or predictions, which include ‘prediction’ intervals that include the uncertainty for a new observation. We can specify these as follows. First we create a small data set to make some predictions on. It will include both values for of the binary covariates, and the means of the numeric covariates (0).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb29" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb29-1">prediction_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crossing</span>(</span>
<span id="cb29-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b1 =</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;">1</span>,</span>
<span id="cb29-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b2 =</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;">1</span>,</span>
<span id="cb29-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x1 =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb29-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x2 =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb29-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x3 =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb29-7">)</span>
<span id="cb29-8"></span>
<span id="cb29-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fitted values</span></span>
<span id="cb29-10"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fitted</span>(model_baseline))  </span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>     Estimate Est.Error     Q2.5    Q97.5
[1,] 3.517482 0.3382849 2.855822 4.167321
[2,] 3.796906 0.3377263 3.118250 4.453510
[3,] 3.866082 0.3346731 3.179920 4.511195
[4,] 4.357828 0.3507970 3.688756 5.026747
[5,] 3.185495 0.3381892 2.527887 3.825222
[6,] 3.910027 0.3347265 3.244999 4.558492</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb31" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb31-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># new predictions</span></span>
<span id="cb31-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb31-3">  prediction_data,</span>
<span id="cb31-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(model_baseline, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> prediction_data, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">re_formula =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>)</span>
<span id="cb31-5">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>  b1 b2 x1 x2 x3 Estimate Est.Error      Q2.5    Q97.5
1  0  0  0  0  0 2.696397  1.069881 0.5093926 4.709590
2  0  1  0  0  0 2.557696  1.013811 0.5566073 4.603278
3  1  0  0  0  0 3.450119  1.082413 1.3938133 5.471762
4  1  1  0  0  0 3.324694  1.008474 1.3336782 5.300122</code></pre>
</div>
</div>
<p>In general, we’d always like to visualize the predictions. We can do so as we did before with the <span class="func" style="">conditional_effects</span> function, which would also allow us to set specific covariate values. For the third plot of the nonlinear effect below, I modify the basic conditional effects plot that <span class="pack" style="">brms</span> provides for a slightly cleaner visualization.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb33" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb33-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">conditional_effects</span>(model_baseline, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">effects =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x2'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">conditions =</span> prediction_data[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,])</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/conditional-effects-model-comparison-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><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;">conditional_effects</span>(model_interact, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">effects =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x1:b2'</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/conditional-effects-model-comparison-2.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb35" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb35-1">init <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">conditional_effects</span>(model_interact_nonlin, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">effects =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x3'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">spaghetti =</span> T)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/conditional-effects-model-comparison-show-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Expanding your story through prediction is essential to helping your audience understand the model on a practical level. You would do well to spend time looking at specific data scenarios, especially in the case of nonlinear models (e.g.&nbsp;GLM) and models with interactions.</p>
</section>
<section id="model-comparison" class="level2">
<h2 class="anchored" data-anchor-id="model-comparison">Model Comparison</h2>
<p>In typical situations it is good to have competing models, and having additional models allows us to see if improvements can be made in one way or another, both to our models, and potentially to our way of thinking about them. In a general sense, we will go about things very similarly in the Bayesian context that we would elsewhere. However, we’ll also more easily apply other approaches that are not so commonly used (even if they can be).</p>
<section id="choosing-a-model" class="level3">
<h3 class="anchored" data-anchor-id="choosing-a-model">Choosing a model</h3>
<p>In traditional contexts, we can use a specific approach to pit competing models against one another, selecting the ‘best’ model based on a particular metric, for example, AIC, cross-validation error, etc. With ‘error metrics’, the model with the lowest value is the winner. In this case, nothing is new in the Bayesian world. Here, we can use estimates like <em>WAIC</em> and <em>LOOIC</em> for model comparison, much like you would <em>AIC</em> to compare models in traditional frameworks. The values themselves don’t tell us much, but in comparing models, lower means less predictive error for these ‘information criteria’ metrics, which is what we want<sup>4</sup>, and since we’re Bayesian, we will even have estimates of uncertainty for these values as well. We also have cross-validation approaches (which IC metrics approximate), which we will demonstrate later.</p>
<p>With our new models added to the mix, we can now make some comparisons using <span class="func" style="">loo_compare</span>. First, we’ll add LOOIC estimates to our models, which are not estimated by default.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">model_baseline <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add_criterion</span>(model_baseline,  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'loo'</span>)</span>
<span id="cb36-2">model_interact <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add_criterion</span>(model_interact, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'loo'</span>)</span>
<span id="cb36-3">model_interact_nonlin <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add_criterion</span>(model_interact_nonlin, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'loo'</span>)</span></code></pre></div></div>
</div>
<p>To start, we’ll show the LOOIC result for the baseline model. We have the total expected log probability (<code>elpd_loo</code>) for the leave-one-out observations. We also get stuff like <code>p_loo</code>, which is the effective number of parameters. For those familiar with penalized maximum likelihood, these are familiar analogues. However we also get a summary regarding <code>Pareto k values</code>, which we’ll talk about soon.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb37" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb37-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># example</span></span>
<span id="cb37-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loo</span>(model_baseline)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
Computed from 1000 by 1000 log-likelihood matrix.

         Estimate   SE
elpd_loo  -1500.6 21.9
p_loo        88.0  3.8
looic      3001.2 43.9
------
MCSE of elpd_loo is 0.4.
MCSE and ESS estimates assume MCMC draws (r_eff in [0.6, 1.3]).

All Pareto k estimates are good (k &lt; 0.67).
See help('pareto-k-diagnostic') for details.</code></pre>
</div>
</div>
<p>Let’s now compare the baseline model to the others models using <span class="func" style="">loo_compare</span>. It shows the ‘best’ (lowest-valued) model first, followed by the others. We get the difference of each elpd vs.&nbsp;the lowest, also get a standard error for this difference, which you could use to help assess how different the values are statistically. Just by this standard, the model that is based on the underlying data generating mechanism is the clear winner, as we would expect.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb39" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb39-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loo_compare</span>(</span>
<span id="cb39-2">  model_baseline, </span>
<span id="cb39-3">  model_interact,</span>
<span id="cb39-4">  model_interact_nonlin</span>
<span id="cb39-5">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>                      elpd_diff se_diff
model_interact_nonlin   0.0       0.0  
model_interact        -44.5       9.4  
model_baseline        -46.3       9.7  </code></pre>
</div>
</div>
<p>Now let’s compare several metrics available to us. In this particular setting, all are generally in agreement in the rank order of the models, though there appears to be no meaningful difference between the baseline and interaction models.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">model</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">R2</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">loo_R2</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">WAIC</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">LOOIC</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">ELPD</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">weight</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">baseline</td>
<td style="text-align: right;">0.48</td>
<td style="text-align: right;">0.43</td>
<td style="text-align: right;">2999.15</td>
<td style="text-align: right;">3001.18</td>
<td style="text-align: right;">-1500.59</td>
<td style="text-align: right;">7.680717e-06</td>
</tr>
<tr class="even">
<td style="text-align: left;">interact</td>
<td style="text-align: right;">0.49</td>
<td style="text-align: right;">0.43</td>
<td style="text-align: right;">2995.28</td>
<td style="text-align: right;">2997.42</td>
<td style="text-align: right;">-1498.71</td>
<td style="text-align: right;">4.067051e-06</td>
</tr>
<tr class="odd">
<td style="text-align: left;">interact_nonlin</td>
<td style="text-align: right;">0.53</td>
<td style="text-align: right;">0.48</td>
<td style="text-align: right;">2905.87</td>
<td style="text-align: right;">2908.49</td>
<td style="text-align: right;">-1454.25</td>
<td style="text-align: right;">9.999883e-01</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>For our ultimate model comparison we want to stick to using the IC values. As far as choosing between WAIC vs.&nbsp;LOOIC, the latter has better diagnostics for noting whether there are potential problems in using it. In practice, they will almost always agree with one another. As we noted previously, LOOIC reflects the ELPD, and this value is used in constructing the model weights shown in the last column<sup>5</sup>. The model weights can then be used in making final predictions (i.e.&nbsp;model averaging), or just providing a different way for your audience to gauge which model might be preferred.</p>
</section>
<section id="problems-at-the-loo" class="level3">
<h3 class="anchored" data-anchor-id="problems-at-the-loo">Problems at the loo</h3>
<p>After the model issues discussed in <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-i/">Part I</a>, the next most common point of confusion I see people have is with model comparison, and using LOO in particular. Part of the reason is that this is an area of ongoing research and development, and most of the tools and documentation are notably technical. Another reason is that these are not perfect tools. They can fail to show notable problems for models that are definitely misspecified, and flag models that are essentially okay. Sometimes they flag models that other indicators may suggest are better models relatively speaking, which actually isn’t a contradiction, but which may indicate an overfit situation.</p>
<p>So in general, no tool is perfect, but in the real world we have to get things, so let’s address a couple issues.</p>
<section id="not-so-different-models" class="level5">
<h5 class="anchored" data-anchor-id="not-so-different-models">Not so different models</h5>
<p>Let’s start with the case where models do not appear to perform very differently. If two models aren’t very different from one another, the usual response is to go with the simpler model. For example, if we were only comparing the baseline model vs.&nbsp;the interaction model, there really isn’t much difference in terms of LOOIC/ELPD. However, we will have to consider things a little differently in the Bayesian context. Consider the following two thoughts.</p>
<blockquote class="blockquote">
<p>The general issue is that with <em>unregularized</em> estimation such as least squares or maximum likelihood, adding parameters to a model (or making a model more complex) leads to overfitting. With regularized estimation such as multilevel modeling, Bayesian inference, lasso, deep learning, etc., the regularization adds complexity but in a way that reduces the problem of overfitting. So traditional notions of model complexity and tradeoffs are overturned. ~ Andrew Gelman</p>
</blockquote>
<blockquote class="blockquote">
<p>Sometimes a simple model will outperform a more complex model… Nevertheless, I believe that deliberately limiting the complexity of the model is not fruitful when the problem is evidently complex. Instead, if a simple model is found that outperforms some particular complex model, the appropriate response is to define a different complex model that captures whatever aspect of the problem led to the simple model performing well. ~ Radford Neal</p>
</blockquote>
<p>The take-home message here is that <em>simpler is not always better</em>. And to be frank, using <em>penalized</em> (a.k.a. <em>regularized</em>) approaches (e.g.&nbsp;lasso, ridge, mixed models) should probably be our default model in the non-Bayesian context, and it turns out that such approaches actually approximate a Bayesian one with specific priors. In the end, you may have to think about things a little more carefully, and given that you are using methods that can help avoid overfitting, you may instead lean on a more complex model with otherwise similar performing models. And that would be closer to how nature works anyway, which is always more complex than our brains can easily understand.</p>
<!-- ###### Loo warnings -->
<!-- So what should we do here? As an example, let's start with our complex model and get the leave-one-out criterion measure.  I will avoid as much technical jargon as possible so that the applied modeler can get on with things.  The first part are the stats that are used in the previous model comparison and weighting, particularly the elpd_loo[^looic].  We also get  influence statistics for our observed data.   -->
<!-- ```{r loo-basic} -->
<!-- loo(model_baseline) -->
<!-- loo(model_interact_nonlin) -->
<!-- ``` -->
<!-- ```{r pareto-compare, echo=FALSE} -->
<!-- pareto_probs = loo(model_interact_nonlin) -->
<!-- # str(pareto_probs) -->
<!-- loo_pit_interact_nonlin = pp_check(model_interact_nonlin, type = 'loo_pit') -->
<!-- loo_pit_baseline = pp_check(model_baseline, type = 'loo_pit') -->
<!-- # bind_rows( -->
<!-- #   loo_pit_baseline %>% layer_data(), -->
<!-- #   loo_pit_interact_nonlin %>% layer_data(), -->
<!-- #   .id = 'model' -->
<!-- # ) %>%  -->
<!-- #   mutate( -->
<!-- #     model = factor(model, labels = c('baseline', 'complex')), -->
<!-- #     alpha = rep(c(1, .5), e = 1000) -->
<!-- #     ) %>%  -->
<!-- #   rename(Uniform = x, `LOO-PIT` = y) %>%  -->
<!-- #   ggplot(aes(Uniform, `LOO-PIT`)) + -->
<!-- #   geom_line(aes(color = model, alpha = I(alpha)), size = 2) + -->
<!-- #   geom_line(aes(y = theoretical), color = '#990021', alpha = .5) + -->
<!-- #   scico::scale_color_scico_d(begin = .25, end = .75) + -->
<!-- #   theme_clean() -->
<!-- # main_df %>%  -->
<!-- #   slice(which(pareto_probs$diagnostics$pareto_k > .5)) %>%  -->
<!-- #   bind_cols(pareto_probs$diagnostics %>% -->
<!-- #               as_tibble() %>% -->
<!-- #               slice(which(pareto_probs$diagnostics$pareto_k > .5))) %>%  -->
<!-- #   bind_cols(pareto_probs$pointwise %>% -->
<!-- #               as_tibble() %>% -->
<!-- #               slice(which(pareto_probs$diagnostics$pareto_k > .5))) -->
<!-- ``` -->
</section>
<section id="pareto-values" class="level5">
<h5 class="anchored" data-anchor-id="pareto-values">Pareto values</h5>
<p>Let’s look again at the basic result from using the <span class="func" style="">loo</span> function.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb41" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb41-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loo</span>(model_interact)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
Computed from 1000 by 1000 log-likelihood matrix.

         Estimate   SE
elpd_loo  -1498.7 22.0
p_loo        89.5  3.9
looic      2997.4 44.0
------
MCSE of elpd_loo is 0.4.
MCSE and ESS estimates assume MCMC draws (r_eff in [0.6, 1.2]).

All Pareto k estimates are good (k &lt; 0.67).
See help('pareto-k-diagnostic') for details.</code></pre>
</div>
</div>
<p>We haven’t yet discussed <em>Pareto values</em>, but it is not uncommon to get a result with some values that are not ‘good’ or ‘ok’. If you happen to see Pareto values in the ‘bad’ or ‘very bad’ group, what does it mean? You can read the definition provided <a href="https://mc-stan.org/loo/reference/loo-glossary.html#pareto-k-estimates">here</a>, but it may not help many due to the background knowledge needed to parse it. However, you can just understand it as an (leave-one-out) <em>extreme value</em> diagnostic, and if it is a problem, it mostly means your LOOIC may not be good for comparing models.</p>
<p>As in the standard model setting, ‘outliers’ indicate <em>model incompetence</em>, or in other words, the model is unable to understand such observations. Unless you have reason to suspect something inherently wrong in the data (e.g.&nbsp;an incorrect value/typo), an outlier is a sign that your model is not able to capture the data fully. It definitely is <em>not</em> a reason to remove the observation!</p>
<p>If you have Pareto values &gt; .7, you may recalculate LOOIC with the options provided by the <span class="func" style="">loo</span> function or use the <span class="func" style="">reloo</span> function, getting a better estimate that could then be used in, for example, model stacking for prediction. If you don’t discover many outliers, it probably won’t make much difference in your final estimates and conclusions, and so probably isn’t worth the trouble pursing much further. The output for Pareto values doesn’t even save the row identifying information that would make it easy to find which observations are the problem, but you can do something like the following if you need to.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb43" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb43-1">pareto <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loo</span>(model_interact_nonlin)</span>
<span id="cb43-2"></span>
<span id="cb43-3">problems <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> pareto<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>pointwise <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb43-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb43-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rowid_to_column</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb43-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(influence_pareto_k <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> .<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb43-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pull</span>(rowid)</span>
<span id="cb43-8"></span>
<span id="cb43-9">model_interact_nonlin<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>data <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb43-10">  <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;">rank =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rank</span>(y)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb43-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">slice</span>(problems)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>          y b1 b2        x1        x2         x3 group rank
1  8.198540  1  1 0.3636720 0.0652158  1.3760312    68 1000
2 -1.123859  1  0 0.8573758 0.6268734 -0.3354954    97    3</code></pre>
</div>
</div>
<p>As we might have expected, the observations with the more extreme target values are likely to be problems (rank closer to 1 or 1000), but for some of these, there is nothing to suggest why they might be difficult, and it’s even harder to speculate in typical modeling situations with more predictors and complexity. Furthermore, outside of additional model complexity, which might then hamper interpretation, there is often little we can do about this, or at least, what we can do is generally not obvious in applied settings.</p>
</section>
</section>
</section>
<section id="model-averaging" class="level2">
<h2 class="anchored" data-anchor-id="model-averaging">Model Averaging</h2>
<p>With the previous statistics for model comparison we can obtain relative model weights, using the <span class="func" style="">model_weights</span> function. This essentially spreads the total probability of the models across all those being compared. These weights in turn allow us to obtain (weighted) average predictions. The key idea being that we do not select a ‘best’ model, but rather combine their results for predictive purposes<sup>6</sup>.</p>
<p>We can start by comparing the first two models. Adding the interactions helped, and comparing the weights suggests that the interaction model would be contributing most to the averaged predictions.</p>
<div class="cell">
<div class="cell-output cell-output-stdout">
<pre><code>Method: stacking
------
               weight
model_baseline 0.234 
model_interact 0.766 </code></pre>
</div>
</div>
<p>If we compare the baseline to our most complex model, almost the entirety of the weight is placed on the latter.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb46" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb46-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loo_model_weights</span>(model_baseline, model_interact_nonlin)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Method: stacking
------
                      weight
model_baseline        0.000 
model_interact_nonlin 1.000 </code></pre>
</div>
</div>
<p>Now we compare all three, with roughly the same conclusion.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: right;" data-quarto-table-cell-role="th">model_baseline</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">model_interact</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">model_interact_nonlin</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">1e-05</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0.99999</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>Now what about those average predictions? Let’s create a data frame that sets the continuous covariates at their means, and at each level of the categorical covariates. For our purposes here, we will also ignore group effects<sup>7</sup>. We then will make average predictions for those observations using <span class="func" style="">pp_average</span>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">prediction_data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crossing</span>(</span>
<span id="cb48-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b1 =</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;">1</span>,</span>
<span id="cb48-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">b2 =</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;">1</span>,</span>
<span id="cb48-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x1 =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb48-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x2 =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb48-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x3 =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb48-7">)</span>
<span id="cb48-8"></span>
<span id="cb48-9">average_predictions <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pp_average</span>(</span>
<span id="cb48-10">  model_baseline,</span>
<span id="cb48-11">  model_interact,</span>
<span id="cb48-12">  model_interact_nonlin,</span>
<span id="cb48-13">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> prediction_data,</span>
<span id="cb48-14">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">re_formula =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb48-15">)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: right;" data-quarto-table-cell-role="th">b1</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">b2</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">x1</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">x2</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">x3</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Estimate</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Est.Error</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Q2.5</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Q97.5</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Baseline Estimate</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Model Nonlin Est.</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">2.73</td>
<td style="text-align: right;">1.03</td>
<td style="text-align: right;">0.67</td>
<td style="text-align: right;">4.70</td>
<td style="text-align: right;">2.69</td>
<td style="text-align: right;">2.73</td>
</tr>
<tr class="even">
<td style="text-align: right;">0</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">2.29</td>
<td style="text-align: right;">0.98</td>
<td style="text-align: right;">0.31</td>
<td style="text-align: right;">4.21</td>
<td style="text-align: right;">2.54</td>
<td style="text-align: right;">2.30</td>
</tr>
<tr class="odd">
<td style="text-align: right;">1</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">2.95</td>
<td style="text-align: right;">1.03</td>
<td style="text-align: right;">1.00</td>
<td style="text-align: right;">4.98</td>
<td style="text-align: right;">3.48</td>
<td style="text-align: right;">2.93</td>
</tr>
<tr class="even">
<td style="text-align: right;">1</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">3.09</td>
<td style="text-align: right;">1.02</td>
<td style="text-align: right;">1.07</td>
<td style="text-align: right;">5.04</td>
<td style="text-align: right;">3.34</td>
<td style="text-align: right;">3.08</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>As expected, we can see that the averaged predictions are essentially the same as what we would get from the model with all the weight. In other scenarios, you may be dealing with a more nuanced result.</p>
</section>
<section id="cross-validation" class="level2">
<h2 class="anchored" data-anchor-id="cross-validation">Cross-Validation</h2>
<p>In machine learning contexts, cross-validation is the default approach to considerations of model performance. We can do so easily within the Bayesian context as well. I go ahead and do so for a single model, as well as all three models, so we can see how our previous performance metrics might change. In general, prediction on a validation set will be expected to be worse than on the training data<sup>8</sup>, but it is the better estimate of prediction error.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb49" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb49-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(future)</span>
<span id="cb49-2"></span>
<span id="cb49-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plan</span>(multisession)</span>
<span id="cb49-4"></span>
<span id="cb49-5">model_interact_nonlin_cv <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">kfold</span>(</span>
<span id="cb49-6">  model_interact_nonlin,</span>
<span id="cb49-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">K =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb49-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">chains =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb49-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">save_fits =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb49-10">)</span>
<span id="cb49-11"></span>
<span id="cb49-12">model_all_cv <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">kfold</span>(</span>
<span id="cb49-13">  model_baseline,</span>
<span id="cb49-14">  model_interact,</span>
<span id="cb49-15">  model_interact_nonlin,</span>
<span id="cb49-16">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">K =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span id="cb49-17">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">chains =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb49-18">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">save_fits =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb49-19">)</span>
<span id="cb49-20"></span>
<span id="cb49-21"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plan</span>(sequential)</span></code></pre></div></div>
</div>
<p>With a single cross-validation model in place, we can then make predictions with it to get the test error or other metrics of interest. As we expect, the training error, i.e.&nbsp;that on the original/full data is better than the test error, but the latter is the better estimate of our model error, and thus a better metric for comparing models.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">test_predictions <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">kfold_predict</span>(model_interact_nonlin_cv)</span>
<span id="cb50-2"></span>
<span id="cb50-3"></span>
<span id="cb50-4">train_error <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> yardstick<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rmse_vec</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">truth    =</span> model_interact_nonlin<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>data<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>y,</span>
<span id="cb50-5">                                  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">estimate =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fitted</span>(model_interact_nonlin)[, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb50-6"></span>
<span id="cb50-7">test_error  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> yardstick<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rmse_vec</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">truth    =</span> test_predictions<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>y,</span>
<span id="cb50-8">                                  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">estimate =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">colMeans</span>(test_predictions<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>yrep))</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: right;" data-quarto-table-cell-role="th">train_error</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">test_error</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">0.933</td>
<td style="text-align: right;">1.051</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>Now let’s revisit our LOOIC comparison, only now it is based on LOOIC via the cross-validation process. We would come to the same conclusions, but we can see that the differences, while still substantial, are not as great. In addition, other standard metrics can help validate the Bayesian-specific metrics, as RMSE does here.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## model_all_cv$diffs</span></span></code></pre></div></div>
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">model</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">elpd_diff</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">se_diff</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">elpd_kfold</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">rmse</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">model_interact_nonlin</td>
<td style="text-align: right;">0.00</td>
<td style="text-align: right;">0.00</td>
<td style="text-align: right;">-1472.57</td>
<td style="text-align: right;">1.06</td>
</tr>
<tr class="even">
<td style="text-align: left;">model_baseline</td>
<td style="text-align: right;">-33.62</td>
<td style="text-align: right;">11.33</td>
<td style="text-align: right;">-1506.19</td>
<td style="text-align: right;">1.09</td>
</tr>
<tr class="odd">
<td style="text-align: left;">model_interact</td>
<td style="text-align: right;">-41.59</td>
<td style="text-align: right;">11.05</td>
<td style="text-align: right;">-1514.16</td>
<td style="text-align: right;">1.10</td>
</tr>
</tbody>
</table>
</div>
</div>
<section id="variable-selection" class="level3">
<h3 class="anchored" data-anchor-id="variable-selection">Variable Selection</h3>
<p>If desired, we can use cross-validation to help with feature selection. We’ve already discussed why this really shouldn’t be a concern, namely because there rarely is a reason to throw out variables regardless of how minimally important they might be. Furthermore, interactions among variables are the norm, not the exception. So while a variable might not do well on its own, it can be extremely important in how it interacts with another feature.</p>
<p>In any case, one can use the <span class="pack" style="">projpred</span> package to get a sense of this, and also why it can be problematic. For starters, we cannot test our nonlinear model due to its complexity<sup>9</sup>. But we can also see that we would not choose the true underlying model using this approach. In addition, for expediency I had to turn off the random effects, otherwise this would take more time than I wanted to spend for this demo (the group effect would have been the first selected). In short, be prepared for issues that might accompany the complexities in your model<sup>10</sup>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(projpred)</span>
<span id="cb52-2"></span>
<span id="cb52-3">model_feature_select_cv <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">update</span>(model_interact, .<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="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>group), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cores =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb52-4">ref_model <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_refmodel</span>(model_feature_select_cv)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># reference model structure</span></span>
<span id="cb52-5"></span>
<span id="cb52-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">options</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mc.cores =</span> parallel<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">detectCores</span>())</span>
<span id="cb52-7">var_select <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cv_varsel</span>(ref_model)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># will take a very long time</span></span></code></pre></div></div>
</div>
<p>With results in place we can summarize and visualize our results, similar to how we have done before. This is from <code>summary(var_select)</code>. You can see how often features are selected across all cv runs via the observation level folds, and the expected loo results.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: right;" data-quarto-table-cell-role="th">size</th>
<th style="text-align: left;" data-quarto-table-cell-role="th">ranking</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">cv_proportions</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">elpd</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">elpd.se</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">elpd.diff</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">elpd.diff.se</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">0</td>
<td style="text-align: left;">(Intercept)</td>
<td style="text-align: right;">NA</td>
<td style="text-align: right;">-1779.6</td>
<td style="text-align: right;">21.5</td>
<td style="text-align: right;">-63.5</td>
<td style="text-align: right;">11.3</td>
</tr>
<tr class="even">
<td style="text-align: right;">1</td>
<td style="text-align: left;">b1</td>
<td style="text-align: right;">1.0</td>
<td style="text-align: right;">-1736.4</td>
<td style="text-align: right;">21.9</td>
<td style="text-align: right;">-20.3</td>
<td style="text-align: right;">7.1</td>
</tr>
<tr class="odd">
<td style="text-align: right;">2</td>
<td style="text-align: left;">x3</td>
<td style="text-align: right;">1.0</td>
<td style="text-align: right;">-1714.5</td>
<td style="text-align: right;">21.3</td>
<td style="text-align: right;">1.6</td>
<td style="text-align: right;">2.3</td>
</tr>
<tr class="even">
<td style="text-align: right;">3</td>
<td style="text-align: left;">b2</td>
<td style="text-align: right;">0.8</td>
<td style="text-align: right;">-1723.1</td>
<td style="text-align: right;">21.7</td>
<td style="text-align: right;">-7.0</td>
<td style="text-align: right;">2.1</td>
</tr>
<tr class="odd">
<td style="text-align: right;">4</td>
<td style="text-align: left;">x2</td>
<td style="text-align: right;">0.7</td>
<td style="text-align: right;">-1725.1</td>
<td style="text-align: right;">21.7</td>
<td style="text-align: right;">-8.9</td>
<td style="text-align: right;">1.9</td>
</tr>
<tr class="even">
<td style="text-align: right;">5</td>
<td style="text-align: left;">x1</td>
<td style="text-align: right;">0.8</td>
<td style="text-align: right;">-1720.1</td>
<td style="text-align: right;">21.7</td>
<td style="text-align: right;">-4.0</td>
<td style="text-align: right;">1.7</td>
</tr>
<tr class="odd">
<td style="text-align: right;">6</td>
<td style="text-align: left;">b2:x1</td>
<td style="text-align: right;">0.8</td>
<td style="text-align: right;">-1721.4</td>
<td style="text-align: right;">21.7</td>
<td style="text-align: right;">-5.3</td>
<td style="text-align: right;">1.3</td>
</tr>
<tr class="even">
<td style="text-align: right;">7</td>
<td style="text-align: left;">b1:b2</td>
<td style="text-align: right;">0.8</td>
<td style="text-align: right;">-1715.9</td>
<td style="text-align: right;">21.6</td>
<td style="text-align: right;">0.2</td>
<td style="text-align: right;">0.1</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>The plot of elpd (higher better) and rmse (lower better) suggest a possible cutoff of submodel size 2, which would include <code>b1</code> and <code>x3</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb53" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb53-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># plot predictive performance on training data</span></span>
<span id="cb53-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(var_select, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">stats =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'elpd'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'rmse'</span>))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/cv-feature-selection-plot-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Here is the final rank ordering with density plots for the two best features + one other for comparison. Unexpectedly, the ‘top’ feature is almost centered on zero. Go figure.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ranking</span>(var_select)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>fulldata</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "b1"    "x3"    "b2"    "x2"    "x1"    "b2:x1" "b1:b2"</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb56" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb56-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mcmc_areas</span>(</span>
<span id="cb56-2">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.matrix</span>(ref_model<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>fit),</span>
<span id="cb56-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pars =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b_b11'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b_x3'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b_x1'</span>)</span>
<span id="cb56-4">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb56-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coord_cartesian</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xlim =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/index_files/figure-html/cv-feature-select-mcmc-area-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
</section>
</section>
<section id="the-rabbit-hole-of-model-comparsion" class="level2">
<h2 class="anchored" data-anchor-id="the-rabbit-hole-of-model-comparsion">The rabbit hole of model comparsion</h2>
<p>If you start to look more into this, there are numerous technical articles, whole websites, and various discussions regarding how to go about it. I’m guessing many do not want to try and parse highly technical information, only to still feel confused about what to actually do. Many suggestions amount to ‘your model is probably misspecified’, but without additional thoughts on how to proceed. Some of the data issues that lead to problems are just the reality of data doing what data does. There are also suggestions that posterior predictive checks (PPCs) can be used to detect the problem. But a difficulty here is that these don’t detect anything by themselves without very specific directed action, nor do they typically have a standard metric to report, so the practical utility does have its limits. In addition, it’s not clear to me that issues or problems regarding specific statistics for model comparison (e.g.&nbsp;LOOIC estimation) should be a basis for altering a model, unless there is an obvious path for doing so. And let’s face it, if there was, you’d probably already be taking it.</p>
<p>For those that do want to go down the rabbit hole, I have numerous links in the resources section.</p>
</section>
<section id="solutions-for-model-comparison" class="level2">
<h2 class="anchored" data-anchor-id="solutions-for-model-comparison">Solutions for Model Comparison</h2>
<p>When doing model comparison, the following summarizes some basic steps you can take.</p>
<ul>
<li><p>Don’t assume you’ll have any certainty about some model being ‘best’.</p></li>
<li><p>Use the metrics noted above, e.g.&nbsp;LOOIC, when making comparisons (not R<sup>2</sup>).</p></li>
<li><p>Avoid the problem and fit the model that includes everything of interest, assuming you have a decent data size to do so. It is likely you can still learn some things about the model by comparing it to others.</p></li>
<li><p>Variable selection is typically just a model comparison problem restated differently, and in a lot of cases I’ve come across, a misguided endeavor. If something is even minimally important, there is no reason to throw it out, as you’d just have worse predictions doing so. With complex models, you can’t assess one variable without consideration of others, so trying to say that one is more important than the others doesn’t really make sense.</p></li>
<li><p>If some application performance measure is obvious and available to assess, pick a model that does best in that setting.</p></li>
<li><p>If trying to select among many competing models, e.g.&nbsp;feature selection, you should consider why you are in this situation. If you don’t have much data, then the usual model selection criteria may lead you notably astray. If you have a lot of data, consider why you need to select a subset of predictors and not use all available. If you are somewhere in between, note that you’ll likely spend a lot more time here and still not be confident in the results. However, there are approaches, such as those in the <span class="pack" style="">projpred</span> package, that might be useful, but likely will only work for simpler models.</p></li>
</ul>
</section>
</section>
<section id="summary-the-practical-approach-to-bayesian-models" class="level1">
<h1>Summary: The Practical Approach to Bayesian Models</h1>
<p>For applied analysts, just a few steps can go a long way toward making you feel better about your model. You can assess your priors in a straightforward fashion before starting, and that will not only help you have more confidence in your results, but likely also help you convince others of the results as well. Once you run the model, explore it in-depth, and take advantage of taking the Bayesian approach that allows you to more easily explore it. Many tools are available for you to asses model effectiveness, use them!</p>
<p>Key to understanding any model is through prediction, which can make even complex settings more relatable. You can pit models against one another to see which performs best in a predictive sense, but note that more complexity is more realistic, and in the Bayesian world, you don’t have to choose a ‘best’ model.</p>
<p>You can use the diagnostics to further understand why and how the model isn’t perfect, which might give you some ideas on how you might do things differently in the future. However, the diagnostic criteria and other statistics may themselves have problems, the solutions of which are difficult. You should be okay with leaving some aspects of your model imperfect. There’s always next time!</p>
<p>All in all, any modeling endeavor done well, Bayesian or otherwise, will take time, and often encounter difficulties. With the right tools, working through these difficulties can lead to a better understanding of both the data (i.e.&nbsp;the world around us), and how we think about it!</p>
</section>
<section id="resources" class="level1">
<h1>Resources</h1>
<section id="prior-checks" class="level3">
<h3 class="anchored" data-anchor-id="prior-checks">Prior Checks</h3>
<ul>
<li><a href="https://statmodeling.stat.columbia.edu/2019/08/10/">Gelman’s prior check approach</a></li>
<li><a href="https://github.com/stan-dev/stan/wiki/Prior-Choice-Recommendations">Stan Group’s Prior Choice Recommendations</a></li>
</ul>
</section>
<section id="r2" class="level3">
<h3 class="anchored" data-anchor-id="r2">R<sup>2</sup></h3>
<ul>
<li><p><a href="https://avehtari.github.io/bayes_R2/bayes_R2.html">Bayesian R2 and LOO-R2</a> Vehtari et al.</p></li>
<li><p>Andrew Gelman, Ben Goodrich, Jonah Gabry, and Aki Vehtari (2018). R-squared for Bayesian regression models. The American Statistician, doi:10.1080/00031305.2018.1549100. <a href="http://www.stat.columbia.edu/~gelman/research/unpublished/bayes_R2_v3.pdf">Online Preprint</a>.</p></li>
</ul>
</section>
<section id="model-comparison-1" class="level3">
<h3 class="anchored" data-anchor-id="model-comparison-1">Model Comparison</h3>
<ul>
<li><p><a href="https://mc-stan.org/loo/reference/loo-glossary.html">The LOO glossary</a></p></li>
<li><p><a href="https://mc-stan.org/loo/articles/loo2-weights.html">LOO model weights</a></p></li>
<li><p><a href="https://avehtari.github.io/modelselection/CV-FAQ.html#16_What_to_do_if_I_have_many_high_Pareto_(k)%E2%80%99s">16 What to do if I have many high Pareto k’s?</a></p></li>
</ul>
<section id="stan-forum-threads" class="level4">
<h4 class="anchored" data-anchor-id="stan-forum-threads">Stan Forum Threads</h4>
<ul>
<li><p><a href="https://discourse.mc-stan.org/t/understanding-looic/13409/6">Understanding LOOIC</a></p></li>
<li><p><a href="https://discourse.mc-stan.org/t/can-waic-looic-be-used-to-compare-models-with-different-likelihoods/7380">Can WAIC/LOOIC be used to compare models with different likelihoods?</a></p></li>
<li><p><a href="https://discourse.mc-stan.org/t/a-quick-note-what-i-infer-from-p-loo-and-pareto-k-values/3446">A quick note what I infer from p_loo and Pareto km values</a></p></li>
<li><p><a href="https://discourse.mc-stan.org/t/recommendations-for-what-to-do-when-k-exceeds-0-5-in-the-loo-package/3417">Recommendations for what to do when k exceeds 0.5 in the loo package?</a></p></li>
<li><p><a href="https://discourse.mc-stan.org/t/improve-model-with-some-observations-pareto-0-7/17500">Improve model with some observations Pareto &gt;0.7</a></p></li>
<li><p><a href="https://discourse.mc-stan.org/t/pareto-k-for-outlier-detection/12177/9">Pareto K for outlier detection 1</a></p></li>
<li><p><a href="https://discourse.mc-stan.org/t/good-pp-check-and-r-square-but-large-pareto-k-values/17678">Possibly incompatible metrics</a></p></li>
</ul>
</section>
</section>
<section id="pareto-values-1" class="level3">
<h3 class="anchored" data-anchor-id="pareto-values-1">Pareto values</h3>
<ul>
<li><p>Vehtari, A., Simpson, D., Gelman, A., Yao, Y., and Gabry, J. (2019). Pareto smoothed importance sampling. <a href="https://arxiv.org/abs/1507.02646/">preprint arXiv:1507.02646</a></p></li>
<li><p><a href="https://discourse.mc-stan.org/t/a-quick-note-what-i-infer-from-p-loo-and-pareto-k-values/3446">Aki Vehtari’s A quick note what I infer from p_loo and Pareto k values</a></p></li>
<li><p><a href="https://avehtari.github.io/modelselection/CV-FAQ.html#16_What_to_do_if_I_have_many_high_Pareto_(k)%E2%80%99s">What to do if I have many high Pareto k?</a></p></li>
</ul>
</section>
<section id="model-averaging-1" class="level3">
<h3 class="anchored" data-anchor-id="model-averaging-1">Model Averaging</h3>
<ul>
<li><p>Vehtari, A., Gelman, A., and Gabry, J. (2017a). Practical Bayesian model evaluation using leave-one-out cross-validation and WAIC. Statistics and Computing. 27(5), 1413–1432. doi:10.1007/s11222-016-9696-4 (<a href="http://link.springer.com/article/10.1007%2Fs11222-016-9696-4">journal version</a>, <a href="https://arxiv.org/abs/1507.04544">preprint arXiv:1507.04544</a>).</p></li>
<li><p>Yao, Y., Vehtari, A., Simpson, D., and Gelman, A. (2018) Using stacking to average Bayesian predictive distributions. Bayesian Analysis, advance publication, doi:10.1214/17-BA1091. (<a href="https://projecteuclid.org/euclid.ba/1516093227">online</a>).</p></li>
</ul>
</section>
<section id="cross-validation-1" class="level3">
<h3 class="anchored" data-anchor-id="cross-validation-1">Cross-Validation</h3>
<ul>
<li><p><a href="https://avehtari.github.io/modelselection/CV-FAQ.html">CV FAQ</a></p></li>
<li><p><a href="https://mc-stan.org/projpred/articles/quickstart.html">Projpred Quickstart</a></p></li>
<li><p><a href="https://rawgit.com/avehtari/modelselection_tutorial/master/roaches.html#22_cross-validation_checking">Bayesian data analysis - roaches cross-validation demo</a></p></li>
</ul>
</section>
<section id="misc" class="level3">
<h3 class="anchored" data-anchor-id="misc">Misc</h3>
<ul>
<li><p><a href="https://mc-stan.org/docs/2_26/stan-users-guide/problematic-posteriors-chapter.html">Problematic Posteriors</a></p></li>
<li><p>Gabry, J. , Simpson, D. , Vehtari, A. , Betancourt, M. and Gelman, A. (2019), Visualization in Bayesian workflow. J. R. Stat. Soc. A, 182: 389-402. doi:10.1111/rssa.12378. (<a href="https://rss.onlinelibrary.wiley.com/doi/abs/10.1111/rssa.12378">journal version</a>, <a href="https://arxiv.org/abs/1709.01449">arXiv preprint</a>, <a href="https://github.com/jgabry/bayes-vis-paper">code on GitHub</a>)</p></li>
<li><p><a href="http://mc-stan.org/cmdstanr/articles/cmdstanr.html">Use CmdStan to save memory</a></p></li>
<li><p><a href="https://jrnold.github.io/bayesian_notes/">Jeffrey Arnold’s Bayesian Notes</a> has nice examples of many models and good summaries otherwise</p></li>
</ul>


</section>
</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>If you were coding in Stan directly, you can run a single iteration to see if your code compiles at all.↩︎</p></li>
<li id="fn2"><p>Daniel Lakeland proposes (<a href="https://statmodeling.stat.columbia.edu/2019/08/10/">as a comment in the discussion of the 10% approach outlined</a>) an alternative approach is whether the posterior estimate falls within the 95% highest density interval of the prior. This is available via the method argument in the demonstrated function (<code>method = 'lakeland'</code>).↩︎</p></li>
<li id="fn3"><p>As in the text of the output, this is the same as testing whether abs(b1) + abs(b2) - 2*x1 &gt; 0. In this case the resulting value is greater than zero with high probability.↩︎</p></li>
<li id="fn4"><p>Similar to AIC, LOOIC is ~ -2*expected log posterior density (<em>ELPD</em>), similar to how we use -2*log likelihood (a.k.a. deviance) in standard approaches for AIC. We don’t add a penalty for parameters here, and I think this is because the regularization is already built in to the modeling process, and the number of parameters might be more difficult to define in the Bayesian context with priors.↩︎</p></li>
<li id="fn5"><p>Technically we can use WAIC to produce weights like we do with AIC, e.g.&nbsp;<code>exp(waic) / sum(exp(all_waics))</code>, but this isn’t recommended. The stacking approach allows similar models to share their weight, while more unique models will mostly keep their weight as additional models are added.↩︎</p></li>
<li id="fn6"><p>Some might be familiar with Bayesian model averaging. Conceptually we aren’t changing much, but BMA assumes that one of our models is the true model, while the stacking approach underlying these weights does not. It is also different from conventional stacking in machine learning in that we are trying to average posterior predictive distributions, rather than point estimates.↩︎</p></li>
<li id="fn7"><p>In other words, for prediction we set <code>re_formula = NA</code>.↩︎</p></li>
<li id="fn8"><p>At the time of this writing, the underlying use of the <span class="pack" style="">furrr</span> package defaults to not using a seed in it’s parallelization process, and then warns you that a seed has not been set for each repeated use of a cluster. Passing a seed through the seed argument won’t actually do anything presently here, so one will hope that <span class="pack" style="">furrr</span> will change their default behavior. It’s a nuisance that can be ignored though.↩︎</p></li>
<li id="fn9"><p>Perhaps this might be possible in a future release, but there are other complications that might make it problematic still.↩︎</p></li>
<li id="fn10"><p>I revisited this late 2024, and it took <em>hours</em> to run the <code>cv_varsel</code> under these defaults, and I found the resulting objects even less intuitive to work with. They mention in the vignette there are many ways to speed it up, but accuracy will be compromised. In short, this is not something you could iterate over. On the plus side, the results were consistent with what I had seen before, for better or worse.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2021,
  author = {Clark, Michael},
  title = {Practical {Bayes} {Part} {II}},
  date = {2021-02-28},
  url = {https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2021" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2021. <span>“Practical Bayes Part II.”</span> February
28. <a href="https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/">https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/</a>.
</div></div></section></div> ]]></description>
  <category>bayesian</category>
  <guid>https://m-clark.github.io/posts/2021-02-28-practical-bayes-part-ii/</guid>
  <pubDate>Sun, 28 Feb 2021 05:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/r_and_stan.png" medium="image" type="image/png" height="53" width="144"/>
</item>
<item>
  <title>Models by Example</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2020-11-30-models-by-example/</link>
  <description><![CDATA[ 





<section id="new-book" class="level1">
<h1>New Book</h1>
<p>I’ve completed a new bookdown document, <a href="https://m-clark.github.io/models-by-example/">Models by Example</a>, that converts most of the code from my Miscellaneous R repo. I initially just wanted to update the code, but decided to use a more formal approach to make it cleaner and more accessible. It’s mostly complete, though may be added to on rare occasion, and further cleaned as I find annoying bits here and there. Each topic contains ‘by-hand’ demonstration, such that you can see conceptually how a model is estimated, or technique employed. This can help those that want to dive a little deeper to get a peek behind the curtain of the functions and packages they use, hopefully empowering them to go further with such models.</p>
<p>Topics covered include the following, and I plan to post a sample chapter soon.</p>
<section id="models" class="level5">
<h5 class="anchored" data-anchor-id="models">Models</h5>
<ul>
<li>Linear Regression</li>
<li>Logistic Regression</li>
<li>One-factor Mixed Model</li>
<li>Two-factor Mixed Model</li>
<li>Mixed Model via ML</li>
<li>Probit &amp; Bivariate Probit</li>
<li>Heckman Selection</li>
<li>Marginal Structural Model</li>
<li>Tobit</li>
<li>Cox Survival</li>
<li>Hurdle Model</li>
<li>Zero-Inflated Model</li>
<li>Naive Bayes</li>
<li>Multinomial</li>
<li>Ordinal</li>
<li>Markov Model</li>
<li>Hidden Markov Model</li>
<li>Quantile Regression</li>
<li>Cubic Spline Model</li>
<li>Gaussian Processes</li>
<li>Neural Net</li>
<li>Extreme Learning Machine</li>
<li>Reproducing Kernel Hilbert Space Regression</li>
<li>Confirmatory Factor Analysis</li>
</ul>
</section>
<section id="bayesian" class="level5">
<h5 class="anchored" data-anchor-id="bayesian">Bayesian</h5>
<ul>
<li>Basics</li>
<li>Bayesian t-test</li>
<li>Bayesian Linear Regression</li>
<li>Bayesian Beta Regression</li>
<li>Bayesian Mixed Model</li>
<li>Bayesian Multilevel Mediation</li>
<li>Bayesian IRT</li>
<li>Bayesian CFA</li>
<li>Bayesian Nonparametric Models</li>
<li>Bayesian Stochastic Volatility Model</li>
<li>Bayesian Multinomial Models</li>
<li>Variational Bayes Regression</li>
<li>Topic Model</li>
</ul>
</section>
<section id="estimation" class="level5">
<h5 class="anchored" data-anchor-id="estimation">Estimation</h5>
<ul>
<li>Maximum Likelihood</li>
<li>Penalized Maximum Likelihood</li>
<li>L1 (lasso) regularization</li>
<li>L2 (ridge) regularization</li>
<li>Newton and IRLS</li>
<li>Nelder Mead</li>
<li>Expectation-Maximization</li>
<li>Gradient Descent</li>
<li>Stochastic Gradient Descent</li>
<li>Metropolis Hastings</li>
<li>Hamiltonian Monte Carlo</li>
</ul>


</section>
</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2020,
  author = {Clark, Michael},
  title = {Models by {Example}},
  date = {2020-11-30},
  url = {https://m-clark.github.io/posts/2020-11-30-models-by-example/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2020" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2020. <span>“Models by Example.”</span> November 30. <a href="https://m-clark.github.io/posts/2020-11-30-models-by-example/">https://m-clark.github.io/posts/2020-11-30-models-by-example/</a>.
</div></div></section></div> ]]></description>
  <category>regression</category>
  <category>machine learning</category>
  <guid>https://m-clark.github.io/posts/2020-11-30-models-by-example/</guid>
  <pubDate>Mon, 30 Nov 2020 05:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/gp.svg" medium="image" type="image/svg+xml"/>
</item>
<item>
  <title>Micro-macro models</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2020-08-31-micro-macro-mlm/</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>NB: This post was revisited when updating the website early 2025, and some changes were required. Attempts to keep things consistent were made, but if you feel you’ve found an issue, please post it at <a href="http://github.com/m-clark/m-clark.github.io/issues">GitHub</a>.</p>
</blockquote>
<p><img src="https://m-clark.github.io/img/micromacro/multilevel.png" class="img-fluid"></p>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>Every once in a while, it comes up that someone has clustered data, with covariates that vary at different levels, and where mixed models or similar would normally be implemented, but in which the target variable only varies at the cluster level (or ‘group’ level- I will use the terms interchangeably). Though the outcome is at the cluster level, the individual may still want to use information from lower-level/within-cluster variables. Such situations are generically referred to as <em>micro-macro</em> models, to distinguish between the standard setting where the target varies at the lower level (which does not require a special name). An example might be using team member traits to predict team level scores. While conceptually one wants to use all available information in a model, normally we just run a model at the cluster (team) level using summaries of variables that would otherwise vary within the cluster, for example, using mean scores or proportions. Not only is it natural, it makes conceptual sense, and as such it is the default approach. Alternatives include using the within cluster variables as predictors, but this wouldn’t be applicable except in balanced settings where they would represent the same thing for each group, and even in the balanced settings collinearity might be a notable issue. So how would we deal with this?</p>
<section id="prequsites" class="level4">
<h4 class="anchored" data-anchor-id="prequsites">Prequsites</h4>
<p>For the following you should have familiarity with mixed/multilevel models, and it would help to have an understanding of factor analysis and structural equation modeling.</p>
</section>
</section>
<section id="predicting-group-level-outcomes" class="level2">
<h2 class="anchored" data-anchor-id="predicting-group-level-outcomes">Predicting Group-Level Outcomes</h2>
<p>Croon and van Veldhoven <span class="citation" data-cites="croon2007predicting">Croon and Veldhoven (2007)</span> (CV) present a group-level regression model (e.g.&nbsp;a basic linear model) as follows.</p>
<p><img src="https://latex.codecogs.com/png.latex?y_g%20=%20%5Cbeta_0%20+%20%5Cxi_g%5Cbeta_1%20+%20Z_g%5Cbeta_2%20+%20%5Cepsilon_g"></p>
<p>In this depiction, <img src="https://latex.codecogs.com/png.latex?y_g"> is the group level target variable, the <img src="https://latex.codecogs.com/png.latex?Z_g"> represent the typical observed group-level covariates and corresponding coefficients (<img src="https://latex.codecogs.com/png.latex?%5Cbeta_2">). If this were the entirety of the model, there would be no ‘levels’ to consider and we could use a standard model, say OLS regression. In the case we are interested in, some variables vary within these clusters, while others do not. Again, normally we might do a mixed model, but remember, <img src="https://latex.codecogs.com/png.latex?y_g"> only varies at the group level, so that won’t really work.</p>
<p>In this setting then, <img src="https://latex.codecogs.com/png.latex?%5Cxi_g"> represents an aggregated effect of the lower level variables. In standard practice it would just be the calculated mean, proportion, or some other metric with values for each cluster. In the CV depiction however, it is a <em>latent</em> (or perhaps several) latent variables and their corresponding effects <img src="https://latex.codecogs.com/png.latex?%5Cbeta_1">.</p>
<p>If we assume a single <img src="https://latex.codecogs.com/png.latex?%5Cxi_g"> variable, the model for the underlying within-cluster variables is the standard latent variable model, a.k.a factor analysis. With an observed multivariate <img src="https://latex.codecogs.com/png.latex?x">, e.g.&nbsp;repeated observations of some measure for an individual or, as before, team member scores, we have the <a href="https://m-clark.github.io/docs/FA_notes.html">latent linear model</a> as follows:</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Ctextbf%7Bx%7D_%7Big%7D%20=%20%5Cxi_g%5Clambda%20+%20v_%7Big%7D"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?x_%7Big%7D"> are the (possibly repeated) observations <img src="https://latex.codecogs.com/png.latex?i"> for a group/individual <img src="https://latex.codecogs.com/png.latex?g">, <img src="https://latex.codecogs.com/png.latex?%5Clambda"> are the factor loadings and variances are constant. We can now see the full model as a structural equation model as follows for a situation with five observations per group.</p>
<p><img src="https://m-clark.github.io/img/micromacro/sem.png" class="img-fluid"></p>
</section>
<section id="issues-with-aggregate-approaches" class="level2">
<h2 class="anchored" data-anchor-id="issues-with-aggregate-approaches">Issues with Aggregate Approaches</h2>
<p>CV suggest that simple aggregation, e.g.&nbsp;using a group mean, will result in problems, specifically biased estimates. They simulate data that varies the number of groups/clusters, the number of observations within groups, the intraclass correlation of observations within a group. In most of the cases they explore, the bias for the aggregate mean effect is notable, and there is sometimes small bias for the group level covariates, if they are collinear with the aggregate covariate. We will duplicate this approach later.</p>
<p>An approach to adjusting the group mean is offered by CV, with the structural model implied. These adjusted group means, or in their parlance, best linear unbiased predictors (BLUPs), result in a bias-free result. The notion of a BLUP will be familiar to those who use mixed models, as that is what the random effects are for a standard linear mixed model. As such, later on we’ll take a look at using a mixed model as a possible solution. In any case, once the adjusted means are calculated, you can then run your standard regression with the bias mostly eliminated.</p>
</section>
<section id="issues-with-adjustment" class="level2">
<h2 class="anchored" data-anchor-id="issues-with-adjustment">Issues with Adjustment</h2>
<p>It turns out the the weighting calculation proffered by CV is somewhat complicated, not easily implemented, and rarely used. Foster-Johnson &amp; Kromrey <span class="citation" data-cites="foster2018predicting">Foster-Johnson and Kromrey (2018)</span> (FJK) looked further into its utility, as well as other possible solutions that might be easier to implement. As far as type I error rate goes, FJK demonstrated that using the CV adjusted group means offers no advantage over unadjusted, and even showed less statistical power. They suggested that a standard correction for heteroscedasticity (White’s) might be enough. In applying corrected standard errors for both unadjusted and adjusted group means, FJK found there to be additional power for both approaches, but if anything still favored the standard group mean. What’s more, while the bias remained, there was actually notable variability in the adjusted mean results. FJK’s final recommendation was to use the usual group means with robust standard errors, easily implemented in any statistical package.</p>
<p>I will add that the adjustment still uses an underlying factor model of equal loadings and variances across the observations. For notably reliable scales this might be reasonable, but it isn’t a necessity. In repeated measures settings for example, we might see decreased variability across time, or practice effects, which might make the assumption more tenuous.</p>
</section>
<section id="my-perspective" class="level2">
<h2 class="anchored" data-anchor-id="my-perspective">My Perspective</h2>
<p>My first glance at the issue raised by CV immediately called to mind the standard measurement model typically employed for factor analysis, i.e.&nbsp;a latent linear model. So my interpretation was that we are simply talking about a well known fact in measurement: that reliability of the measure is key in using a mean or sum score, and decreased reliability attenuates the correlation among the variables in question. I even did <a href="https://m-clark.github.io/docs/lv_sim.html">a simulation demonstrating the problem</a> a while back. So in this case, I’m interested in the issue from a reliability perspective.</p>
<p>It turns out that factor models and mixed models share a lot in common. Those familiar with <em>growth curve models</em> know that they are equivalent to mixed models, but the comparison is a more general one of random effects methods. To demonstrate the equivalence, I’ll use a cleaned up version of the <a href="https://en.wikipedia.org/wiki/Big_Five_personality_traits">Big 5</a> data in the <span class="pack" style="">psych</span> package. Specifically, we’ll use the five items that belong to the Agreeableness measure.</p>
<p>First we make the data in both wide and long. The former makes it amenable to factor analysis, while the latter is what we need for a mixed model.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># data prep for long and wide format</span></span>
<span id="cb1-2"></span>
<span id="cb1-3">agree_df <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> noiris<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>big_five <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(A1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>A5) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">drop_na</span>()</span>
<span id="cb1-6"></span>
<span id="cb1-7">agree_long <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> agree_df <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-8">  <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;">id =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">row_number</span>())) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb1-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pivot_longer</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>id, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">names_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'variable'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values_to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'value'</span>)</span></code></pre></div></div>
</div>
<p>The standard factor model will have to be constrained to have equal loadings and item variances. In addition, we’ll estimate the intercepts, but otherwise this is your basic factor analysis.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># or use growth() to save some of the model tedium</span></span>
<span id="cb2-2">cfa_model_agree <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb2-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  agree =~ a*A1 + a*A2 + a*A3 + a*A4 + a*A5</span></span>
<span id="cb2-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  </span></span>
<span id="cb2-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  A1 ~~ var*A1</span></span>
<span id="cb2-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  A2 ~~ var*A2</span></span>
<span id="cb2-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  A3 ~~ var*A3</span></span>
<span id="cb2-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  A4 ~~ var*A4</span></span>
<span id="cb2-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  A5 ~~ var*A5</span></span>
<span id="cb2-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb2-11"></span>
<span id="cb2-12"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(lavaan)</span>
<span id="cb2-13"></span>
<span id="cb2-14">cfa_fit_agree <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cfa</span>(cfa_model_agree, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> agree_df, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">meanstructure =</span> T) </span>
<span id="cb2-15"></span>
<span id="cb2-16"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summary</span>(cfa_fit_agree)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>lavaan 0.6.17 ended normally after 11 iterations

  Estimator                                         ML
  Optimization method                           NLMINB
  Number of model parameters                        11
  Number of equality constraints                     4

  Number of observations                          2709

Model Test User Model:
                                                      
  Test statistic                               744.709
  Degrees of freedom                                13
  P-value (Chi-square)                           0.000

Parameter Estimates:

  Standard errors                             Standard
  Information                                 Expected
  Information saturated (h1) model          Structured

Latent Variables:
                   Estimate  Std.Err  z-value  P(&gt;|z|)
  agree =~                                            
    A1         (a)    1.000                           
    A2         (a)    1.000                           
    A3         (a)    1.000                           
    A4         (a)    1.000                           
    A5         (a)    1.000                           

Intercepts:
                   Estimate  Std.Err  z-value  P(&gt;|z|)
   .A1               -2.412    0.026  -94.340    0.000
   .A2                4.797    0.026  187.611    0.000
   .A3                4.599    0.026  179.859    0.000
   .A4                4.682    0.026  183.107    0.000
   .A5                4.551    0.026  177.982    0.000

Variances:
                   Estimate  Std.Err  z-value  P(&gt;|z|)
   .A1       (var)    1.201    0.016   73.607    0.000
   .A2       (var)    1.201    0.016   73.607    0.000
   .A3       (var)    1.201    0.016   73.607    0.000
   .A4       (var)    1.201    0.016   73.607    0.000
   .A5       (var)    1.201    0.016   73.607    0.000
    agree             0.571    0.022   25.621    0.000</code></pre>
</div>
</div>
<p>When we run the mixed model, we get the same variance and intercept estimates.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(lme4)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Loading required package: Matrix</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>
Attaching package: 'Matrix'</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>The following objects are masked from 'package:tidyr':

    expand, pack, unpack</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(mixedup) <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># for post-processing</span></span>
<span id="cb8-2"></span>
<span id="cb8-3">mixed_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lmer</span>(value <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="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> variable <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>id), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> agree_long,  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">REML =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>)</span>
<span id="cb8-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise_model</span>(mixed_fit, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">digits =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Computing profile confidence intervals ...</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>
Variance Components:</code></pre>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>    Group    Effect Variance    SD SD_2.5 SD_97.5 Var_prop
       id Intercept    0.571 0.755  0.727   0.785    0.322
 Residual        NA    1.201 1.096  1.081   1.111    0.678</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>
Fixed Effects:</code></pre>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>       Term  Value    SE       t P_value Lower_2.5 Upper_97.5
 variableA1 -2.412 0.026 -94.340   0.000    -2.462     -2.362
 variableA2  4.797 0.026 187.611   0.000     4.747      4.847
 variableA3  4.599 0.026 179.859   0.000     4.549      4.649
 variableA4  4.682 0.026 183.107   0.000     4.632      4.732
 variableA5  4.551 0.026 177.982   0.000     4.501      4.601</code></pre>
</div>
</div>
<p>We can also see that the estimated factor scores agree with the estimated random effects.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: right;" data-quarto-table-cell-role="th">index</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Estimated.Factor.Scores</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Estimated.Random.Effects</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">1</td>
<td style="text-align: right;">-0.453</td>
<td style="text-align: right;">-0.453</td>
</tr>
<tr class="even">
<td style="text-align: right;">2</td>
<td style="text-align: right;">-0.312</td>
<td style="text-align: right;">-0.312</td>
</tr>
<tr class="odd">
<td style="text-align: right;">3</td>
<td style="text-align: right;">-0.594</td>
<td style="text-align: right;">-0.594</td>
</tr>
<tr class="even">
<td style="text-align: right;">4</td>
<td style="text-align: right;">-0.031</td>
<td style="text-align: right;">-0.031</td>
</tr>
<tr class="odd">
<td style="text-align: right;">5</td>
<td style="text-align: right;">-0.453</td>
<td style="text-align: right;">-0.453</td>
</tr>
<tr class="even">
<td style="text-align: right;">6</td>
<td style="text-align: right;">-0.031</td>
<td style="text-align: right;">-0.031</td>
</tr>
<tr class="odd">
<td style="text-align: right;">2704</td>
<td style="text-align: right;">-0.453</td>
<td style="text-align: right;">-0.453</td>
</tr>
<tr class="even">
<td style="text-align: right;">2705</td>
<td style="text-align: right;">-1.720</td>
<td style="text-align: right;">-1.720</td>
</tr>
<tr class="odd">
<td style="text-align: right;">2706</td>
<td style="text-align: right;">-0.312</td>
<td style="text-align: right;">-0.312</td>
</tr>
<tr class="even">
<td style="text-align: right;">2707</td>
<td style="text-align: right;">-0.453</td>
<td style="text-align: right;">-0.453</td>
</tr>
<tr class="odd">
<td style="text-align: right;">2708</td>
<td style="text-align: right;">-1.297</td>
<td style="text-align: right;">-1.297</td>
</tr>
<tr class="even">
<td style="text-align: right;">2709</td>
<td style="text-align: right;">-1.157</td>
<td style="text-align: right;">-1.157</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>Usually when the term BLUP comes up it is in reference to the random effects estimated from a linear mixed model. As such, I thought it might be interesting to see how a mixed or factor model might be used to deal with the bias. I also thought it was a bit odd that neither CV nor FJK actually conduct the implied SEM (but see the paper co-authored by the <span class="pack" style="">lavaan</span> package author <span class="citation" data-cites="devlieger2016hypothesis">Devlieger et al. (2016)</span>), so I wanted to look at that too.</p>
</section>
<section id="model-setup" class="level2">
<h2 class="anchored" data-anchor-id="model-setup">Model Setup</h2>
<p>For our demonstration, I will create some data as CV did and run a variety of models to see what we get. My focus is on bias, not coverage or power, as I think FJK covered those aspects plenty. The models in particular are:</p>
<ul>
<li><strong>Standard linear model</strong>: a basic group level analysis using unadjusted means.</li>
<li><strong>Random effects</strong>: a group level model using estimated factor scores using <span class="pack" style="">lavaan</span>, or the BLUPs from <span class="pack" style="">lme4</span>, or those with heterogeneous variance via <span class="pack" style="">glmmTMB</span><sup>1</sup>. These involved a two-step approach, with the factor/mixed model followed by the standard linear model.</li>
<li><strong>Structural equation model</strong>: A full, single-step SEM via <span class="pack" style="">lavaan</span>. This model has the ability to account for the correlation of the Z and latent variable. It is exactly as CV depict in their Figure 1 and Figure @ref(fig:sem-plot) above.</li>
<li><strong>Adjusted means</strong>: Use CV’s approach</li>
</ul>
</section>
<section id="data-setup" class="level2">
<h2 class="anchored" data-anchor-id="data-setup">Data Setup</h2>
<p>I made a function<sup>2</sup> to create data with the values shown in CV (p.&nbsp;52) for a single aggregate <img src="https://latex.codecogs.com/png.latex?X"> and single group-level covariate <img src="https://latex.codecogs.com/png.latex?Z">. Using their notation, the model that generates the data is the following:</p>
<p><img src="https://latex.codecogs.com/png.latex?y_g%20=%20.3%20+%20.3Z_g%20+%20.3%5Cxi_g%20+%20%5Cepsilon_g"> <img src="https://latex.codecogs.com/png.latex?x_%7Big%7D%20=%20%5Cxi%20+%20%5Cnu_g"></p>
<p>As there, <img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2_%5Cepsilon"> is .35. While they look at a variety of situations, I’ll just consider a single scenario for our purposes, where the correlation of the <img src="https://latex.codecogs.com/png.latex?Z"> and <img src="https://latex.codecogs.com/png.latex?%5Cxi"> was .3, the intraclass correlation of the observed <img src="https://latex.codecogs.com/png.latex?x_%7Big%7D"> was .1 (i.e.&nbsp;<img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2_%5Cnu"> = 9), the number of groups was 100 and the number of observations per group was balanced at 10 (row 16 of their table 1). I simulated 1000 such data sets so that we could examine the mean value of the estimated coefficients. I first started by analyzing the result with a factor analysis, and if there are any problems such as negative variances or lack of convergence, the data is regenerated, as that will also help with any issues the mixed model would have. So the final 1000 data sets don’t have convergence issues or other problems that might make the results a little wonky.</p>
</section>
<section id="results" class="level2">
<h2 class="anchored" data-anchor-id="results">Results</h2>
<p>Here are the results. We can first take a peek at the estimated scores from the two-step approaches. The CV adjustment appears closely matched to the true score at first, but we see it’s range is very wild, which is what FJK found also. Interestingly, the BLUPs from the mixed models have less variance than the true scores. The factor score is in keeping with the BLUPs, but appears also to have notable extremes, but far less than the CV adjustment. We’ll talk about why these extremes may arise later.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<caption>Estimated scores</caption>
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">Variable</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">N</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Mean</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">SD</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Min</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Q1</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Median</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Q3</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Max</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">% Missing</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">True</td>
<td style="text-align: right;">1e+05</td>
<td style="text-align: right;">0.01</td>
<td style="text-align: right;">1.00</td>
<td style="text-align: right;">-4.31</td>
<td style="text-align: right;">-0.67</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0.68</td>
<td style="text-align: right;">4.44</td>
<td style="text-align: right;">0</td>
</tr>
<tr class="even">
<td style="text-align: left;">CV Adj</td>
<td style="text-align: right;">1e+05</td>
<td style="text-align: right;">0.01</td>
<td style="text-align: right;">1.07</td>
<td style="text-align: right;">-22.97</td>
<td style="text-align: right;">-0.65</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0.66</td>
<td style="text-align: right;">25.64</td>
<td style="text-align: right;">0</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Unadjusted</td>
<td style="text-align: right;">1e+05</td>
<td style="text-align: right;">0.00</td>
<td style="text-align: right;">1.39</td>
<td style="text-align: right;">-6.32</td>
<td style="text-align: right;">-0.93</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0.94</td>
<td style="text-align: right;">6.96</td>
<td style="text-align: right;">0</td>
</tr>
<tr class="even">
<td style="text-align: left;">BLUP_mixed</td>
<td style="text-align: right;">1e+05</td>
<td style="text-align: right;">0.00</td>
<td style="text-align: right;">0.74</td>
<td style="text-align: right;">-4.20</td>
<td style="text-align: right;">-0.48</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0.48</td>
<td style="text-align: right;">3.98</td>
<td style="text-align: right;">0</td>
</tr>
<tr class="odd">
<td style="text-align: left;">BLUP_mixed_hetvar</td>
<td style="text-align: right;">1e+05</td>
<td style="text-align: right;">0.00</td>
<td style="text-align: right;">0.74</td>
<td style="text-align: right;">-4.18</td>
<td style="text-align: right;">-0.48</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0.47</td>
<td style="text-align: right;">3.97</td>
<td style="text-align: right;">0</td>
</tr>
<tr class="even">
<td style="text-align: left;">Factor Score</td>
<td style="text-align: right;">1e+05</td>
<td style="text-align: right;">0.00</td>
<td style="text-align: right;">0.87</td>
<td style="text-align: right;">-7.29</td>
<td style="text-align: right;">-0.47</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0.46</td>
<td style="text-align: right;">6.54</td>
<td style="text-align: right;">0</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>Now let’s look at the bias in the estimates.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<caption>Percent bias</caption>
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">Model</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Intercept</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Z</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">X</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">Unadjusted</td>
<td style="text-align: right;">0.149</td>
<td style="text-align: right;">14.494</td>
<td style="text-align: right;">-49.877</td>
</tr>
<tr class="even">
<td style="text-align: left;">BLUP_mixed</td>
<td style="text-align: right;">0.051</td>
<td style="text-align: right;">14.494</td>
<td style="text-align: right;">-1.828</td>
</tr>
<tr class="odd">
<td style="text-align: left;">BLUP_mixed_hetvar</td>
<td style="text-align: right;">0.053</td>
<td style="text-align: right;">14.647</td>
<td style="text-align: right;">-1.673</td>
</tr>
<tr class="even">
<td style="text-align: left;">Factor Score</td>
<td style="text-align: right;">0.063</td>
<td style="text-align: right;">16.502</td>
<td style="text-align: right;">11.968</td>
</tr>
<tr class="odd">
<td style="text-align: left;">CV Adj</td>
<td style="text-align: right;">-0.663</td>
<td style="text-align: right;">-2.368</td>
<td style="text-align: right;">7.992</td>
</tr>
<tr class="even">
<td style="text-align: left;">SEM</td>
<td style="text-align: right;">-0.017</td>
<td style="text-align: right;">-1.777</td>
<td style="text-align: right;">4.744</td>
</tr>
<tr class="odd">
<td style="text-align: left;">True</td>
<td style="text-align: right;">-0.567</td>
<td style="text-align: right;">-0.380</td>
<td style="text-align: right;">0.513</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>The results suggest a couple things. First, the results of CV were duplicated for the unadjusted setting, where the group level covariate has a slight bias upward, but the aggregate is severely downwardly biased<sup>3</sup>. We can also see that a two-step approach using BLUPs from a mixed model (with or without heterogeneous variances), or factor scores, either eliminate or notably reduce the bias for the aggregate score, but still have issue with the group level covariate. This is because of the correlation between the group level and lower level covariates, which if zero, would result in no bias, and has long been a known issue with mixed models. The factor scores had some very wild results at times, even after overcoming basic inadmissible results. In the end, we see that the calculated adjustment and SEM both essentially eliminate the bias by practical standards. It is worth noting that the bias for either the factor analysis or SEM would be completely eliminated if the model adds a regression of the latent variable onto the group level covariate <img src="https://latex.codecogs.com/png.latex?Z">.</p>
<p>Note that in practice, a two-step approach, such as using the mixed model BLUPs or factor scores, comes with the same issue of using an estimate rather than observed score that we have using the mean. Even if there is no bias, the estimated uncertainty would be optimistic as it doesn’t take into account the estimation process. This uncertainty decreases with the number of observations per group (or number of items from the factor analytic perspective), but would technically need to be dealt with, e.g.&nbsp;using ‘factor score regression’ <span class="citation" data-cites="devlieger2016hypothesis">Devlieger et al. (2016)</span> or more simply, just doing the SEM.</p>
</section>
<section id="reliability" class="level2">
<h2 class="anchored" data-anchor-id="reliability">Reliability</h2>
<p>Interestingly, if we look at the reliability of the measure, we shouldn’t be surprised at the results. Reliability may be thought of as the amount of variance in an observed score that is true score variance <span class="citation" data-cites="revelle2019reliability">Revelle and Condon (2019)</span>. Since the underlying construct is assumed unidimensional, we can examine something like coefficient <img src="https://latex.codecogs.com/png.latex?%5Calpha">, which gives a sense of how reliable the mean or total score would be. Doing so reveals a fairly poor measure for 10 observations per group under the CV settings. The mean coefficient <img src="https://latex.codecogs.com/png.latex?%5Calpha"> is 0.52, the max of which is 0.74, which, from a measurement model perspective, would be unacceptable<sup>4</sup>. This is all to say that we have rediscovered attenuation in correlation due to (lack of) reliability, something <a href="https://en.wikipedia.org/wiki/Correction_for_attenuation">addressed by Spearman over a century ago</a><sup>5</sup>.</p>
<p>In actual repeated measures, or with constructed scales, it’s probably unlikely we would have this poor of a measure. Indeed, if we think a mean is appropriate in the first place, we are probably assuming that the scores are something that can be meaningfully combined in the first place, because if a latent construct doesn’t actually explain the observations well, then what is the point of estimating it?</p>
<p>In our current context, we can create a more reliable measure by decreasing the variance value for <img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2_%5Cnu"> which is the residual variance for the observed items at the lower level. Decreasing it from 9 to 1, puts the observed scores in a notably better place (<img src="https://latex.codecogs.com/png.latex?%5Calpha"> = 0.91), and if we actually have a reliable measure (or even just increase the number of observations per group, as noted by CV), the results show hardly any bias for the group level effect and a near negligible one for the mean effect.</p>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<caption>Percent bias</caption>
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">Model</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Intercept</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">Z</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">X</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">Unadjusted</td>
<td style="text-align: right;">-0.011</td>
<td style="text-align: right;">2.698</td>
<td style="text-align: right;">-9.651</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>In the end we relearn a valuable, but very old lesson. The take home story here, at least to me, is to have a reliable measure and/or get more observations per group if you can, which would be the same advice for any clustered data situation. If you do have a reliable measure, such as a proportion of simple counts, or a known scale with good properties, using the mean should not give you too much pause. As a precaution, you might go ahead and use White’s correction as suggested by FJK. If you have enough data and the model isn’t overly complicated, consider doing the SEM.</p>
<p>last updated: 2025-01-02</p>



</section>


<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-croon2007predicting" class="csl-entry">
Croon, Marcel A, and Marc JPM van Veldhoven. 2007. <span>“Predicting Group-Level Outcome Variables from Variables Measured at the Individual Level: A Latent Variable Multilevel Model.”</span> <em>Psychological Methods</em> 12 (1): 45.
</div>
<div id="ref-devlieger2016hypothesis" class="csl-entry">
Devlieger, Ines, Axel Mayer, and Yves Rosseel. 2016. <span>“Hypothesis Testing Using Factor Score Regression: A Comparison of Four Methods.”</span> <em>Educational and Psychological Measurement</em> 76 (5): 741–70.
</div>
<div id="ref-foster2018predicting" class="csl-entry">
Foster-Johnson, Lynn, and Jeffrey D Kromrey. 2018. <span>“Predicting Group-Level Outcome Variables: An Empirical Comparison of Analysis Strategies.”</span> <em>Behavior Research Methods</em> 50 (6): 2461–79.
</div>
<div id="ref-revelle2019reliability" class="csl-entry">
Revelle, William, and David M Condon. 2019. <span>“Reliability from <img src="https://latex.codecogs.com/png.latex?%5Calpha"> to <img src="https://latex.codecogs.com/png.latex?%5Comega">: A Tutorial.”</span> <em>Psychological Assessment</em> 31 (12): 1395.
</div>
</div></section><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>I wasn’t sure in the mixed model whether to include the item and or group level Z as fixed effects. Results did not change much, so I went with a mixed model with no fixed effects to make them closer to the scale of the mean scores.↩︎</p></li>
<li id="fn2"><p>All code is contained within the <a href="https://github.com/m-clark/m-clark.github.io/blob/master/_posts/2020-08-31-micro-macro-mlm/micro-macro.Rmd">R markdown file</a> that produced this post.↩︎</p></li>
<li id="fn3"><p>For those who may not have access to the article, the values for percentage bias in CV were as follows: for the unadjusted model, the bias for the coefficients under these conditions was 0.6, 15.3, -50.4, and for the adjusted model, -1.1, -1.3, 5.0.↩︎</p></li>
<li id="fn4"><p>A typical cutoff for coefficient <img src="https://latex.codecogs.com/png.latex?%5Calpha"> for a good measure is .8. We can actually use a ‘G-theory’ approach and calculate this by hand <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B1%7D%7B1+9/10%7D">, where 1 is the variance CV fixed for the true score, and 9 is residual variance. <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B1%7D%7B1+9%7D"> is the <img src="https://latex.codecogs.com/png.latex?%5Crho_x">, i.e.&nbsp;intraclass correlation, that they have in Table 1. In the better scenario <img src="https://latex.codecogs.com/png.latex?%5Crho_x"> = <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B1%7D%7B1+4%7D"> = .2 and the reliability is <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B1%7D%7B1+4/10%7D"> = .71, which is notably better, though still substandard. Even then we can see from their table dramatic decreases in bias from that improvement in reliability.↩︎</p></li>
<li id="fn5"><p>The lack of reliability is likely the culprit behind the wider range in the estimated factor scores as well.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2020,
  author = {Clark, Michael},
  title = {Micro-Macro Models},
  date = {2020-08-31},
  url = {https://m-clark.github.io/posts/2020-08-31-micro-macro-mlm/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2020" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2020. <span>“Micro-Macro Models.”</span> August 31. <a href="https://m-clark.github.io/posts/2020-08-31-micro-macro-mlm/">https://m-clark.github.io/posts/2020-08-31-micro-macro-mlm/</a>.
</div></div></section></div> ]]></description>
  <category>mixed models</category>
  <category>latent variables</category>
  <category>regression</category>
  <guid>https://m-clark.github.io/posts/2020-08-31-micro-macro-mlm/</guid>
  <pubDate>Mon, 31 Aug 2020 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/micromacro/multilevel.png" medium="image" type="image/png" height="71" width="144"/>
</item>
<item>
  <title>Exploratory Data Analysis</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2020-07-10-eda/</link>
  <description><![CDATA[ 





<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>In R there are many tools available to help you dive in and explore your data. However, in consulting I still see a lot of people using base R’s <span class="func" style="">table</span> and <span class="func" style="">summary</span> functions, followed by a lot of work to get the result into a more presentable format. My own frustrations led to me creating a package (<a href="https://m-clark.github.io/tidyext/">tidyext</a>) for personal use in this area. While that suits me fine, there are tools that can go much further with little effort. Recently, Staniak &amp; Biecek wrote an article in the R Journal exploring several of such packages, so I thought I’d try them out for myself, and take others along with me for that ride.</p>
<p>As this will be a workshop/demo, I’ve created a separate repo and document to make it easier to find, so here is the link: <a href="https://m-clark.github.io/exploratory-data-analysis-tools/">https://m-clark.github.io/exploratory-data-analysis-tools/</a></p>
<p>The packages demoed are:</p>
<ul>
<li><span class="pack" style="">arsenal</span></li>
<li><span class="pack" style="">DataExplorer</span></li>
<li><span class="pack" style="">dataMaid</span></li>
<li><span class="pack" style="">gtsummary</span></li>
<li><span class="pack" style="">janitor</span> (not explored in the previous article)</li>
<li><span class="pack" style="">SmartEDA</span></li>
<li><span class="pack" style="">summarytools</span></li>
<li><span class="pack" style="">visdat</span></li>
</ul>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://m-clark.github.io/img/tukey.png" class="img-fluid figure-img"></p>
<figcaption>Tukey</figcaption>
</figure>
</div>


</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2020,
  author = {Clark, Michael},
  title = {Exploratory {Data} {Analysis}},
  date = {2020-07-10},
  url = {https://m-clark.github.io/posts/2020-07-10-eda/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2020" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2020. <span>“Exploratory Data Analysis.”</span> July 10.
<a href="https://m-clark.github.io/posts/2020-07-10-eda/">https://m-clark.github.io/posts/2020-07-10-eda/</a>.
</div></div></section></div> ]]></description>
  <category>miscellaneous</category>
  <guid>https://m-clark.github.io/posts/2020-07-10-eda/</guid>
  <pubDate>Fri, 10 Jul 2020 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/eda.png" medium="image" type="image/png" height="102" width="144"/>
</item>
<item>
  <title>Predictions with an offset</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2020-06-15-predict-with-offset/</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>NB: This post was revisited when updating the website early 2025, and some changes were required. Attempts to keep things consistent were made, but if you feel you’ve found an issue, please post it at <a href="http://github.com/m-clark/m-clark.github.io/issues">GitHub</a>. Also for this particular post, Stata is not something I’ve used in years nor have access to. So for those interested who do have access, I can only show you the code, since at the time, it wasn’t something I could save. But since I’m here, check out the fantastic <span class="pack">marginaleffects</span> package in R.</p>
</blockquote>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>Getting predictions in R is and always has been pretty easy for the vast majority of packages providing modeling functions, as they also provide a <span class="func" style="">predict</span> method for the model objects. For those in the Stata world, they typically use <code>margins</code> for this, but when they come to R, there is no obvious option for how to go about it in the same way<sup>1</sup>. Likewise, some in the R world catch a whiff of Stata’s margins and would want something similar, but may not be sure where to turn.</p>
<p>A little digging will reveal there are several packages that will provide the same sort of thing. In addition, there are numerous resources for both R and Stata for getting marginal results (i.e.&nbsp;predictions). However, here we note the issues that arise when models include an <em>offset</em>. Offsets are commonly used to model rates when the target variable is a count, but are used in other contexts as well. The Stata <a href="https://www.stata.com/manuals/rmargins.pdf">documentation for the margins command</a> offers no specific details of how the offset/exposure is treated, and some R packages appear not to know what to do with it, or offer few options to deal with it. So even when the models are identical, marginal estimates might be different in R and Stata. Here we’ll try to sort some of this out.</p>
</section>
<section id="get-some-data" class="level2">
<h2 class="anchored" data-anchor-id="get-some-data">Get some data</h2>
<p>We will use the <span class="objclass" style="">Insurance</span> data from the <span class="pack" style="">MASS</span> package which most with R will have access to. From the helpfile:</p>
<blockquote class="blockquote">
<p>The data given in data frame Insurance consist of the numbers of policyholders of an insurance company who were exposed to risk, and the numbers of car insurance claims made by those policyholders.</p>
</blockquote>
<ul>
<li><strong>District</strong>: district of residence of policyholder (1 to 4): 4 is major cities.</li>
<li><strong>Group</strong>: group of car with levels &lt;1 litre, 1–1.5 litre, 1.5–2 litre, &gt;2 litre</li>
<li><strong>Age</strong>: the age of the insured in 4 groups labelled &lt;25, 25–29, 30–35, &gt;35</li>
<li><strong>Holders</strong>: number of policyholders</li>
<li><strong>Claims</strong>: number of claims</li>
</ul>
<p>We do a bit of minor processing, and I save the data as a <a href="https://github.com/m-clark/m-clark.github.io/raw/master/data/insurance.dta">Stata file</a> in case anyone wants to play with it in that realm.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="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;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb1-4"></span>
<span id="cb1-5">insurance <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> MASS<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>Insurance <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb1-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rename_all</span>(tolower) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb1-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb1-8">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># create standard rather than ordered factors for typical output</span></span>
<span id="cb1-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age   =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(age, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ordered =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>),</span>
<span id="cb1-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">group =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(group, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ordered =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>),</span>
<span id="cb1-11">    </span>
<span id="cb1-12">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># create a numeric age covariate for later</span></span>
<span id="cb1-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age_num =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">case_when</span>(</span>
<span id="cb1-14">      age <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;">'&lt;25'</span>   <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">18</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>(), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> T),</span>
<span id="cb1-15">      age <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;">'25-29'</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">29</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>(), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> T),</span>
<span id="cb1-16">      age <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;">'30-35'</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</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;">35</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>(), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> T),</span>
<span id="cb1-17">      age <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;">'&gt;35'</span>   <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">36</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;">75</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">n</span>(), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> T),</span>
<span id="cb1-18">    ),</span>
<span id="cb1-19">    </span>
<span id="cb1-20">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># for stata consistency</span></span>
<span id="cb1-21">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ln_holders =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(holders)</span>
<span id="cb1-22">  )</span>
<span id="cb1-23"></span>
<span id="cb1-24"></span>
<span id="cb1-25">haven<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">write_dta</span>(insurance, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'data/insurance.dta'</span>)</span></code></pre></div></div>
</div>
<p>Let’s take a quick peek to get our bearings.</p>
<div class="cell">
<div class="cell-output cell-output-stdout">
<pre><code>$`Numeric Variables`
# A tibble: 4 × 10
  Variable       N  Mean     SD   Min    Q1 Median     Q3     Max `% Missing`
  &lt;chr&gt;      &lt;dbl&gt; &lt;dbl&gt;  &lt;dbl&gt; &lt;dbl&gt; &lt;dbl&gt;  &lt;dbl&gt;  &lt;dbl&gt;   &lt;dbl&gt;       &lt;dbl&gt;
1 holders       64 365.  623.     3   46.8  136    328.   3582              0
2 claims        64  49.2  71.2    0    9.5   22     55.5   400              0
3 age_num       64  35.2  15.8   18   25     29.5   35.5    75              0
4 ln_holders    64   4.9   1.48   1.1  3.84   4.91   5.79    8.18           0

$`Categorical Variables`
# A tibble: 12 × 4
   Variable Group  Frequency   `%`
   &lt;chr&gt;    &lt;fct&gt;      &lt;int&gt; &lt;dbl&gt;
 1 district 1             16    25
 2 district 2             16    25
 3 district 3             16    25
 4 district 4             16    25
 5 group    &lt;1l           16    25
 6 group    &gt;2l           16    25
 7 group    1-1.5l        16    25
 8 group    1.5-2l        16    25
 9 age      &lt;25           16    25
10 age      &gt;35           16    25
11 age      25-29         16    25
12 age      30-35         16    25</code></pre>
</div>
</div>
</section>
<section id="model" class="level2">
<h2 class="anchored" data-anchor-id="model">Model</h2>
<p>Starting out, we run a model in as simple a form as possible. I use just a standard negative binomial with a single covariate <code>age</code>, so we can clearly see how the ouptut is being produced. Note that <code>age</code> has four categories as seen above.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1">nb_glm_offset <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> MASS<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glm.nb</span>(claims <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>  age <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">offset</span>(ln_holders), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> insurance)</span>
<span id="cb3-2"></span>
<span id="cb3-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summary</span>(nb_glm_offset)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
Call:
MASS::glm.nb(formula = claims ~ age + offset(ln_holders), data = insurance, 
    init.theta = 28.40119393, link = log)

Coefficients:
            Estimate Std. Error z value Pr(&gt;|z|)    
(Intercept) -1.59233    0.09071 -17.554  &lt; 2e-16 ***
age25-29    -0.12697    0.11743  -1.081   0.2796    
age30-35    -0.25340    0.11558  -2.193   0.0283 *  
age&gt;35      -0.41940    0.10583  -3.963  7.4e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for Negative Binomial(28.4012) family taken to be 1)

    Null deviance: 86.761  on 63  degrees of freedom
Residual deviance: 67.602  on 60  degrees of freedom
AIC: 444.38

Number of Fisher Scoring iterations: 1

              Theta:  28.40 
          Std. Err.:  9.80 

 2 x log-likelihood:  -434.385 </code></pre>
</div>
</div>
<p>Now we run it with Stata. We get the same result, so this means we can’t get different predictions if we do the same thing in both R or Stata<sup>2</sup>.</p>
<div class="cell" data-consolelog="false">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode stata code-with-copy"><code class="sourceCode stata"><span id="cb5-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">nbreg</span> claims i.age, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">offset</span>(ln_holders) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">nolog</span></span></code></pre></div></div>
</div>
</section>
<section id="emmeans" class="level2">
<h2 class="anchored" data-anchor-id="emmeans">emmeans</h2>
<p>First let’s use <span class="pack" style="">emmeans</span>, a very popular package for getting <em>estimated marginal means</em>, to get the predicted counts for each age group.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(emmeans)</span>
<span id="cb6-2"></span>
<span id="cb6-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">emmeans</span>(</span>
<span id="cb6-4">  nb_glm_offset,</span>
<span id="cb6-5">  <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> age,</span>
<span id="cb6-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"response"</span>,</span>
<span id="cb6-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">offset =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(insurance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>ln_holders)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  default</span></span>
<span id="cb6-8">)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">age</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">response</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">SE</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">df</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">asymp.LCL</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">asymp.UCL</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">&lt;25</td>
<td style="text-align: right;">27.437</td>
<td style="text-align: right;">2.489</td>
<td style="text-align: right;">Inf</td>
<td style="text-align: right;">22.968</td>
<td style="text-align: right;">32.776</td>
</tr>
<tr class="even">
<td style="text-align: left;">25-29</td>
<td style="text-align: right;">24.166</td>
<td style="text-align: right;">1.802</td>
<td style="text-align: right;">Inf</td>
<td style="text-align: right;">20.880</td>
<td style="text-align: right;">27.969</td>
</tr>
<tr class="odd">
<td style="text-align: left;">30-35</td>
<td style="text-align: right;">21.295</td>
<td style="text-align: right;">1.525</td>
<td style="text-align: right;">Inf</td>
<td style="text-align: right;">18.507</td>
<td style="text-align: right;">24.505</td>
</tr>
<tr class="even">
<td style="text-align: left;">&gt;35</td>
<td style="text-align: right;">18.038</td>
<td style="text-align: right;">0.983</td>
<td style="text-align: right;">Inf</td>
<td style="text-align: right;">16.211</td>
<td style="text-align: right;">20.072</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>How is this result obtained? It is just the prediction at each value of the covariate, with the offset held at its mean. We can duplicate this result by using the <span class="func" style="">predict</span> method and specifying a data frame with the values of interest.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1">nd <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb7-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">levels</span>(insurance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>age),</span>
<span id="cb7-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ln_holders =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(insurance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>ln_holders)</span>
<span id="cb7-4">)</span>
<span id="cb7-5"></span>
<span id="cb7-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(</span>
<span id="cb7-7">  nb_glm_offset,</span>
<span id="cb7-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> nd,</span>
<span id="cb7-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'response'</span></span>
<span id="cb7-10">)</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: right;" data-quarto-table-cell-role="th">prediction</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">27.437</td>
</tr>
<tr class="even">
<td style="text-align: right;">24.166</td>
</tr>
<tr class="odd">
<td style="text-align: right;">21.295</td>
</tr>
<tr class="even">
<td style="text-align: right;">18.038</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>As an explicit comparison, the intercept represents group ‘&lt;25’, and if we exponentiate and add the mean offset we get:</p>
<p><img src="https://latex.codecogs.com/png.latex?exp(Intercept%20+%20%5Coverline%7Bln%5C_holders%7D)%20=%20e%5E%7B-1.59+4.90%7D%20=%20%5Cqquad"> 27.437</p>
</section>
<section id="stata-basic-margins" class="level2">
<h2 class="anchored" data-anchor-id="stata-basic-margins">Stata: basic margins</h2>
<p>Now let’s look at Stata. First we want just the basic margins output.</p>
<div class="cell" data-consolelog="false">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode stata code-with-copy"><code class="sourceCode stata"><span id="cb8-1">margins age </span></code></pre></div></div>
</div>
<p>These values, while consistent in pattern, are much different than the <span class="pack" style="">emmeans</span> output, so what is going on?</p>
<section id="r-by-hand" class="level3">
<h3 class="anchored" data-anchor-id="r-by-hand">R by hand</h3>
<p>In this model, we only have the <code>age</code> covariate and the offset, so there really isn’t much to focus on besides the latter. To replicate the Stata output in R, we will use <em>all</em> values of the offset for <em>every</em> level of <code>age</code>, and subsequently get an average prediction for each age group. First, we create a data frame for prediction using <span class="func" style="">expand.grid</span>, get the predictions for all those values, then get mean prediction per group.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1">predictions <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> </span>
<span id="cb9-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">expand.grid</span>(</span>
<span id="cb9-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age        =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">levels</span>(insurance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>age), </span>
<span id="cb9-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ln_holders =</span> insurance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>ln_holders</span>
<span id="cb9-5">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb9-6">  <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;">prediction =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(nb_glm_offset, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> ., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'response'</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb9-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(age) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb9-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">avg_prediction =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(prediction)) </span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">age</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">avg_prediction</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">&lt;25</td>
<td style="text-align: right;">74.257</td>
</tr>
<tr class="even">
<td style="text-align: left;">25-29</td>
<td style="text-align: right;">65.403</td>
</tr>
<tr class="odd">
<td style="text-align: left;">30-35</td>
<td style="text-align: right;">57.635</td>
</tr>
<tr class="even">
<td style="text-align: left;">&gt;35</td>
<td style="text-align: right;">48.820</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<section id="emmeans-1" class="level3">
<h3 class="anchored" data-anchor-id="emmeans-1">emmeans</h3>
<p>The <span class="pack" style="">emmeans</span> doesn’t appear to allow one to provide all values of the offset, as adding additional values just applies them to each group and then recycles. In this case, it would just use the first four values of <code>ln_holders</code> for each age group respectively, which is not what we want.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">emmeans</span>(</span>
<span id="cb10-2">  nb_glm_offset,</span>
<span id="cb10-3">  <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> age,</span>
<span id="cb10-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"response"</span>,</span>
<span id="cb10-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">offset =</span> insurance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>ln_holders</span>
<span id="cb10-6">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> age   response    SE  df asymp.LCL asymp.UCL
 &lt;25       40.1  3.64 Inf      33.6      47.9
 25-29     47.3  3.53 Inf      40.9      54.8
 30-35     38.8  2.78 Inf      33.8      44.7
 &gt;35      224.7 12.25 Inf     201.9     250.0

Confidence level used: 0.95 
Intervals are back-transformed from the log scale </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">insurance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>ln_holders[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>]</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 5.283204 5.575949 5.505332 7.426549</code></pre>
</div>
</div>
<p>If we add the offset to the <code>spec</code> argument, it still just fixes it at the mean (and I tried variations on the spec). So at least using the standard approaches with this model does not appear to give you the same thing as Stata.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">emmeans</span>(</span>
<span id="cb14-2">  nb_glm_offset,</span>
<span id="cb14-3">  <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> age <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">offset</span>(ln_holders),</span>
<span id="cb14-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"response"</span></span>
<span id="cb14-5">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> age   ln_holders response    SE  df asymp.LCL asymp.UCL
 &lt;25          4.9     27.4 2.489 Inf      23.0      32.8
 25-29        4.9     24.2 1.802 Inf      20.9      28.0
 30-35        4.9     21.3 1.525 Inf      18.5      24.5
 &gt;35          4.9     18.0 0.983 Inf      16.2      20.1

Confidence level used: 0.95 
Intervals are back-transformed from the log scale </code></pre>
</div>
</div>
<p>Unfortunately Stata has the opposite issue. Trying to set the offset to the mean results in an error, and using <code>atmeans</code> doesn’t change the previous result.</p>
<div class="cell" data-consolelog="false">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode stata code-with-copy"><code class="sourceCode stata"><span id="cb16-1">margins age, atmeans</span>
<span id="cb16-2">margins age, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">at</span>(ln_holders = 10.27)</span></code></pre></div></div>
</div>
</section>
<section id="margins" class="level3">
<h3 class="anchored" data-anchor-id="margins">margins</h3>
<p>The <span class="pack" style="">margins</span> package explicitly attempts to duplicate Stata’s margins command, but here we can see it has an issue with the offset.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb17-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(margins)</span>
<span id="cb17-2"></span>
<span id="cb17-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margins</span>(</span>
<span id="cb17-4">  nb_glm_offset,</span>
<span id="cb17-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">variables =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'age'</span>,</span>
<span id="cb17-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"response"</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># default</span></span>
<span id="cb17-7">)</span></code></pre></div></div>
<div class="cell-output cell-output-error">
<pre><code>Error in offset(ln_holders): could not find function "offset"</code></pre>
</div>
</div>
<p>The offset function is part of the stats package of the base R installation, so I tried rerunning the model using <code>stats::offset</code>, but this makes the offset just like any other covariate, i.e.&nbsp;it did not have a fixed coefficient of 1. Changing the model to a standard <code>glm</code> class with poisson and moving the offset to the <code>offset</code> argument did work, and produces the results for the differences in predictions for each group from the reference group (<code>dydx</code> in Stata), but we’ll visit this type of result later<sup>3</sup>. However, the <code>offset</code> argument is not available to <span class="func" style="">glm.nb</span>, so we’re stuck for now.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">pois_glm_offset <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glm</span>(</span>
<span id="cb19-2">  claims <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>  age,</span>
<span id="cb19-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data   =</span> insurance,</span>
<span id="cb19-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">family =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'poisson'</span>,</span>
<span id="cb19-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">offset =</span> ln_holders</span>
<span id="cb19-6">)</span>
<span id="cb19-7"></span>
<span id="cb19-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margins</span>(</span>
<span id="cb19-9">  pois_glm_offset,</span>
<span id="cb19-10">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">variables =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'age'</span>,</span>
<span id="cb19-11">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"response"</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># default</span></span>
<span id="cb19-12">)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> age25-29 age30-35 age&gt;35
   -10.32   -18.46 -28.79</code></pre>
</div>
<div class="code-copy-outer-scaffold"><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;">expand.grid</span>(</span>
<span id="cb21-2">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age        =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">levels</span>(insurance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>age), </span>
<span id="cb21-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ln_holders =</span> insurance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>ln_holders</span>
<span id="cb21-4">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb21-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prediction =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(pois_glm_offset, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> ., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'response'</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb21-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(age) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb21-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">avg_prediction =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(prediction)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb21-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">diff =</span> avg_prediction <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> avg_prediction[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]) </span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 4 × 3
  age   avg_prediction  diff
  &lt;fct&gt;          &lt;dbl&gt; &lt;dbl&gt;
1 &lt;25             73.4   0  
2 25-29           63.1 -10.3
3 30-35           55.0 -18.5
4 &gt;35             44.7 -28.8</code></pre>
</div>
</div>
</section>
</section>
<section id="stata-over" class="level2">
<h2 class="anchored" data-anchor-id="stata-over">Stata: over</h2>
<p>In Stata, with categorical values we can also use the <code>over</code> approach. What do we get in this case?</p>
<div class="cell" data-collectcode="true" data-cleanlog="true">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode stata code-with-copy"><code class="sourceCode stata"><span id="cb23-1">margins, <span class="bn" style="color: #AD0000;
background-color: null;
font-style: inherit;">over</span>(age)</span></code></pre></div></div>
</div>
<p>These are very different from our previous results for Stata, so what’s happening here?</p>
<section id="r-by-hand-1" class="level3">
<h3 class="anchored" data-anchor-id="r-by-hand-1">R by hand</h3>
<p>This can be duplicated with the <span class="func" style="">predict</span> function as follows. While similar to the previous approach, here <em>only the observed values of the offset for each group are used</em>. We then make predictions for all values of the data and average them by group.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">predictions_over <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> insurance <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb24-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(age) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb24-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_modify</span>(</span>
<span id="cb24-4">    <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb24-5">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prediction =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(</span>
<span id="cb24-6">          <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(nb_glm_offset, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> ., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'response'</span>)</span>
<span id="cb24-7">        )</span>
<span id="cb24-8">      ),</span>
<span id="cb24-9">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">keep =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb24-10">  ) </span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">age</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">prediction</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">&lt;25</td>
<td style="text-align: right;">14.471</td>
</tr>
<tr class="even">
<td style="text-align: left;">25-29</td>
<td style="text-align: right;">26.162</td>
</tr>
<tr class="odd">
<td style="text-align: left;">30-35</td>
<td style="text-align: right;">29.677</td>
</tr>
<tr class="even">
<td style="text-align: left;">&gt;35</td>
<td style="text-align: right;">141.098</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>The pattern is actually in the opposite direction, which is unexpected, but probably just reflects the fact that we just don’t have much data. However, it’s good to note that these respective approaches would not necessarily tell you the same thing.</p>
</section>
<section id="emmeans-2" class="level3">
<h3 class="anchored" data-anchor-id="emmeans-2">emmeans</h3>
<p>I currently don’t know of an equivalence for <span class="pack" style="">emmeans</span> in this offset case, and initial searches didn’t turn up much, though it is hard to distinguish specific ‘average predictions’ from many other similar scenarios. I attempted the following, which keeps the values of <code>ln_holders</code>, but it only keeps unique ones, and it’s not reproducing what I would expect, although it implies that it is averaging over the offset values.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">rg <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ref_grid</span>(nb_glm_offset, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cov.keep =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ln_holders'</span>))</span>
<span id="cb25-2"></span>
<span id="cb25-3">em_over <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">emmeans</span>(rg, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>age, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'response'</span>)  </span>
<span id="cb25-4"></span>
<span id="cb25-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(em_over)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>    age  response        SE  df asymp.LCL  asymp.UCL
1   &lt;25  7.814354 0.7088454 Inf   6.54154   9.334825
2 25-29 17.042911 1.2709131 Inf  14.72545  19.725092
3 30-35 20.304984 1.4542076 Inf  17.64579  23.364916
4   &gt;35 96.993166 5.2865742 Inf  87.16592 107.928350</code></pre>
</div>
</div>
</section>
<section id="margins-1" class="level3">
<h3 class="anchored" data-anchor-id="margins-1">margins</h3>
<p>The over approach for the <span class="pack" style="">margins</span> package is not explicitly supported. The package author states:</p>
<blockquote class="blockquote">
<p>At present, margins() does not implement the over option. The reason for this is also simple: R already makes data subsetting operations quite simple using simple <code>[</code> extraction. If, for example, one wanted to calculate marginal effects on subsets of a data frame, those subsets can be passed directly to margins() via the data argument (as in a call to prediction()).</p>
</blockquote>
<p>It would look something like the following, but we still have the offset problem for this negative binomial class, so I don’t show a result.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb27-1">insurance <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb27-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(age) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb27-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_map</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">margins</span>(nb_glm_offset, .), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">keep =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>) </span></code></pre></div></div>
</div>
</section>
</section>
<section id="stata-dydx" class="level2">
<h2 class="anchored" data-anchor-id="stata-dydx">Stata: dydx</h2>
<section id="categorical-covariate" class="level3">
<h3 class="anchored" data-anchor-id="categorical-covariate">Categorical Covariate</h3>
<p>Sometimes people want differences as you move from one level (e.g.&nbsp;the reference level) to the next for some covariate, the ‘average marginal effect’. In Stata this is obtained with the <code>dydx</code> option.</p>
<div class="cell" data-collectcode="true" data-cleanlog="true">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb28" style="background: #f1f3f5;"><pre class="sourceCode stata code-with-copy"><code class="sourceCode stata"><span id="cb28-1">margins, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">dydx</span>(age)</span></code></pre></div></div>
</div>
<p>In R, we can get this from our initial predictions that used all offset values by just taking the differences in the predicted values.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb29" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb29-1">predictions <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb29-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;">dydx =</span> avg_prediction <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> avg_prediction[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">age</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">avg_prediction</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">dydx</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">&lt;25</td>
<td style="text-align: right;">74.257</td>
<td style="text-align: right;">0.000</td>
</tr>
<tr class="even">
<td style="text-align: left;">25-29</td>
<td style="text-align: right;">65.403</td>
<td style="text-align: right;">-8.854</td>
</tr>
<tr class="odd">
<td style="text-align: left;">30-35</td>
<td style="text-align: right;">57.635</td>
<td style="text-align: right;">-16.622</td>
</tr>
<tr class="even">
<td style="text-align: left;">&gt;35</td>
<td style="text-align: right;">48.820</td>
<td style="text-align: right;">-25.437</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<section id="continuous-predictor" class="level3">
<h3 class="anchored" data-anchor-id="continuous-predictor">Continuous predictor</h3>
<p>Now we’ll consider a continuous covariate. Here we’ll again just focus on a simple example where we rerun the model, but with age as numeric rather than binned<sup>4</sup>. For comparison we’ll set the numeric age values at roughly the midpoint of the binned categories. We can do this using the <code>at</code> option.</p>
<div class="cell" data-collectcode="true" data-cleanlog="true">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb30" style="background: #f1f3f5;"><pre class="sourceCode stata code-with-copy"><code class="sourceCode stata"><span id="cb30-1">margins, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">at</span>(age_num = (21, 27, 32, 50))</span></code></pre></div></div>
</div>
<p>Again, we can duplicate this with the basic <span class="func" style="">predict</span> function. We just predict at that value of the covariate for all values of the offset, and get the average prediction as we did before.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb31" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb31-1">nb_glm_offset_cont <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> MASS<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glm.nb</span>(claims <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>  age_num <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">offset</span>(ln_holders), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> insurance)</span>
<span id="cb31-2"></span>
<span id="cb31-3">predictions <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">expand.grid</span>(</span>
<span id="cb31-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age_num =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">21</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">27</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">32</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>),</span>
<span id="cb31-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ln_holders =</span> insurance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>ln_holders</span>
<span id="cb31-6">) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb31-7">  <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;">pred =</span> </span>
<span id="cb31-8">           <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(</span>
<span id="cb31-9">             nb_glm_offset_cont,</span>
<span id="cb31-10">             <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> .,</span>
<span id="cb31-11">             <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'response'</span></span>
<span id="cb31-12">           )</span>
<span id="cb31-13">  ) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb31-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(age_num) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb31-15">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">average_prediction =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(pred))</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: right;" data-quarto-table-cell-role="th">age_num</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">average_prediction</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">21</td>
<td style="text-align: right;">67.500</td>
</tr>
<tr class="even">
<td style="text-align: right;">27</td>
<td style="text-align: right;">64.366</td>
</tr>
<tr class="odd">
<td style="text-align: right;">32</td>
<td style="text-align: right;">61.865</td>
</tr>
<tr class="even">
<td style="text-align: right;">50</td>
<td style="text-align: right;">53.639</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>We can also get the <code>dydx</code> for the continuous covariate, which is the derivative of the target with respect to the covariate. In linear models, this is just the regression coefficient, but here we have to do things a little differently.</p>
<div class="cell" data-collectcode="true" data-cleanlog="true">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb32" style="background: #f1f3f5;"><pre class="sourceCode stata code-with-copy"><code class="sourceCode stata"><span id="cb32-1">margins, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">dydx</span>(age_num)</span></code></pre></div></div>
</div>
<p>As noted for the categorical case, this value is the <em>average marginal effect</em>. As the Stata reference describes:</p>
<blockquote class="blockquote">
<p>It is not necessarily true that dydx() = 0.5 means that “y increases by 0.5 if x increases by 1”. It is true that “y increases with x at a rate such that, if the rate were constant, y would increase by 0.5 if x increased by 1”</p>
</blockquote>
<p>This qualified interpretation may not be of much value in contexts where the rate is not constant, but we can still see what Stata is doing.</p>
</section>
<section id="r-by-hand-2" class="level3">
<h3 class="anchored" data-anchor-id="r-by-hand-2">R by hand</h3>
<p>For <code>dydx</code>, when it comes to continuous covariates, there isn’t an obvious change in the covariate to use (i.e.&nbsp;the <code>dx</code>) to evaluate at each point, as is the case with categorical variables, which can use a reference group. So what we do is use a small arbitrary difference (<img src="https://latex.codecogs.com/png.latex?%5Cepsilon">) for the covariate at its observed values, get the predictions for the values above and below the observed value, and then average those differences in predicted values. For comparison to Stata, I set <img src="https://latex.codecogs.com/png.latex?%5Cepsilon"> to the value used by the <code>margins</code> command. Note that we are only using the observed values for the offset.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb33" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb33-1">h <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">epsilon =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-5</span>) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">max</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abs</span>(x), <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="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sqrt</span>(epsilon)</span>
<span id="cb33-2"></span>
<span id="cb33-3">age_dx_plus <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> insurance <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb33-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(age_num, ln_holders) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb33-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age_num =</span> age_num <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h</span>(age_num))</span>
<span id="cb33-6"></span>
<span id="cb33-7">age_dx_minus <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> insurance <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb33-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(age_num, ln_holders) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb33-9">  <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;">age_num =</span> age_num <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">h</span>(age_num))</span>
<span id="cb33-10"></span>
<span id="cb33-11">predictions_dydx <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> </span>
<span id="cb33-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(</span>
<span id="cb33-13">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dy =</span> </span>
<span id="cb33-14">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(nb_glm_offset_cont, age_dx_plus,  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'response'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span></span>
<span id="cb33-15">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(nb_glm_offset_cont, age_dx_minus, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'response'</span>), </span>
<span id="cb33-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dx   =</span> age_dx_plus<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>age_num <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> age_dx_minus<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>age_num,</span>
<span id="cb33-17">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dydx =</span> dy<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>dx</span>
<span id="cb33-18">  )</span>
<span id="cb33-19"></span>
<span id="cb33-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># summarise(predictions_dydx, ame = mean(dydx))</span></span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: right;" data-quarto-table-cell-role="th">ame</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">-0.42552</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>So we just get predictions for a small difference in age for each value of age, and average that difference in predictions.</p>
</section>
<section id="emmeans-3" class="level3">
<h3 class="anchored" data-anchor-id="emmeans-3">emmeans</h3>
<p>The emmeans package is primarily geared toward factor variables, but does have support for numeric variables interacting with factors. However, this isn’t what we’re really looking for here.</p>
</section>
<section id="margins-2" class="level3">
<h3 class="anchored" data-anchor-id="margins-2">margins</h3>
<p>We can however use the <span class="pack" style="">margins</span> package for this, and it provides the same result as before. For whatever reason, it doesn’t have an issue with the offset if we use the lower level <span class="func" style="">dydx</span> function.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">dydx</span>(</span>
<span id="cb34-2">  insurance,</span>
<span id="cb34-3">  nb_glm_offset_cont,</span>
<span id="cb34-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">variable =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'age_num'</span>,</span>
<span id="cb34-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">eps =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-5</span></span>
<span id="cb34-6">) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span></span>
<span id="cb34-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ame =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(dydx_age_num))</span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: right;" data-quarto-table-cell-role="th">ame</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">-0.42552</td>
</tr>
</tbody>
</table>
</div>
</div>
<p>For more on the <code>dydx</code> case for continuous variables in general, see the resources.</p>
</section>
</section>
<section id="other-complications" class="level2">
<h2 class="anchored" data-anchor-id="other-complications">Other complications</h2>
<p>Obviously models will have more than one covariate, and in the particular case that was brought to my attention, there were also random effects. I may explore more in the future, but the general result should hold in those circumstances. As a quick example<sup>5</sup>, we can get the same age results for both, by getting the age group predictions with all values of the dataset (not just the offset).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb35" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb35-1">nb_glm_offset_full <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> MASS<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glm.nb</span>(</span>
<span id="cb35-2">  claims <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>  age <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> group <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> district <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">offset</span>(ln_holders), </span>
<span id="cb35-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> insurance</span>
<span id="cb35-4">)</span>
<span id="cb35-5"></span>
<span id="cb35-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summary</span>(nb_glm_offset_full)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
Call:
MASS::glm.nb(formula = claims ~ age + group + district + offset(ln_holders), 
    data = insurance, init.theta = 449932.7775, link = log)

Coefficients:
            Estimate Std. Error z value Pr(&gt;|z|)    
(Intercept) -1.82174    0.07679 -23.723  &lt; 2e-16 ***
age25-29    -0.19101    0.08286  -2.305 0.021155 *  
age30-35    -0.34495    0.08138  -4.239 2.25e-05 ***
age&gt;35      -0.53667    0.06996  -7.671 1.70e-14 ***
group1-1.5l  0.16133    0.05054   3.192 0.001412 ** 
group1.5-2l  0.39281    0.05500   7.142 9.23e-13 ***
group&gt;2l     0.56341    0.07232   7.791 6.67e-15 ***
district2    0.02587    0.04302   0.601 0.547637    
district3    0.03853    0.05052   0.763 0.445686    
district4    0.23421    0.06168   3.797 0.000146 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for Negative Binomial(449932.8) family taken to be 1)

    Null deviance: 236.212  on 63  degrees of freedom
Residual deviance:  51.416  on 54  degrees of freedom
AIC: 390.74

Number of Fisher Scoring iterations: 1

              Theta:  449933 
          Std. Err.:  4185437 
Warning while fitting theta: iteration limit reached 

 2 x log-likelihood:  -368.745 </code></pre>
</div>
</div>
<div class="cell" data-consolelog="false">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb37" style="background: #f1f3f5;"><pre class="sourceCode stata code-with-copy"><code class="sourceCode stata"><span id="cb37-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">nbreg</span> claims i.age i.<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group</span> i.district, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">offset</span>(ln_holders) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">nolog</span></span>
<span id="cb37-2">margins age</span></code></pre></div></div>
</div>
<p>To do this with predict, we make predictions for all observed values as if they were at each level of age. Then we average them for each age group, just like we did before.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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">predictions_full_model <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span>  </span>
<span id="cb38-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map_df</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(i) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(insurance, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">levels</span>(age)[i])) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb38-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mutate</span>(</span>
<span id="cb38-4">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(age, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">levels</span>(insurance<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>age)),   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># convert back to factor</span></span>
<span id="cb38-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prediction =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(nb_glm_offset_full, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> ., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'response'</span>)</span>
<span id="cb38-6">  )  <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb38-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group_by</span>(age) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb38-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">avg_prediction =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(prediction)) </span></code></pre></div></div>
</div>
<div class="cell">
<div class="cell-output-display">
<table class="table caption-top table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;" data-quarto-table-cell-role="th">age</th>
<th style="text-align: right;" data-quarto-table-cell-role="th">avg_prediction</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">&lt;25</td>
<td style="text-align: right;">76.397</td>
</tr>
<tr class="even">
<td style="text-align: left;">25-29</td>
<td style="text-align: right;">63.113</td>
</tr>
<tr class="odd">
<td style="text-align: left;">30-35</td>
<td style="text-align: right;">54.109</td>
</tr>
<tr class="even">
<td style="text-align: left;">&gt;35</td>
<td style="text-align: right;">44.669</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<section id="r-packages" class="level2">
<h2 class="anchored" data-anchor-id="r-packages">R Packages</h2>
<p>To summarize R’s capabilities with Stata-like margins with models using an offset, we have a few options we can note. First, we can get the values using the <span class="func" style="">predict</span> method. Then there are the packages to help with getting these types of predictions. <span class="pack" style="">margins</span> explicitly attempts to replicate Stata-like margins for standard and some more complex models, but there doesn’t appear to be documentation on how the offset is dealt with by default. Furthermore, care must be taken if it isn’t an explicitly supported model. As we have also seen, <span class="pack" style="">emmeans</span> provides many predictions of the sort discussed here, supports many more models, produces results in a nice format, and has plotting capabilities. However, it’s mostly suited toward factor variables.</p>
<p>Beyond those, <span class="pack" style="">ggeffects</span> uses <span class="func" style="">predict</span> and <span class="pack" style="">emmeans</span> under the hood, so offers a nice way to do the same sorts of things, but with a more viable plot as a result. Other packages and functions are available for specific settings. For example, <span class="func" style="">conditional_effects</span> in the <span class="pack" style="">brms</span> package provides predictions and visualization for the bayesian setting.</p>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>Hopefully this will clarify the discrepancies between R and Stata with models using an offset. Honestly, I pretty much always use the <span class="func" style="">predict</span> function with my specified data values because I know what it’s doing and I can understand the results without hesitation regardless of model or package used. Furthermore, if one knows their data at all, it should be possible to specify covariate values that are meaningful pretty easily. On the other hand, getting predictions at averages can cause conceptual issues with categorical variables in many settings, and getting <em>average</em> effects often also can be hard to interpret (e.g.&nbsp;nonlinear relationships).</p>
<p>One thing you don’t get with some of the averaged predictions using the <span class="func" style="">predict</span> function are interval estimates, but this could be obtained via bootstrapping. Otherwise, most predict methods provide the standard error for a prediction with an additional argument (e.g.&nbsp;<code>se.fit = TRUE</code>), so if you getting predictions at key values of the variables it is trivial to get the interval estimate. In general, most R packages are just using predict under the hood, so being familiar with it will likely get you what you need on its own.</p>
</section>
<section id="resources" class="level2">
<h2 class="anchored" data-anchor-id="resources">Resources</h2>
<section id="reference" class="level3">
<h3 class="anchored" data-anchor-id="reference">Reference</h3>
<p><a href="https://www.stata.com/manuals/rmargins.pdf">Stata reference for margins</a></p>
<p><a href="https://cran.r-project.org/web/packages/emmeans/index.html">emmeans</a></p>
<p><a href="https://cloud.r-project.org/web/packages/margins/vignettes/Introduction.html">margins</a></p>
<p><a href="https://strengejacke.github.io/ggeffects">ggeffects</a></p>
</section>
<section id="notes" class="level3">
<h3 class="anchored" data-anchor-id="notes">Notes</h3>
<p><a href="https://www3.nd.edu/~rwilliam/stats3/Margins01.pdf">Marginal Effects- Rich Williams notes- 1</a></p>
<p><a href="https://www3.nd.edu/~rwilliam/stats3/Margins02.pdf">Marginal Effects- Rich Williams notes- 2</a></p>
<p><a href="https://www3.nd.edu/~rwilliam/stats3/Margins03.pdf">Marginal Effects- Rich Williams notes- 3</a></p>
<p><a href="https://www.stata-journal.com/article.html?article=st0260">Marginal Effects Stata Article by Rich Williams</a></p>
<p><a href="https://errickson.net/marginsnotes/">Josh Errickson’s comparisons of Stata, emmeans, and ggeffects</a></p>
<p><a href="https://stats.idre.ucla.edu/stata/faq/">UCLA IDRE FAQ (Margins command section)</a></p>
<p><a href="https://www.stata.com/support/faqs/statistics/marginal-effects-after-offset/">Stata FAQ (based on old mfx command)</a></p>
</section>
</section>
<section id="appendix" class="level2">
<h2 class="anchored" data-anchor-id="appendix">Appendix</h2>
<p>Just for giggles, I did an average marginal effect for a GAM, though I find little utility in it for the relationship shown. Confirmed via <span class="pack" style="">gratia</span> and <span class="pack" style="">margins</span>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb39" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb39-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(mgcv)</span>
<span id="cb39-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb39-3">dat <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;">gamSim</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dist =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"normal"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Gu &amp; Wahba 4 term additive model</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb41" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb41-1">b <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;">gam</span>(y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">s</span>(x2), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> dat)</span>
<span id="cb41-2"></span>
<span id="cb41-3">visibly<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_gam</span>(b)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2020-06-15-predict-with-offset/index_files/figure-html/margins-gam-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><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="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># set change step</span></span>
<span id="cb42-2">h <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-5</span></span>
<span id="cb42-3"></span>
<span id="cb42-4">b_dx_plus <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> dat <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb42-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(x2) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb42-6">  <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;">x2 =</span> x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> h)</span>
<span id="cb42-7"></span>
<span id="cb42-8">b_dx_minus <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> dat <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb42-9">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span>(x2) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%&gt;%</span> </span>
<span id="cb42-10">  <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;">x2 =</span> x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> h)</span>
<span id="cb42-11"></span>
<span id="cb42-12">predictions_dydx <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> </span>
<span id="cb42-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tibble</span>(</span>
<span id="cb42-14">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x2 =</span> dat<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x2,</span>
<span id="cb42-15">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dy =</span> </span>
<span id="cb42-16">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(b, b_dx_plus,  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'response'</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span></span>
<span id="cb42-17">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">predict</span>(b, b_dx_minus, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'response'</span>), </span>
<span id="cb42-18">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dx   =</span> b_dx_plus<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> b_dx_minus<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x2,</span>
<span id="cb42-19">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dydx =</span> dy<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>dx</span>
<span id="cb42-20">  ) </span>
<span id="cb42-21"></span>
<span id="cb42-22">gratia_result  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> gratia<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">derivatives</span>(b, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">newdata =</span> dat, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">eps =</span> h)</span>
<span id="cb42-23">margins_result <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> margins<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dydx</span>(dat, b, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">variable =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'x2'</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">eps =</span> h<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># note that margins uses the h function specified previously</span></span>
<span id="cb42-24"></span>
<span id="cb42-25"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all.equal</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(predictions_dydx<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>dydx), gratia_result<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>derivative)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "names for current but not for target" 
[2] "Mean relative difference: 5.59627e-05"</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb44" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb44-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all.equal</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(predictions_dydx<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>dydx), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.numeric</span>(margins_result<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>dydx_x2))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] TRUE</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb46" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb46-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summarise</span>(</span>
<span id="cb46-2">  predictions_dydx, </span>
<span id="cb46-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ame =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(dydx), </span>
<span id="cb46-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ame_gratia =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(gratia_result<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>derivative),</span>
<span id="cb46-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ame_margins =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(margins_result<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>dydx_x2)</span>
<span id="cb46-6">) </span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 1 × 3
    ame ame_gratia ame_margins
  &lt;dbl&gt;      &lt;dbl&gt;       &lt;dbl&gt;
1  1.76       1.76        1.76</code></pre>
</div>
</div>


</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>Not the least of which is that most outside of econometrics don’t call predictions <em>margins</em>, since these days we aren’t adding results to the margin of a hand-written table.↩︎</p></li>
<li id="fn2"><p>For those in the R world, the <code>i.age</code> tells Stata to treat the age factor as, well, a factor. Stata’s <code>alpha</code> is 1/<code>theta</code> from R’s output.↩︎</p></li>
<li id="fn3"><p>The <span class="pack" style="">margins</span> package does do predictions rather than the marginal effects, but it, like others, is just a wrapper for the <span class="func" style="">predict</span> method, and doesn’t appear to average them, so I don’t demonstrate that.↩︎</p></li>
<li id="fn4"><p>There is rarely a justifiable reason to discretize age as near as I can tell, and doing so inevitably results in less satisfying and less reliable conclusions.↩︎</p></li>
<li id="fn5"><p>There is a weird print issue where the Stata output isn’t showing the coefficient for one of the levels of <code>group</code>, but the model is correct and was verified directly using Stata.↩︎</p></li>
</ol>
</section><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2020,
  author = {Clark, Michael},
  title = {Predictions with an Offset},
  date = {2020-06-16},
  url = {https://m-clark.github.io/posts/2020-06-15-predict-with-offset/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2020" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2020. <span>“Predictions with an Offset.”</span> June
16. <a href="https://m-clark.github.io/posts/2020-06-15-predict-with-offset/">https://m-clark.github.io/posts/2020-06-15-predict-with-offset/</a>.
</div></div></section></div> ]]></description>
  <category>regression</category>
  <guid>https://m-clark.github.io/posts/2020-06-15-predict-with-offset/</guid>
  <pubDate>Tue, 16 Jun 2020 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/margins/preview.svg" medium="image" type="image/svg+xml"/>
</item>
<item>
  <title>Factor Analysis with the psych package</title>
  <dc:creator>Michael Clark</dc:creator>
  <link>https://m-clark.github.io/posts/2020-04-10-psych-explained/</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>NB: This post was revisited when updating the website early 2025, and some changes were required. Attempts to keep things consistent were made, but if you feel you’ve found an issue, please post it at <a href="http://github.com/m-clark/m-clark.github.io/issues">GitHub</a>.</p>
</blockquote>

<div class="no-row-height column-margin column-container"><div class="">
<p>Last updated January 02, 2025.</p>
</div></div><p>Prerequisites: familiarity with <a href="https://m-clark.github.io/sem/">factor analysis</a></p>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>The <span class="pack" style="">psych</span> package is a great tool for assessing underlying latent structure. It can provide reliability statistics, do cluster analysis, principal components analysis, mediation models, and, of course factor analysis. However, it’s been around a very long time, and many things have added to, subtracted, renamed, debugged, etc. And while the package author and noted psychometrician <a href="https://www.psychology.northwestern.edu/people/faculty/core/profiles/william-revelle.html">William Revelle</a> even provides a <a href="http://www.personality-project.org/r/book/">freely available book</a> on the details, it can still be difficult for many to ‘jump right in’ with the package. This is because it provides so much more than other tools, which is great, but which also can be overwhelming. Even I don’t recall what some of the output regards for factor analysis, and I use the package often. While a lot of it doesn’t matter for most use, it’d be nice to have a clean reference, so here it is.</p>
<p>What follows is an explanation of the factor analysis results from the <span class="pack" style="">psych</span> package, but much of it carries over into printed results for principal components via <span class="func" style="">principal</span>, reliability via <span class="func" style="">omega</span>, very simple structure via <span class="func" style="">vss</span> and others. Note that this is not an <a href="m-clark.github.io/sem">introduction to factor analysis, reliability, and related</a>. It’s assumed you are already familiar with the techniques to some extent, and are interested in using the package for those analyses.</p>
</section>
<section id="demonstration" class="level2">
<h2 class="anchored" data-anchor-id="demonstration">Demonstration</h2>
<p>We will use the classic <a href="https://en.wikipedia.org/wiki/Big_Five_personality_traits">big-five personality measures</a>, which comes with the package, but for our purposes, we’re just going to look at the agreeableness and neuroticism items. See <code>?bfi</code> for details. With data in place we run a standard factor analysis, in this case, assuming two factors.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(tidyverse)</span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(psych)</span>
<span id="cb1-3"></span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data</span>(bfi)</span>
<span id="cb1-5"></span>
<span id="cb1-6">bfi_trim <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bfi <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;">select</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matches</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'^A[1-5]|^N'</span>))</span>
<span id="cb1-7"></span>
<span id="cb1-8">model <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fa</span>(bfi_trim, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb1-9">model</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Factor Analysis using method =  minres
Call: fa(r = bfi_trim, nfactors = 2)
Standardized loadings (pattern matrix) based upon correlation matrix
     MR1   MR2   h2   u2 com
A1  0.07 -0.36 0.14 0.86 1.1
A2  0.05  0.69 0.47 0.53 1.0
A3  0.03  0.76 0.56 0.44 1.0
A4 -0.05  0.47 0.24 0.76 1.0
A5 -0.12  0.60 0.39 0.61 1.1
N1  0.78 -0.03 0.61 0.39 1.0
N2  0.76 -0.02 0.58 0.42 1.0
N3  0.77  0.05 0.58 0.42 1.0
N4  0.58 -0.08 0.36 0.64 1.0
N5  0.54  0.08 0.29 0.71 1.0

                       MR1  MR2
SS loadings           2.44 1.78
Proportion Var        0.24 0.18
Cumulative Var        0.24 0.42
Proportion Explained  0.58 0.42
Cumulative Proportion 0.58 1.00

 With factor correlations of 
      MR1   MR2
MR1  1.00 -0.19
MR2 -0.19  1.00

Mean item complexity =  1
Test of the hypothesis that 2 factors are sufficient.

df null model =  45  with the objective function =  2.82 with Chi Square =  7880.99
df of  the model are 26  and the objective function was  0.23 

The root mean square of the residuals (RMSR) is  0.04 
The df corrected root mean square of the residuals is  0.05 

The harmonic n.obs is  2759 with the empirical chi square  396.78  with prob &lt;  5.7e-68 
The total n.obs was  2800  with Likelihood Chi Square =  636.27  with prob &lt;  1.6e-117 

Tucker Lewis Index of factoring reliability =  0.865
RMSEA index =  0.092  and the 90 % confidence intervals are  0.085 0.098
BIC =  429.9
Fit based upon off diagonal values = 0.98
Measures of factor score adequacy             
                                                   MR1  MR2
Correlation of (regression) scores with factors   0.92 0.88
Multiple R square of scores with factors          0.84 0.77
Minimum correlation of possible factor scores     0.68 0.54</code></pre>
</div>
</div>
<section id="loadings" class="level3">
<h3 class="anchored" data-anchor-id="loadings">Loadings</h3>
<p>That’s a lot of stuff to work though. Let’s go through each part of the printed output.</p>
<ul>
<li>What’s <code>MR</code>, <code>ML</code>, <code>PC</code> etc.? These are factors, and the name merely reflects the fitting method, e.g.&nbsp;minimum residual, maximum likelihood, principal components. The default is minimum residual, so in this case <code>MR</code>.</li>
<li>Why are they ‘out of order’? the number assigned is arbitrary, but this has to do with a rotated solution. See the help file for more details, otherwise they are numbered in terms of variance accounted for.</li>
<li><code>h2</code>: the amount of variance in the item/variable explained by the (retained) factors. It is the sum of the squared loadings, a.k.a. <em>communality</em>.</li>
<li><code>u2</code>: 1 - <code>h2</code>. residual variance, a.k.a. <em>uniqueness</em></li>
<li><code>com</code>: Item complexity. Specifically it is “Hoffman’s index of complexity for each item. This is just <img src="https://latex.codecogs.com/png.latex?%7B(%CE%A3%20%CE%BB_i%5E2)%5E2%7D/%7B%CE%A3%20%CE%BB_i%5E4%7D"> where <img src="https://latex.codecogs.com/png.latex?%CE%BB_i"> is the factor loading on the i<sup>th</sup> factor. From Hofmann (1978), MBR. See also Pettersson and Turkheimer (2010).” It equals one if an item loads only on one factor, 2 if evenly loads on two factors, etc. Basically it tells you how much an item reflects a single construct. It will be lower for relatively lower loadings.</li>
</ul>
</section>
<section id="variance-accounted-for" class="level3">
<h3 class="anchored" data-anchor-id="variance-accounted-for">Variance accounted for</h3>
<pre><code>                       MR1  MR2
SS loadings           2.44 1.78
Proportion Var        0.24 0.18
Cumulative Var        0.24 0.42
Proportion Explained  0.58 0.42
Cumulative Proportion 0.58 1.00</code></pre>
<p>The variance accounted for portion of the output can be explained as follows:</p>
<ul>
<li><code>SS loadings</code>: These are the eigenvalues, the sum of the squared loadings. In this case where we are using a correlation matrix, summing across all factors would equal the number of variables used in the analysis.</li>
<li><code>Proportion Var</code>: tells us how much of the overall variance the factor accounts for out of all the variables.</li>
<li><code>Cumulative Var</code>: the cumulative sum of <code>Proportion Var</code>.</li>
<li><code>Proportion Explained</code>: The relative amount of variance explained- Proportion Var<code>/sum(</code>Proportion Var<code>)</code>.</li>
<li><code>Cumulative Proportion</code>: the cumulative sum of <code>Proportion Explained</code>.</li>
</ul>
<p>These are contained in <code>model$Vaccounted</code>.</p>
</section>
<section id="factor-correlations" class="level3">
<h3 class="anchored" data-anchor-id="factor-correlations">Factor correlations</h3>
<pre><code> With factor correlations of 
      MR1   MR2
MR1  1.00 -0.19
MR2 -0.19  1.00</code></pre>
<p>Whether you get this part of the analysis depends on whether or not these are estimated. You have to have multiple factors and a rotation that allows for the correlations.</p>
<ul>
<li><code>factor correlations</code>: the correlation matrix for the factors. <img src="https://latex.codecogs.com/png.latex?%5Cphi"> (phi)</li>
<li><code>Mean item complexity</code>: the mean of <code>com</code>.</li>
</ul>
<p>These are contained in <code>model$Phi</code>.</p>
</section>
<section id="model-test-results" class="level3">
<h3 class="anchored" data-anchor-id="model-test-results">Model test results</h3>
<pre><code>Test of the hypothesis that 2 factors are sufficient.

The degrees of freedom for the null model are  45  and the objective function was  2.82 with Chi Square of  7880.99
The degrees of freedom for the model are 26  and the objective function was  0.23 </code></pre>
<ul>
<li><code>null model</code>: The degrees of freedom for the null model that assumes no correlation structure.</li>
<li><code>objective function</code>: The value of the function that is minimized by a specific procedure.</li>
<li><code>model</code>: The one you’re actually interested in. Where p = Number of items, nf = number of factors then: degrees of freedom = <img src="https://latex.codecogs.com/png.latex?p%20*%20(p-1)/2%20-%20p%20*%20nf%20+%20nf*(nf-1)/2"> For the null model this is <img src="https://latex.codecogs.com/png.latex?p%20*%20(p-1)/2">.</li>
<li><code>Chi-square</code>: If <code>f</code> is the objective function value. Then <img src="https://latex.codecogs.com/png.latex?%5Cchi%5E2%20=%20(n.obs%20-%201%20-%20(2%20*%20p%20+%205)/6%20-%20(2%20*%20nf)/3))%20*%20f"><br>
Strangely this is reported for the null but not the primary model result, which comes later.</li>
</ul>
</section>
<section id="number-of-observations" class="level3">
<h3 class="anchored" data-anchor-id="number-of-observations">Number of observations</h3>
<pre><code>The harmonic number of observations is  2759 with the empirical chi square  396.78  with prob &lt;  5.7e-68 
The total number of observations was  2800  with Likelihood Chi Square =  636.27  with prob &lt;  1.6e-117 </code></pre>
<ul>
<li><code>total</code>: the number of rows in the data you supplied for analysis</li>
<li><code>harmonic</code>: while one would assume it is the harmonic mean of the number of observations across items, it’s not this exactly, but is instead the harmonic mean of all the pairwise counts of observations (see <code>?pairwiseCount</code>).</li>
</ul>
<p>The <img src="https://latex.codecogs.com/png.latex?%5Cchi%5E2"> reported here regards the primary model. So for your model you can report <code>model$STATISTIC</code>, <code>model$dof</code>, <code>model$PVAL</code>, which is what you see in the printed output for the total number of observations. As this regards the residual correlation matrix, a smaller value is better, as in SEM. The empirical chi-square is based on the harmonic sample size, so might be better, but I’ve never seen it reported.</p>
</section>
<section id="fit-indices" class="level3">
<h3 class="anchored" data-anchor-id="fit-indices">Fit indices</h3>
<pre><code>The root mean square of the residuals (RMSR) is  0.04 
The df corrected root mean square of the residuals is  0.05 

...

Tucker Lewis Index of factoring reliability =  0.865
RMSEA index =  0.092  and the 90 % confidence intervals are  0.085 0.098
BIC =  429.9
Fit based upon off diagonal values = 0.98</code></pre>
<p>The nice thing about the psych package is that it reports SEM-style fit indices for standard factor analysis. You can find some more information via <code>?factor.stats</code>.</p>
<ul>
<li><code>TLI</code>: Tucker Lewis fit index, typically reported in SEM. Generally want &gt; .9</li>
<li><code>RMSEA</code>: Root mean square error of approximation. Also reported is the so-called ‘test of close fit’.</li>
<li><code>RMSR</code>: The (standardized) root mean square of the residuals. Also provided is a ‘corrected’ version, but I doubt this is reported by many.</li>
<li><code>Fit based upon off diagonal values</code>: This is not documented anywhere I can find. However, you can think of it as <code>1 - resid^2 / cor^2</code>, or a kind of <img src="https://latex.codecogs.com/png.latex?R%5E2"> applied to a correlation matrix instead of raw data. It is calculated via <span class="func" style="">factor.stats</span>.</li>
<li><code>BIC</code>: Useful for model comparison purposes only.</li>
</ul>
</section>
<section id="measures-of-factor-score-adequacy" class="level3">
<h3 class="anchored" data-anchor-id="measures-of-factor-score-adequacy">Measures of factor score adequacy</h3>
<pre><code>Measures of factor score adequacy             
                                                   MR1  MR2
Correlation of (regression) scores with factors   0.92 0.88
Multiple R square of scores with factors          0.84 0.77
Minimum correlation of possible factor scores     0.68 0.54</code></pre>
<p>Unfortunately these are named in such a way as to be nearly indistinguishable, but there is some documentation for them in <code>?factor.stats</code>. In general, these tell us how representative the factor score estimates are of the underlying constructs, and can be called indeterminancy indices. Indeterminancy refers to the fact that an infinite number of factor scores can be derived that would be consistent with a given set of loadings. In Revelle’s text, <a href="http://www.personality-project.org/r/book/#chapter6">chapter 6.9</a> goes into detail, while Grice (2001) is a thorough review of the problem.</p>
<ul>
<li><code>Correlation of (regression) scores with factors</code>: square root of the <code>Multiple R square</code>. These can be seen as upper bounds of the determinancy of the factor score estimates that can be computed based on the model. It is essentially the (multiple) correlation of the factor and the observed data, as the name now more clearly suggests.</li>
<li><code>Multiple R square...</code>: “The multiple R square between the factors and factor score estimates, if they were to be found. (From Grice, 2001).” Computationally, it is roughly <code>t(model$weights) %*% model$loadings</code>, where the weights are the factor score coefficients, and can be seen as the maximum proportion of determinancy (higher is better). One way you can think about this is as an <img src="https://latex.codecogs.com/png.latex?R%5E2"> for a regression model of the items predicting the estimated factor score.</li>
<li><code>Minimum correlation...</code>: Not documented, and is only shown as part of the print method, as it is not calculated as part of the factor analysis. But it is <img src="https://latex.codecogs.com/png.latex?2%20%5Ccdot%20R%5E2%20-%201">, and so ranges from -1 to +1. If your <img src="https://latex.codecogs.com/png.latex?R%5E2"> is less than .5, it will be negative, which is not good.</li>
</ul>
</section>
<section id="miscellaneous-results" class="level3">
<h3 class="anchored" data-anchor-id="miscellaneous-results">Miscellaneous results</h3>
<p>There is a lot of other stuff in these objects, like a sample size corrected BIC, Grice’s validity coefficients, the actual residuals for the correlation matrix and more.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str</span>(model, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>List of 54
 $ residual     : num [1:10, 1:10] 0.8556 -0.0899 0.0122 0.0377 0.0573 ...
  ..- attr(*, "dimnames")=List of 2
 $ dof          : num 26
 $ chi          : num 397
 $ nh           : num 2759
 $ rms          : num 0.04
 $ EPVAL        : num 5.71e-68
 $ crms         : num 0.0526
 $ EBIC         : num 191
 $ ESABIC       : num 273
 $ fit          : num 0.789
 $ fit.off      : num 0.981
 $ sd           : num 0.0382
 $ factors      : num 2
 $ complexity   : Named num [1:10] 1.09 1.01 1 1.02 1.08 ...
  ..- attr(*, "names")= chr [1:10] "A1" "A2" "A3" "A4" ...
 $ n.obs        : int 2800
 $ objective    : num 0.228
 $ criteria     : Named num [1:3] 0.228 NA NA
  ..- attr(*, "names")= chr [1:3] "objective" "" ""
 $ STATISTIC    : num 636
 $ PVAL         : num 1.6e-117
 $ Call         : language fa(r = bfi_trim, nfactors = 2)
 $ null.model   : num 2.82
 $ null.dof     : num 45
 $ null.chisq   : num 7881
 $ TLI          : num 0.865
 $ CFI          : num 0.922
 $ RMSEA        : Named num [1:4] 0.0916 0.0855 0.0978 0.9
  ..- attr(*, "names")= chr [1:4] "RMSEA" "lower" "upper" "confidence"
 $ BIC          : num 430
 $ SABIC        : num 513
 $ r.scores     : num [1:2, 1:2] 1 -0.227 -0.227 1
 $ R2           : num [1:2] 0.842 0.768
 $ valid        : num [1:2] 0.905 0.852
 $ score.cor    : num [1:2, 1:2] 1 -0.185 -0.185 1
 $ weights      : num [1:10, 1:2] 0.00559 0.00986 -0.00452 -0.01416 -0.03449 ...
  ..- attr(*, "dimnames")=List of 2
 $ rotation     : chr "oblimin"
 $ hyperplane   : Named num [1:2] 5 5
  ..- attr(*, "names")= chr [1:2] "MR1" "MR2"
 $ communality  : Named num [1:10] 0.144 0.467 0.563 0.237 0.395 ...
  ..- attr(*, "names")= chr [1:10] "A1" "A2" "A3" "A4" ...
 $ communalities: Named num [1:10] 0.144 0.467 0.563 0.237 0.395 ...
  ..- attr(*, "names")= chr [1:10] "A1" "A2" "A3" "A4" ...
 $ uniquenesses : Named num [1:10] 0.856 0.533 0.437 0.763 0.605 ...
  ..- attr(*, "names")= chr [1:10] "A1" "A2" "A3" "A4" ...
 $ values       : num [1:10] 2.6714 1.5564 0.2727 0.1283 0.0455 ...
 $ e.values     : num [1:10] 3.185 2.11 0.938 0.768 0.71 ...
 $ loadings     : 'loadings' num [1:10, 1:2] 0.0744 0.0541 0.0311 -0.0519 -0.1191 ...
  ..- attr(*, "dimnames")=List of 2
 $ model        : num [1:10, 1:10] 0.144 -0.25 -0.277 -0.184 -0.239 ...
  ..- attr(*, "dimnames")=List of 2
 $ fm           : chr "minres"
 $ rot.mat      : num [1:2, 1:2] 0.857 0.549 -0.38 0.944
 $ Phi          : num [1:2, 1:2] 1 -0.186 -0.186 1
  ..- attr(*, "dimnames")=List of 2
 $ Structure    : 'loadings' num [1:10, 1:2] 0.1413 -0.0748 -0.1098 -0.1402 -0.23 ...
  ..- attr(*, "dimnames")=List of 2
 $ method       : chr "regression"
 $ scores       : num [1:2800, 1:2] -0.224 0.2186 0.532 -0.2429 -0.0564 ...
  ..- attr(*, "dimnames")=List of 2
 $ R2.scores    : Named num [1:2] 0.842 0.768
  ..- attr(*, "names")= chr [1:2] "MR1" "MR2"
 $ r            : num [1:10, 1:10] 1 -0.34 -0.265 -0.146 -0.181 ...
  ..- attr(*, "dimnames")=List of 2
 $ np.obs       : num [1:10, 1:10] 2784 2757 2759 2767 2769 ...
  ..- attr(*, "dimnames")=List of 2
 $ fn           : chr "fa"
 $ Vaccounted   : num [1:5, 1:2] 2.443 0.244 0.244 0.578 0.578 ...
  ..- attr(*, "dimnames")=List of 2
 $ ECV          : Named num [1:2] 0.578 1
  ..- attr(*, "names")= chr [1:2] "MR1" "MR2"
 - attr(*, "class")= chr [1:2] "psych" "fa"</code></pre>
</div>
</div>
<p>In turn, these are:</p>
<ul>
<li><code>residual</code>: The residual correlation matrix</li>
<li><code>dof</code>: The model degrees of freedom</li>
<li><code>chi</code>: The empirical model <img src="https://latex.codecogs.com/png.latex?X%5E2"></li>
<li><code>nh</code>: The harmonic sample size</li>
<li><code>rms</code>: Root mean square residual</li>
<li><code>EPVAL</code>: p-value for the empirical chi-square</li>
<li><code>crms</code>: a ‘corrected’ rms</li>
<li><code>EBIC</code>: BIC for the empirical model</li>
<li><code>ESABIC</code>: sample-size corrected BIC for the empirical model</li>
<li><code>fit</code>: Similar to <code>fit.off</code>. General fit index (how well is the observed correlation reproduced)</li>
<li><code>fit.off</code>: Fit based on off diagonals. Reported in the output. See above.</li>
<li><code>sd</code>: standard deviation of the off-diagonals of the residual correlation matrix.</li>
<li><code>factors</code>: the number of factors</li>
<li><code>complexity</code>: The complexity scores. See above.</li>
<li><code>n.obs</code>: The number of observations (assuming complete data)</li>
<li><code>objective</code>: The objective function for the model</li>
<li><code>criteria</code>: Along with the objective function, additional fitting results</li>
<li><code>STATISTIC</code>: The model-based <img src="https://latex.codecogs.com/png.latex?X%5E2"></li>
<li><code>PVAL</code>: The p-value for the model-based <img src="https://latex.codecogs.com/png.latex?X%5E2"></li>
<li><code>Call</code>: The function call</li>
<li><code>null.model</code>: <img src="https://latex.codecogs.com/png.latex?X%5E2"> test results for the null model</li>
<li><code>null.dof</code>: <img src="https://latex.codecogs.com/png.latex?X%5E2"> test results for the null model</li>
<li><code>null.chisq</code>: <img src="https://latex.codecogs.com/png.latex?X%5E2"> test results for the null model</li>
<li><code>TLI</code>: Tucker-Lewis fit index</li>
<li><code>RMSEA</code>: Root mean square error of approximation with upper and lower bounds</li>
<li><code>BIC</code>: Bayesian Information Criterion for the model</li>
<li><code>SABIC</code>: sample-size corrected BIC for the model</li>
<li><code>r.scores</code>: The correlations of the factor score estimates using the specified model, if they were to be found. Comparing these correlations with that of the scores themselves will show, if an alternative estimate of factor scores is used (e.g., the tenBerge method), the problem of factor indeterminacy. For these correlations will not necessarily be the same.</li>
<li><code>R2</code>: correlation of factors and estimated factor scores (squared)</li>
<li><code>valid</code>: validity coefficients</li>
<li><code>score.cor</code>: The correlation matrix of course coded (unit weighted) factor score estimates (i.e.&nbsp;sum scores), if they were to be found, based upon the loadings matrix rather than the weights matrix.</li>
<li><code>weights</code>: weights used to construct factor scores</li>
<li><code>rotation</code>: rotation used</li>
<li><code>communality</code>: communality scores <code>h2</code></li>
<li><code>communalities</code>: So nice they put them twice (actually not entirely equal)</li>
<li><code>uniquenesses</code>: Uniquenesses <code>u2</code></li>
<li><code>values</code> eigenvalues of the model implied correlation matrix</li>
<li><code>e.values</code>: eigenvalues of the correlation matrix</li>
<li><code>loadings</code>: the factor loadings</li>
<li><code>model</code>: the model-implied correlation matrix</li>
<li><code>fm</code>: the estimation approach</li>
<li><code>rot.mat</code>: matrix used in the rotated solution</li>
<li><code>Phi</code>: factor score correlation matrix</li>
<li><code>Structure</code>: this is just the loadings (pattern) matrix times the factor intercorrelation matrix (Phi).</li>
<li><code>method</code>: method used to construct the factor scores</li>
<li><code>scores</code>: estimated factor scores</li>
<li><code>R2.scores</code>: estimated correlation of factor scores with the factor (squared)</li>
<li><code>r</code>: the (possibly smoothed) correlation matrix of the observation</li>
<li><code>np.obs</code>: pairwise sample sizes (used to get the harmonic mean)</li>
<li><code>fn</code>: the function used</li>
<li><code>Vaccounted</code>: the SS loadings output.</li>
</ul>
</section>
</section>
<section id="additional-notes-for-factor-analysis" class="level2">
<h2 class="anchored" data-anchor-id="additional-notes-for-factor-analysis">Additional Notes for Factor Analysis</h2>
<ul>
<li><p>Most of the above would apply to other versions of <span class="func" style="">fa</span> and <span class="func" style="">principal</span> for principal components analysis.</p></li>
<li><p>Though rarely done, if you only provide a correlation matrix as your data, you will not get a variety of metrics in the results, nor factor scores.</p></li>
<li><p>Certain rotations will lead to differently named factors, and possibly lacking some output (e.g.&nbsp;varimax won’t have factor correlations).</p></li>
</ul>
</section>
<section id="other-functions" class="level2">
<h2 class="anchored" data-anchor-id="other-functions">Other Functions</h2>
<p>While the previous will help explain factor analysis and related models, a similar issue arises elsewhere with other package functions that might be of interest. I’ll explain some of those here as interest and personal use dictates.</p>
<section id="alpha" class="level3">
<h3 class="anchored" data-anchor-id="alpha">Alpha</h3>
<p>This is a quick reminder for the results of the reliability coefficient <img src="https://latex.codecogs.com/png.latex?%5Calpha">. For this we’ll just use the agreeableness items to keep things succinct.</p>
<section id="basic-results" class="level4">
<h4 class="anchored" data-anchor-id="basic-results">Basic Results</h4>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1">agreeableness <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> bfi_trim[,<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;">5</span>]</span>
<span id="cb11-2"></span>
<span id="cb11-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># check.keys will rescale negatively scored items</span></span>
<span id="cb11-4">alpha_results <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">alpha</span>(agreeableness, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">check.keys =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n.iter=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>) </span>
<span id="cb11-5">alpha_results</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
Reliability analysis   
Call: alpha(x = agreeableness, check.keys = TRUE, n.iter = 10)

  raw_alpha std.alpha G6(smc) average_r  S/N   ase mean  sd median_r
       0.7      0.46    0.53      0.14 0.85 0.009  4.7 0.9     0.32

    95% confidence boundaries 
             lower alpha upper
Feldt         0.69   0.7  0.72
Duhachek      0.69   0.7  0.72
bootstrapped  0.69   0.7  0.72

 Reliability if an item is dropped:
    raw_alpha std.alpha G6(smc) average_r  S/N alpha se  var.r med.r
A1-      0.72      0.72    0.67     0.397 2.63   0.0087 0.0065 0.375
A2       0.62      0.30    0.39     0.096 0.43   0.0119 0.1095 0.081
A3       0.60      0.21    0.31     0.061 0.26   0.0124 0.1014 0.081
A4       0.69      0.30    0.44     0.099 0.44   0.0098 0.1604 0.104
A5       0.64      0.24    0.36     0.071 0.31   0.0111 0.1309 0.094

 Item statistics 
       n raw.r std.r r.cor r.drop mean  sd
A1- 2784  0.58 0.024 -0.39   0.31  4.6 1.4
A2  2773  0.73 0.665  0.58   0.56  4.8 1.2
A3  2774  0.76 0.742  0.71   0.59  4.6 1.3
A4  2781  0.65 0.661  0.50   0.39  4.7 1.5
A5  2784  0.69 0.719  0.64   0.49  4.6 1.3

Non missing response frequency for each item
      1    2    3    4    5    6 miss
A1 0.33 0.29 0.14 0.12 0.08 0.03 0.01
A2 0.02 0.05 0.05 0.20 0.37 0.31 0.01
A3 0.03 0.06 0.07 0.20 0.36 0.27 0.01
A4 0.05 0.08 0.07 0.16 0.24 0.41 0.01
A5 0.02 0.07 0.09 0.22 0.35 0.25 0.01</code></pre>
</div>
</div>
<ul>
<li><code>raw_alpha</code>: Raw estimate of alpha (based on covariances)</li>
<li><code>std.alpha</code>: Standardized estimate. This value is what is typically reported (though most applied researchers would probably not be able to tell you which they reported). Identical to raw if data is already standardized.</li>
<li><code>G6 (smc)</code>: Guttman’s <img src="https://latex.codecogs.com/png.latex?%5Clambda_6">, the amount of variance in each item that can be accounted for the linear regression of all of the other items</li>
<li><code>average_r</code>: Average inter-item correlation among the items.</li>
<li><code>S/N</code>: Signal to noise ratio, <img src="https://latex.codecogs.com/png.latex?n%20%5Ccdot%20r/(1-r)"> where r is the <code>average_r</code></li>
<li><code>ase</code>: standard error for raw <img src="https://latex.codecogs.com/png.latex?%5Calpha"> (used for the confidence interval, bootstrapped would be better)</li>
<li><code>mean</code>: the mean of the total/mean score of the items</li>
<li><code>sd</code>: the standard deviation of the total/mean score of the items</li>
<li><code>median_r</code>: median inter-item correlation</li>
</ul>
<p>After the initial statistics, the same stats are reported but for a result where a specific item is dropped. For example, if your <img src="https://latex.codecogs.com/png.latex?%5Calpha"> goes up when an item is dropped, it probably isn’t a good item. In this case, the negatively scored item is probably worst, which isn’t an uncommon result.</p>
</section>
<section id="item-statistics" class="level4">
<h4 class="anchored" data-anchor-id="item-statistics">Item statistics</h4>
<p>Next we get the item statistics, they are as follows.</p>
<pre><code> Item statistics 
       n raw.r std.r r.cor r.drop mean  sd
A1- 2784  0.58  0.57  0.38   0.31  4.6 1.4
A2  2773  0.73  0.75  0.67   0.56  4.8 1.2
A3  2774  0.76  0.77  0.71   0.59  4.6 1.3
A4  2781  0.65  0.63  0.47   0.39  4.7 1.5
A5  2784  0.69  0.70  0.60   0.49  4.6 1.3</code></pre>
<ul>
<li><code>n</code>: number of complete observations</li>
<li><code>raw.r</code>: correlation of each item with the total score</li>
<li><code>std.r</code>: correlation of each item with the total score if the items were all standardized</li>
<li><code>r.cor</code>: item correlation corrected for item overlap and scale reliability</li>
<li><code>r.drop</code> item correlation for this item against the scale without this item</li>
<li><code>mean</code>: item mean</li>
<li><code>sd</code>: item standard deviation</li>
</ul>
</section>
<section id="response-frequency" class="level4">
<h4 class="anchored" data-anchor-id="response-frequency">Response frequency</h4>
<p>Finally we have information about the missingness of each item. The initial values show the proportion of each level observed, while the last column shows the percentage missing.</p>
<pre><code>Non missing response frequency for each item
      1    2    3    4    5    6 miss
A1 0.33 0.29 0.14 0.12 0.08 0.03 0.01
A2 0.02 0.05 0.05 0.20 0.37 0.31 0.01
A3 0.03 0.06 0.07 0.20 0.36 0.27 0.01
A4 0.05 0.08 0.07 0.16 0.24 0.41 0.01
A5 0.02 0.07 0.09 0.22 0.35 0.25 0.01</code></pre>
</section>
<section id="other-output" class="level4">
<h4 class="anchored" data-anchor-id="other-output">Other Output</h4>
<p>In addition to these we have a bit more from the output.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str</span>(alpha_results[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(alpha_results)])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>List of 11
 $ keys   :List of 1
  ..$ : chr [1:5] "-A1" "A2" "A3" "A4" ...
 $ scores : Named num [1:2800] 4 4.2 3.8 4.6 4 4.6 4.6 2.6 3.6 5.4 ...
  ..- attr(*, "names")= chr [1:2800] "61617" "61618" "61620" "61621" ...
 $ nvar   : int 5
 $ boot.ci: Named num [1:3] 0.692 0.702 0.717
  ..- attr(*, "names")= chr [1:3] "2.5%" "50%" "97.5%"
 $ boot   : num [1:10, 1:10] 0.712 0.692 0.711 0.718 0.695 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:10] "raw_alpha" "std.alpha" "G6(smc)" "average_r" ...
 $ feldt  :List of 4
  ..$ lower.ci:'data.frame':    1 obs. of  1 variable:
  .. ..$ raw_alpha: num 0.685
  ..$ alpha   :'data.frame':    1 obs. of  1 variable:
  .. ..$ raw_alpha: num 0.703
  ..$ upper.ci:'data.frame':    1 obs. of  1 variable:
  .. ..$ raw_alpha: num 0.72
  ..$ r.bar   :'data.frame':    1 obs. of  1 variable:
  .. ..$ raw_alpha: num 0.321
  ..- attr(*, "class")= chr [1:2] "psych" "alpha.ci"
 $ Unidim :List of 1
  ..$ Unidim: num 0.237
 $ var.r  : num 0.112
 $ Fit    :List of 1
  ..$ Fit.off: num 0.879
 $ call   : language alpha(x = agreeableness, check.keys = TRUE, n.iter = 10)
 $ title  : NULL</code></pre>
</div>
</div>
<p>In turn these are:</p>
<ul>
<li><code>keys</code>: how the items are score (-1 if reverse scored)</li>
<li><code>scores</code>: row means/sums depending on the <code>cumulative</code> argument</li>
<li><code>nvar</code>: the number of variables/items</li>
<li><code>boot.ci</code>: the bootstrapped confidence interval for <img src="https://latex.codecogs.com/png.latex?%5Calpha"> (if requested)</li>
<li><code>boot</code>: the bootstrapped values of <img src="https://latex.codecogs.com/png.latex?%5Calpha"> and other statistics (if requested)</li>
<li><code>Unidim</code>: index of unidimensionalty. <img src="https://latex.codecogs.com/png.latex?%5Calpha"> is a lower bound of a reliability estimate if the data is not unidimensional. See <code>?unidim</code> for details.</li>
<li><code>var.r</code>: This doesn’t appear to be documented anywhere, but it is depicted in the <code>Reliability if item is dropped</code> section. It is the variance of the values of the lower triangle of a correlation matrix.</li>
<li><code>Fit</code>: see <code>Fit based upon off diagonal values</code> for the factor analysis section above.</li>
<li><code>call</code>: the function call</li>
<li><code>title</code>: title of the results (if requested)</li>
</ul>
</section>
</section>
<section id="omega" class="level3">
<h3 class="anchored" data-anchor-id="omega">Omega</h3>
<p>Omega is another reliability metric that finally has been catching on. The <span class="pack" style="">psych</span> function <span style="">omega</span> requires a factor analysis to be run behind the scenes, specifically a <em>bifactor</em> model, so most of the output is the same as with other factor analysis. In addition, the results also provide coefficient <img src="https://latex.codecogs.com/png.latex?%5Calpha"> and Guttman’s <img src="https://latex.codecogs.com/png.latex?%5Clambda_6"> that were explained in the alpha section.</p>
<p>However there is a little more to it, so we’ll explain those aspects. The key help files are <code>?omega</code> and <code>?schmid</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb17-1">omega_result <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">omega</span>(bfi[,<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;">15</span>])</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2020-04-10-psych-explained/index_files/figure-html/omega-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><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">omega_result</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Omega 
Call: omegah(m = m, nfactors = nfactors, fm = fm, key = key, flip = flip, 
    digits = digits, title = title, sl = sl, labels = labels, 
    plot = plot, n.obs = n.obs, rotate = rotate, Phi = Phi, option = option, 
    covar = covar)
Alpha:                 0.81 
G.6:                   0.83 
Omega Hierarchical:    0.54 
Omega H asymptotic:    0.64 
Omega Total            0.85 

Schmid Leiman Factor loadings greater than  0.2 
        g   F1*   F2*   F3*   h2   u2   p2
A1-  0.24              0.30 0.16 0.84 0.36
A2   0.52              0.44 0.47 0.53 0.58
A3   0.59              0.45 0.56 0.44 0.63
A4   0.39              0.28 0.25 0.75 0.62
A5   0.56              0.31 0.44 0.56 0.70
C1               0.53       0.31 0.69 0.11
C2   0.23        0.60       0.42 0.58 0.12
C3   0.21        0.51       0.32 0.68 0.14
C4-  0.25        0.59       0.41 0.59 0.15
C5-  0.28        0.51       0.34 0.66 0.23
E1-  0.37  0.47             0.37 0.63 0.38
E2-  0.48  0.54             0.53 0.47 0.43
E3   0.47  0.36             0.37 0.63 0.61
E4   0.54  0.46             0.51 0.49 0.57
E5   0.41  0.32  0.25       0.33 0.67 0.51

With Sums of squares  of:
   g  F1*  F2*  F3* 
2.47 1.03 1.60 0.69 

general/max  1.54   max/min =   2.32
mean percent general =  0.41    with sd =  0.21 and cv of  0.52 
Explained Common Variance of the general factor =  0.43 

The degrees of freedom are 63  and the fit is  0.34 
The number of observations was  2800  with Chi Square =  961.82  with prob &lt;  6.4e-161
The root mean square of the residuals is  0.04 
The df corrected root mean square of the residuals is  0.05
RMSEA index =  0.071  and the 10 % confidence intervals are  0.067 0.075
BIC =  461.77

Compare this with the adequacy of just a general factor and no group factors
The degrees of freedom for just the general factor are 90  and the fit is  1.58 
The number of observations was  2800  with Chi Square =  4407.94  with prob &lt;  0
The root mean square of the residuals is  0.13 
The df corrected root mean square of the residuals is  0.14 

RMSEA index =  0.131  and the 10 % confidence intervals are  0.128 0.134
BIC =  3693.57 

Measures of factor score adequacy             
                                                 g   F1*  F2*   F3*
Correlation of scores with factors            0.78  0.70 0.82  0.60
Multiple R square of scores with factors      0.61  0.49 0.68  0.36
Minimum correlation of factor score estimates 0.22 -0.01 0.36 -0.28

 Total, General and Subset omega for each subset
                                                 g  F1*  F2*  F3*
Omega total for total scores and subscales    0.85 0.77 0.73 0.73
Omega general for total scores and subscales  0.54 0.40 0.11 0.46
Omega group for total scores and subscales    0.25 0.36 0.62 0.27</code></pre>
</div>
</div>
<p>The bifactor model requires a single general factor and minimally three specific factors, as the plot shows. However, you can run it on single factor just to get the omega total statistic, but any less than three factors will produce a warning and some metrics will either be unavailable or not make much sense.</p>
<section id="reliability" class="level4">
<h4 class="anchored" data-anchor-id="reliability">Reliability</h4>
<pre><code>Alpha:                 0.81 
G.6:                   0.83 
Omega Hierarchical:    0.54 
Omega H asymptotic:    0.64 
Omega Total            0.85 </code></pre>
<p>The first two pieces of info are as in alpha, the next regard <img src="https://latex.codecogs.com/png.latex?%5Comega"> specifically. <img src="https://latex.codecogs.com/png.latex?%5Comega"> is based on the squared factor loadings. <img src="https://latex.codecogs.com/png.latex?%5Comega_%7Bhierarchical%7D"> regards just the loadings of the general factor. The asymptotic is the same for a ‘test of infinite items’, and so can be seen as an upper bound. <img src="https://latex.codecogs.com/png.latex?%5Comega_%7Btotal%7D"> is based on all the general and specific factor loadings. I personally like to think of the ratio of <img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B%5Comega_%7Bhier%7D%7D%7B%5Comega_%7Btotal%7D%7D">, which if very high, say .9 or so, may suggest unidimensionality.</p>
</section>
<section id="loadings-1" class="level4">
<h4 class="anchored" data-anchor-id="loadings-1">Loadings</h4>
<pre><code>Schmid Leiman Factor loadings greater than  0.2 
        g   F1*   F2*   F3*   h2   u2   p2
A1-  0.24              0.30 0.16 0.84 0.36
A2   0.52              0.44 0.47 0.53 0.58
A3   0.59              0.45 0.56 0.44 0.63
A4   0.39              0.28 0.25 0.75 0.62
A5   0.56              0.31 0.44 0.56 0.70
C1               0.53       0.31 0.69 0.11
C2   0.23        0.60       0.42 0.58 0.12
C3   0.21        0.51       0.32 0.68 0.14
C4-  0.25        0.59       0.41 0.59 0.15
C5-  0.28        0.51       0.34 0.66 0.23
E1-  0.37  0.47             0.37 0.63 0.38
E2-  0.48  0.54             0.53 0.47 0.43
E3   0.47  0.36             0.37 0.63 0.61
E4   0.54  0.46             0.51 0.49 0.57
E5   0.41  0.32  0.25       0.33 0.67 0.51

With eigenvalues of:
   g  F1*  F2*  F3* 
2.47 1.03 1.60 0.69 

general/max  1.54   max/min =   2.32
mean percent general =  0.41    with sd =  0.21 and cv of  0.52 
Explained Common Variance of the general factor =  0.43 </code></pre>
<p>The loadings are for the general and specific factors are provided, as well as the communalities and uniquenesses. In addition there is a column for <code>p2</code>, which is considered a diagnostic tool for the appropriateness of a hierarchical model. It is defined as “percent of the common variance for each variable that is general factor variance”, which is just <code>g</code><sup>2</sup>/<code>h2</code>. The line of <code>mean percent general...</code> isn’t documented and is a result of the unexported <span class="func" style="">print.psych.omega</span> function. It wasn’t obvious to me, but these are merely statistics regarding the <code>p2</code> column (<code>cv</code> is the coefficient of variation).</p>
<p>Next you get eigenvalue/variance accounted as in standard factor analysis. Then <code>general/max</code> and <code>max/min</code> regard those ratios of the corresponding eigenvalues. Explained common variance is the percent of variance attributable to the general factor (g/sum(all eigenvalues))</p>
</section>
<section id="model-test-results-fit" class="level4">
<h4 class="anchored" data-anchor-id="model-test-results-fit">Model test results &amp; fit</h4>
<pre><code>The degrees of freedom are 63  and the fit is  0.34 
The number of observations was  2800  with Chi Square =  961.82  with prob &lt;  6.4e-161
The root mean square of the residuals is  0.04 
The df corrected root mean square of the residuals is  0.05
RMSEA index =  0.071  and the 10 % confidence intervals are  0.067 0.075
BIC =  461.77

Compare this with the adequacy of just a general factor and no group factors
The degrees of freedom for just the general factor are 90  and the fit is  1.58 
The number of observations was  2800  with Chi Square =  4407.94  with prob &lt;  0
The root mean square of the residuals is  0.13 
The df corrected root mean square of the residuals is  0.14 

RMSEA index =  0.131  and the 10 % confidence intervals are  0.128 0.134
BIC =  3693.57 </code></pre>
<p>The only thing different here relative to the standard factor analysis results is that there are two models considered- a model with general and specific factors and a model with no specific factors.</p>
</section>
<section id="measures-of-factor-score-adequacy-1" class="level4">
<h4 class="anchored" data-anchor-id="measures-of-factor-score-adequacy-1">Measures of factor score adequacy</h4>
<pre><code>Measures of factor score adequacy             
                                                 g   F1*  F2*   F3*
Correlation of scores with factors            0.78  0.70 0.82  0.60
Multiple R square of scores with factors      0.61  0.49 0.68  0.36
Minimum correlation of factor score estimates 0.22 -0.01 0.36 -0.28</code></pre>
<p>This first part of the output is the same as standard factor analysis (see above).</p>
</section>
<section id="variance-accounted-for-by-group-and-specific-factors" class="level4">
<h4 class="anchored" data-anchor-id="variance-accounted-for-by-group-and-specific-factors">Variance accounted for by group and specific factors</h4>
<pre><code> Total, General and Subset omega for each subset
                                                 g  F1*  F2*  F3*
Omega total for total scores and subscales    0.85 0.77 0.73 0.73
Omega general for total scores and subscales  0.54 0.40 0.11 0.46
Omega group for total scores and subscales    0.25 0.36 0.62 0.27</code></pre>
<p>This part is explained in the <code>?omega</code> helpfile as:</p>
<blockquote class="blockquote">
<p>The notion of omega may be applied to the individual factors as well as the overall test. A typical use of omega is to identify subscales of a total inventory. Some of that variability is due to the general factor of the inventory, some to the specific variance of each subscale. Thus, we can find a number of different omega estimates: what percentage of the variance of the items identified with each subfactor is actually due to the general factor. What variance is common but unique to the subfactor, and what is the total reliable variance of each subfactor. These results are reported in omega.group object and in the last few lines of the normal output.</p>
</blockquote>
<p>As noted, this is contained in <code>omega_result$omega.group</code>. For the unique factors, these sum very simply as total = general + group. The ones for unique factors pertain only to the loadings and part of the correlation matrix for those items specific to that factor. Take agreeableness for example, we are only concerned with the variance of those items. The ‘general’ part regards the loadings of <code>g</code> for the agreeableness items, the <code>group</code> part the loadings of the agreeableness items, and the ‘total’ is just their sum.</p>
<p>The first column, <code>g</code>, just regurgitates <img src="https://latex.codecogs.com/png.latex?%5Comega"> and <img src="https://latex.codecogs.com/png.latex?%5Comega_h"> from the beginning for the first two values, and adds yet another statistic, based only on the sum of variance attributable to each unique factor. Unlike the <img src="https://latex.codecogs.com/png.latex?%5Comega_%7Btotal%7D">, this calculation does not include off-loadings the unique factors have, only the items that are grouped with each factor. In pseudo-code:</p>
<pre><code>for (i in specific) {
 specific_var[i] = sum(specific[i]$loadings[specific_items[i]])^2)
}

value = sum(specific_var) / total_var</code></pre>
<p>That is the variance uniquely defined by the specific factors. Had it included all the loadings for each specific factor calculation, then <code>group + general = total</code> for <code>g</code> as well.</p>
</section>
</section>
<section id="unidimensionality" class="level3">
<h3 class="anchored" data-anchor-id="unidimensionality">Unidimensionality</h3>
<p>Revelle provides an ‘exploratory’ statistic of <em>unidimensionality</em>, or how well a set of variables may be explained by one construct. In practice, you may find multiple factors fit better, e.g.&nbsp;via BIC, but the resulting factors may be highly correlated, so you might still want to consider a single construct. Something like <span class="func" style="">unidim</span> will help make a decision on how viable using a sum score might be for regression or other models. It is explained in the help file as follows:</p>
<blockquote class="blockquote">
<p>The fit FF’ (model implied correlation matrix based on a one factor model) should be identical to the (observed) correlation matrix minus the uniquenesses. unidim is just the ratio of these two estimates. The higher it is, the more the evidence for unidimensionality.</p>
</blockquote>
<p>I’ll run it for both the case where there is only a single construct vs.&nbsp;two underlying constructs.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">unidim</span>(bfi[,<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;">5</span>])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
A measure of unidimensionality 
 Call: unidim(keys = bfi[, 1:5])

Unidimensionality index = 
       u      tau      con    alpha     av.r median.r      CFI      ECV 
    0.89     0.90     0.99     0.71     0.33     0.34     0.97     0.85 

unidim adjusted index reverses negatively scored items.
alpha    Based upon reverse scoring some items.
average and median  correlations are based upon reversed scored items</code></pre>
</div>
<div class="code-copy-outer-scaffold"><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;">unidim</span>(bfi_trim)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
A measure of unidimensionality 
 Call: unidim(keys = bfi_trim)

Unidimensionality index = 
       u      tau      con    alpha     av.r median.r      CFI      ECV 
    0.45     0.62     0.73     0.75     0.23     0.17     0.60     0.58 

unidim adjusted index reverses negatively scored items.
alpha    Based upon reverse scoring some items.
average and median  correlations are based upon reversed scored items</code></pre>
</div>
</div>
<p>The values reported are as follows. In general, you’d pay attention to the <code>adjusted</code> results that are based on items that are reverse scored if needed. If there are no reverse scored items (which you generally should be doing), then these adjusted metrics will be identical to the raw metrics.</p>
<ul>
<li><code>Raw Unidim</code>: The raw value of the unidimensional criterion</li>
<li><code>Adjusted</code>: The unidimensional criterion when items are keyed in positive direction.</li>
<li><code>Fit1</code>: The off diagonal fit from <span class="func" style="">fa</span>. (explained above)</li>
<li><code>alpha</code>: Standardized <img src="https://latex.codecogs.com/png.latex?%5Calpha"> of the keyed items (after appropriate reversals)</li>
<li><code>av.r</code>: The average inter-item correlation of the keyed items.</li>
<li><code>original model</code>: The ratio of the FF’ (model implied correlation matrix based on the loadings) model to the sum(R).</li>
<li><code>adjusted model</code>: The ratio of the FF’ model to the sum(R) when items are flipped.</li>
<li><code>raw.total</code>: sum(R - uniqueness)/sum(R)</li>
<li><code>adjusted total</code>: raw.total ratio with flipped items</li>
</ul>
</section>
<section id="mediate" class="level3">
<h3 class="anchored" data-anchor-id="mediate">Mediate</h3>
<p>The <span class="pack" style="">psych</span> makes even somewhat complicated mediation models about as easily conducted as they can be, assuming you are only dealing with fully observed (no latent) variables and linear models with continuous endogenous variables that are assumed to be normally distributed. Though the output should be straightforward if one understands basic regression as well as the basics of mediation, we demonstrate it here.</p>
<section id="initial-model" class="level4">
<h4 class="anchored" data-anchor-id="initial-model">Initial Model</h4>
<p>Garcia, Schmitt, Branscome, and Ellemers (2010) report data for 129 subjects on the effects of perceived sexism on anger and liking of women’s reactions to in-group members who protest discrimination. We will predict liking (how much the individual liked the target) while using protest (<code>prot2</code> yes or no) and sexism (a scale score based on multiple items) as predictors, and a scaled score of the appropriateness of the target’s response as the mediator (<code>respappr</code>).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">data</span>(GSBE)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># The Garcia et al data set; see ?GSBE for details</span></span>
<span id="cb30-2"></span>
<span id="cb30-3">model <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;">mediate</span>(</span>
<span id="cb30-4">  liking <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>  sexism <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> prot2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> (respappr),</span>
<span id="cb30-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data   =</span> Garcia,</span>
<span id="cb30-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n.iter =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>,</span>
<span id="cb30-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">plot   =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb30-8">)   </span></code></pre></div></div>
</div>
</section>
<section id="visual-results" class="level4">
<h4 class="anchored" data-anchor-id="visual-results">Visual Results</h4>
<p>To start, most of the output of <span class="pack" style="">psych</span> is straightforward if you understand what mediation is, as it follows the same depiction and even uses the same labels as most initial demonstrations of mediation I’ve come across. So if it’s confusing, you probably need to review what such models are attempting to accomplish. The visualization it automatically produces is even clearer for storytelling. I reserved plotting for display here so as to make it easier to compare to the printed output.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb31" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb31-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mediate.diagram</span>(model, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">digits =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://m-clark.github.io/posts/2020-04-10-psych-explained/index_files/figure-html/mediate-diagram-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>We see the original effects of <code>sexism</code> and <code>prot2</code> as <code>c</code>, and what they are after including the mediator <code>c'</code>, where the difference between those values is equivalent to <code>a * b</code>, i.e.&nbsp;the indirect effect (<code>a</code> is the coefficient from the predictor to mediator, <code>b</code> is from the mediator to the outcome). The rest are standard path/regression coefficients as well.</p>
</section>
<section id="statistical-results" class="level4">
<h4 class="anchored" data-anchor-id="statistical-results">Statistical Results</h4>
<p>Now we will just print the result.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">print</span>(model, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">digits =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
Mediation/Moderation Analysis 
Call: mediate(y = liking ~ sexism + prot2 + (respappr), data = Garcia, 
    n.iter = 500, plot = FALSE)

The DV (Y) was  liking . The IV (X) was  sexism prot2 . The mediating variable(s) =  respappr .

Total effect(c) of  sexism  on  liking  =  0.111   S.E. =  0.116  t  =  0.956  df=  126   with p =  0.341
Direct effect (c') of  sexism  on  liking  removing  respappr  =  0.096   S.E. =  0.104  t  =  0.923  df=  125   with p =  0.358
Indirect effect (ab) of  sexism  on  liking  through  respappr   =  0.015 
Mean bootstrapped indirect effect =  0.018  with standard error =  0.056  Lower CI =  -0.09    Upper CI =  0.129

Total effect(c) of  prot2  on  liking  =  0.471   S.E. =  0.195  t  =  2.417  df=  126   with p =  0.0171
Direct effect (c') of  prot2  on  liking  removing  respappr  =  -0.105   S.E. =  0.201  t  =  -0.522  df=  125   with p =  0.602
Indirect effect (ab) of  prot2  on  liking  through  respappr   =  0.576 
Mean bootstrapped indirect effect =  0.563  with standard error =  0.15  Lower CI =  0.306    Upper CI =  0.887
R = 0.501 R2 = 0.251   F = 13.967 on 3 and 125 DF   p-value:  1.903e-09 

 To see the longer output, specify short = FALSE in the print statement or ask for the summary</code></pre>
</div>
</div>
<p>The output simply shows the same results as the graph. The <span class="emph" style="">total effect</span> is the effect of a covariate on the outcome, without the mediator. For example, the effect of sexism on liking without the mediation is 0.111. We can reproduce it as follows. The statistical result is identical to the <code>lm</code> output.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">summary</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lm</span>(liking <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>  sexism <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> prot2, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> Garcia))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
Call:
lm(formula = liking ~ sexism + prot2, data = Garcia)

Residuals:
    Min      1Q  Median      3Q     Max 
-4.3857 -0.6246  0.0599  0.7754  1.7954 

Coefficients:
            Estimate Std. Error t value Pr(&gt;|t|)    
(Intercept)   4.7468     0.6110   7.768 2.41e-12 ***
sexism        0.1111     0.1162   0.956   0.3410    
prot2         0.4711     0.1949   2.417   0.0171 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.03 on 126 degrees of freedom
Multiple R-squared:  0.0523,    Adjusted R-squared:  0.03726 
F-statistic: 3.477 on 2 and 126 DF,  p-value: 0.03391</code></pre>
</div>
</div>
<p>The <span class="emph" style="">direct effect</span> is the effect of sexism with the mediator in the model. We can reproduce the effect here. However this version of the model printout currently has a bug where, after the coefficient, it is reporting SE t etc. from the intercept. If you do a <code>summary(model)</code>, as we will shortly, you’ll get the correct statistical test until it is fixed.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">summary</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lm</span>(liking <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>  sexism <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> prot2 <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> respappr, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">data =</span> Garcia))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
Call:
lm(formula = liking ~ sexism + prot2 + respappr, data = Garcia)

Residuals:
    Min      1Q  Median      3Q     Max 
-4.0210 -0.5337  0.0874  0.6591  2.6760 

Coefficients:
            Estimate Std. Error t value Pr(&gt;|t|)    
(Intercept)  3.26766    0.60281   5.421 2.94e-07 ***
sexism       0.09584    0.10379   0.923    0.358    
prot2       -0.10482    0.20065  -0.522    0.602    
respappr     0.40075    0.06958   5.760 6.18e-08 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.9193 on 125 degrees of freedom
Multiple R-squared:  0.2511,    Adjusted R-squared:  0.2331 
F-statistic: 13.97 on 3 and 125 DF,  p-value: 6.545e-08</code></pre>
</div>
</div>
<p>The <span class="emph" style="">indirect effect</span> coefficient is the product of the <code>a</code> and <code>b</code> paths: 0.038 * 0.401. Along with this, the bootstrapped interval estimate is provided (you can ignore the <code>mean bootstrapped effect</code>, which is equal to the effect with enough iterations). There is no p-value, but it’s not needed anyway for any of these results.</p>
<p>After that, the same results are provided for the <code>prot2</code> predictor. Finally, the <img src="https://latex.codecogs.com/png.latex?R%5E2"> and F test for the overall model are reported, which are identical to the <code>lm</code> summary results that include all effects. I would suggest reporting the adjusted <img src="https://latex.codecogs.com/png.latex?R%5E2"> from that instead.</p>
<p>A much cleaner result that incorporates the <code>lm</code> results we did can be obtained by summarizing instead of printing the fitted model. All of this output is available as elements of the model object itself.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><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;">summary</span>(model)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Call: mediate(y = liking ~ sexism + prot2 + (respappr), data = Garcia, 
    n.iter = 500, plot = FALSE)

Direct effect estimates (traditional regression)    (c') X + M on Y 
          liking   se     t  df     Prob
Intercept   3.27 0.60  5.42 125 2.94e-07
sexism      0.10 0.10  0.92 125 3.58e-01
prot2      -0.10 0.20 -0.52 125 6.02e-01
respappr    0.40 0.07  5.76 125 6.18e-08

R = 0.5 R2 = 0.25   F = 13.97 on 3 and 125 DF   p-value:  6.54e-08 

 Total effect estimates (c) (X on Y) 
          liking   se    t  df     Prob
Intercept   4.75 0.61 7.77 126 2.41e-12
sexism      0.11 0.12 0.96 126 3.41e-01
prot2       0.47 0.19 2.42 126 1.71e-02

 'a'  effect estimates (X on M) 
          respappr   se    t  df     Prob
Intercept     3.69 0.70 5.29 126 5.33e-07
sexism        0.04 0.13 0.29 126 7.75e-01
prot2         1.44 0.22 6.45 126 2.15e-09

 'b'  effect estimates (M on Y controlling for X) 
         liking   se    t  df     Prob
respappr    0.4 0.07 5.76 125 6.18e-08

 'ab'  effect estimates (through all  mediators)
       liking boot   sd lower upper
sexism   0.02 0.02 0.06 -0.09  0.13
prot2    0.58 0.56 0.15 -0.09  0.13</code></pre>
</div>
</div>
<p>If you are doing mediation with linear models only, you would be hard-pressed to find an easier tool to use than the <span class="pack" style="">psych</span> package. It can incorporate multiple mediators and so-called ‘moderated mediation’ as well. However, just because it is easy to do a mediation model, doesn’t mean you should.</p>
</section>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>The <span class="pack" style="">psych</span> package is very powerful and provides a lot of results from just a single line of code. However, the documentation, while excellent in general, fails to note many pieces of output, or clearly explain it, at least, not without consulting other references (which are provided). Hopefully this saves others some time when they use it. I may add some other functions to explain in time, so check back at some point.</p>


</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-reuse"><h2 class="anchored quarto-appendix-heading">Reuse</h2><div class="quarto-appendix-contents"><div><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></div></div></section><section class="quarto-appendix-contents" id="quarto-citation"><h2 class="anchored quarto-appendix-heading">Citation</h2><div><div class="quarto-appendix-secondary-label">BibTeX citation:</div><pre class="sourceCode code-with-copy quarto-appendix-bibtex"><code class="sourceCode bibtex">@online{clark2020,
  author = {Clark, Michael},
  title = {Factor {Analysis} with the Psych Package},
  date = {2020-04-10},
  url = {https://m-clark.github.io/posts/2020-04-10-psych-explained/},
  langid = {en}
}
</code></pre><div class="quarto-appendix-secondary-label">For attribution, please cite this work as:</div><div id="ref-clark2020" class="csl-entry quarto-appendix-citeas">
Clark, Michael. 2020. <span>“Factor Analysis with the Psych
Package.”</span> April 10. <a href="https://m-clark.github.io/posts/2020-04-10-psych-explained/">https://m-clark.github.io/posts/2020-04-10-psych-explained/</a>.
</div></div></section></div> ]]></description>
  <category>latent variables</category>
  <guid>https://m-clark.github.io/posts/2020-04-10-psych-explained/</guid>
  <pubDate>Fri, 10 Apr 2020 04:00:00 GMT</pubDate>
  <media:content url="https://m-clark.github.io/img/factor_analysis.png" medium="image" type="image/png" height="95" width="144"/>
</item>
</channel>
</rss>
