<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://diogoribeiro7.github.io/analytics-blog-jekyll/feed/tutorials.xml" rel="self" type="application/atom+xml" /><link href="https://diogoribeiro7.github.io/analytics-blog-jekyll/" rel="alternate" type="text/html" /><updated>2026-09-27T23:42:02+01:00</updated><id>https://diogoribeiro7.github.io/analytics-blog-jekyll/feed/tutorials.xml</id><title type="html">DataLog | Data Science &amp;amp; Research Theme | Tutorials</title><subtitle>DataLog is a clean and academic-inspired Jekyll theme crafted for data scientists, researchers, and technical writers who want to share reproducible analyses, research papers, tutorials, datasets, and project portfolios.</subtitle><author><name>Diogo Ribeiro</name><email>dfr@esmad.ipp.pt</email></author><entry><title type="html">Minimal Mistakes Front Matter, Rendered by DataLog</title><link href="https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2026/05/05/minimal-mistakes-front-matter-compatibility/" rel="alternate" type="text/html" title="Minimal Mistakes Front Matter, Rendered by DataLog" /><published>2026-05-05T00:00:00+01:00</published><updated>2026-05-05T00:00:00+01:00</updated><id>https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2026/05/05/minimal-mistakes-front-matter-compatibility</id><content type="html" xml:base="https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2026/05/05/minimal-mistakes-front-matter-compatibility/"><![CDATA[<p>This post's front matter is written the way the <a href="https://mmistakes.github.io/minimal-mistakes/">Minimal Mistakes</a> theme expects it, and none of it has been renamed for DataLog. The hero image above, the teaser on the home page cards, the title in the browser tab, the meta description, the wide body class and the editorial note below all come from Minimal Mistakes fields.</p>

<h2 id="what-was-mapped">What was mapped</h2>

<div class="content-table" role="region" tabindex="0" aria-label="Table 1"><table>
  <thead>
    <tr>
      <th>Minimal Mistakes field</th>
      <th>DataLog field</th>
      <th>Where it shows</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">header.overlay_image</code></td>
      <td><code class="language-plaintext highlighter-rouge">post_hero.image</code> with <code class="language-plaintext highlighter-rouge">post_hero.overlay: true</code></td>
      <td>The title sits over the image at the top of this page</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">header.overlay_filter</code></td>
      <td><code class="language-plaintext highlighter-rouge">post_hero.overlay_filter</code></td>
      <td>The darkening over the hero image</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">header.teaser</code></td>
      <td><code class="language-plaintext highlighter-rouge">teaser</code></td>
      <td>Thumbnail on the home page and related-post cards</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">header.og_image</code>, <code class="language-plaintext highlighter-rouge">header.twitter_image</code></td>
      <td><code class="language-plaintext highlighter-rouge">og_image</code>, <code class="language-plaintext highlighter-rouge">twitter_image</code></td>
      <td>Social sharing previews</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">seo_title</code></td>
      <td><code class="language-plaintext highlighter-rouge">&lt;title&gt;</code> and social titles</td>
      <td>The browser tab reads the SEO title, the heading reads the real one</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">seo_description</code></td>
      <td><code class="language-plaintext highlighter-rouge">description</code></td>
      <td>The meta description</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">classes: wide</code></td>
      <td>body class <code class="language-plaintext highlighter-rouge">wide</code></td>
      <td>Paragraphs use the full content width</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">subtitle</code></td>
      <td>subtitle under the title</td>
      <td>The line under the heading</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">why_this_exists</code>, <code class="language-plaintext highlighter-rouge">evidence</code>, <code class="language-plaintext highlighter-rouge">methodology</code>, <code class="language-plaintext highlighter-rouge">reviewed_at</code></td>
      <td>provenance note</td>
      <td>The editorial note above the article body</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">redirect_from</code></td>
      <td>redirect page</td>
      <td><code class="language-plaintext highlighter-rouge">/legacy/minimal-mistakes-post/</code> redirects here</td>
    </tr>
  </tbody>
</table></div>

<h2 id="what-is-ignored">What is ignored</h2>

<p><code class="language-plaintext highlighter-rouge">author_profile</code> controls the Minimal Mistakes sidebar, which DataLog does not have; DataLog shows the author card at the end of the post instead. <code class="language-plaintext highlighter-rouge">seo_type: article</code> is redundant, because DataLog already marks posts as articles for social cards and structured data.</p>

<h2 id="where-the-rules-live">Where the rules live</h2>

<p>The mapping is a single build hook in <code class="language-plaintext highlighter-rouge">_plugins/front_matter_compat.rb</code>. It only fills DataLog fields that are absent, so a post that sets <code class="language-plaintext highlighter-rouge">image</code> or <code class="language-plaintext highlighter-rouge">description</code> explicitly keeps those values. The full field table and the URL-preservation settings are in the <a href="https://github.com/DiogoRibeiro7/analytics-blog-jekyll/blob/develop/docs/migrating-from-minimal-mistakes.md">migration guide</a>.</p>]]></content><author><name>Diogo Ribeiro</name></author><category term="tutorials" /><category term="migration" /><category term="minimal-mistakes" /><category term="front-matter" /><summary type="html"><![CDATA[How DataLog reads Minimal Mistakes header images, teasers, SEO titles and descriptions, wide layouts and redirects without editing every post.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://diogoribeiro7.github.io/analytics-blog-jekyll/assets/img/social-card.png" /><media:content medium="image" url="https://diogoribeiro7.github.io/analytics-blog-jekyll/assets/img/social-card.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">SQL Analytics Guide for Reproducible Pipelines</title><link href="https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2024/02/10/sql-analytics-guide/" rel="alternate" type="text/html" title="SQL Analytics Guide for Reproducible Pipelines" /><published>2024-02-10T00:00:00+00:00</published><updated>2024-02-10T00:00:00+00:00</updated><id>https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2024/02/10/sql-analytics-guide</id><content type="html" xml:base="https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2024/02/10/sql-analytics-guide/"><![CDATA[<h2 id="modeling-philosophy">Modeling philosophy</h2>

<ul>
  <li>Separate staging, intermediate, and mart layers to isolate concerns.</li>
  <li>Document every model with <code class="language-plaintext highlighter-rouge">description</code> blocks to power dbt docs.</li>
  <li>Pair assertions with automated tests using <code class="language-plaintext highlighter-rouge">unique</code>, <code class="language-plaintext highlighter-rouge">not_null</code>, and <code class="language-plaintext highlighter-rouge">relationships</code>.</li>
</ul>

<h2 id="example-staging-model">Example staging model</h2>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight" tabindex="0"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="k">with</span> <span class="k">source</span> <span class="k">as</span> <span class="p">(</span>
    <span class="k">select</span> <span class="o">*</span>
    <span class="k">from</span> <span class="p">{{</span> <span class="k">source</span><span class="p">(</span><span class="s1">'stripe'</span><span class="p">,</span> <span class="s1">'charges'</span><span class="p">)</span> <span class="p">}}</span>
<span class="p">),</span>
<span class="n">renamed</span> <span class="k">as</span> <span class="p">(</span>
    <span class="k">select</span>
        <span class="n">id</span> <span class="k">as</span> <span class="n">charge_id</span><span class="p">,</span>
        <span class="n">customer_id</span><span class="p">,</span>
        <span class="n">amount</span> <span class="o">/</span> <span class="mi">100</span><span class="p">.</span><span class="mi">0</span> <span class="k">as</span> <span class="n">amount_eur</span><span class="p">,</span>
        <span class="n">created</span><span class="p">::</span><span class="nb">date</span> <span class="k">as</span> <span class="n">charge_date</span><span class="p">,</span>
        <span class="n">status</span>
    <span class="k">from</span> <span class="k">source</span>
<span class="p">)</span>
<span class="k">select</span> <span class="o">*</span> <span class="k">from</span> <span class="n">renamed</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="building-aggregate-marts">Building aggregate marts</h2>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight" tabindex="0"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="k">with</span> <span class="n">charges</span> <span class="k">as</span> <span class="p">(</span>
    <span class="k">select</span> <span class="o">*</span> <span class="k">from</span> <span class="p">{{</span> <span class="k">ref</span><span class="p">(</span><span class="s1">'stg_stripe_charges'</span><span class="p">)</span> <span class="p">}}</span>
<span class="p">),</span>
<span class="n">customers</span> <span class="k">as</span> <span class="p">(</span>
    <span class="k">select</span> <span class="o">*</span> <span class="k">from</span> <span class="p">{{</span> <span class="k">ref</span><span class="p">(</span><span class="s1">'dim_customers'</span><span class="p">)</span> <span class="p">}}</span>
<span class="p">)</span>
<span class="k">select</span>
    <span class="k">c</span><span class="p">.</span><span class="n">customer_id</span><span class="p">,</span>
    <span class="k">c</span><span class="p">.</span><span class="n">segment</span><span class="p">,</span>
    <span class="n">date_trunc</span><span class="p">(</span><span class="s1">'month'</span><span class="p">,</span> <span class="n">ch</span><span class="p">.</span><span class="n">charge_date</span><span class="p">)</span> <span class="k">as</span> <span class="n">charge_month</span><span class="p">,</span>
    <span class="k">sum</span><span class="p">(</span><span class="n">ch</span><span class="p">.</span><span class="n">amount_eur</span><span class="p">)</span> <span class="k">as</span> <span class="n">monthly_revenue</span><span class="p">,</span>
    <span class="n">count_if</span><span class="p">(</span><span class="n">ch</span><span class="p">.</span><span class="n">status</span> <span class="o">=</span> <span class="s1">'failed'</span><span class="p">)</span> <span class="k">as</span> <span class="n">failed_payments</span>
<span class="k">from</span> <span class="n">charges</span> <span class="n">ch</span>
<span class="k">join</span> <span class="n">customers</span> <span class="k">c</span> <span class="k">using</span> <span class="p">(</span><span class="n">customer_id</span><span class="p">)</span>
<span class="k">group</span> <span class="k">by</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="testing-critical-assumptions">Testing critical assumptions</h2>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight" tabindex="0"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="rouge-code"><pre><span class="na">version</span><span class="pi">:</span> <span class="m">2</span>
<span class="na">models</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">fct_billing_health</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Monthly</span><span class="nv"> </span><span class="s">revenue</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">failure</span><span class="nv"> </span><span class="s">counts</span><span class="nv"> </span><span class="s">per</span><span class="nv"> </span><span class="s">customer."</span>
    <span class="na">tests</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">unique</span><span class="pi">:</span>
          <span class="na">column_name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">customer_id</span><span class="nv"> </span><span class="s">||</span><span class="nv"> </span><span class="s">'-'</span><span class="nv"> </span><span class="s">||</span><span class="nv"> </span><span class="s">charge_month"</span>
      <span class="pi">-</span> <span class="na">not_null</span><span class="pi">:</span>
          <span class="na">column_name</span><span class="pi">:</span> <span class="s">monthly_revenue</span>
      <span class="pi">-</span> <span class="na">relationships</span><span class="pi">:</span>
          <span class="na">to</span><span class="pi">:</span> <span class="s">ref('dim_customers')</span>
          <span class="na">field</span><span class="pi">:</span> <span class="s">customer_id</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="automation-tips">Automation tips</h2>

<ol>
  <li>Schedule CI builds with <code class="language-plaintext highlighter-rouge">dbt-cloud</code> or GitHub Actions to run on each PR.</li>
  <li>Export lineage metadata to the technical search index for discoverability.</li>
  <li>Snapshot slowly changing dimensions using <code class="language-plaintext highlighter-rouge">dbt snapshot</code> for audit trails.</li>
</ol>

<p>Download the <a href="https://github.com/DiogoRibeiro7/warehouse-template">project template</a>
and explore the generated docs site to navigate dependencies visually.</p>]]></content><author><name>Diogo Ribeiro</name></author><category term="tutorials" /><category term="sql" /><category term="analytics-engineering" /><category term="dbt" /><summary type="html"><![CDATA[An end-to-end guide to crafting warehouse-ready SQL transformations with dbt, including window functions, CTE patterns, and automated quality checks.]]></summary></entry><entry><title type="html">R Exploratory Analysis of Urban Housing Markets</title><link href="https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2024/02/05/r-exploratory-analysis-housing/" rel="alternate" type="text/html" title="R Exploratory Analysis of Urban Housing Markets" /><published>2024-02-05T00:00:00+00:00</published><updated>2024-02-05T00:00:00+00:00</updated><id>https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2024/02/05/r-exploratory-analysis-housing</id><content type="html" xml:base="https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2024/02/05/r-exploratory-analysis-housing/"><![CDATA[<h2 id="project-setup">Project setup</h2>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight" tabindex="0"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="n">library</span><span class="p">(</span><span class="n">tidyverse</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">lubridate</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">scales</span><span class="p">)</span><span class="w">

</span><span class="n">housing</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">read_csv</span><span class="p">(</span><span class="s2">"data/housing_portugal.csv"</span><span class="p">)</span><span class="w">
</span><span class="n">glimpse</span><span class="p">(</span><span class="n">housing</span><span class="p">)</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Key checks before modeling:</p>

<ul>
  <li>Inspect missing values with <code class="language-plaintext highlighter-rouge">skimr::skim</code>.</li>
  <li>Validate coordinate reference systems if spatial joins are required.</li>
  <li>Record assumptions in an analysis log (see <code class="language-plaintext highlighter-rouge">/docs/analysis-playbook.md</code>).</li>
</ul>

<h2 id="feature-engineering">Feature engineering</h2>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight" tabindex="0"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="n">housing</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">housing</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
  </span><span class="n">mutate</span><span class="p">(</span><span class="w">
    </span><span class="n">price_per_m2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">price_eur</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">floor_area_m2</span><span class="p">,</span><span class="w">
    </span><span class="n">listing_month</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">floor_date</span><span class="p">(</span><span class="n">listing_date</span><span class="p">,</span><span class="w"> </span><span class="s2">"month"</span><span class="p">),</span><span class="w">
    </span><span class="n">energy_rating</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fct_explicit_na</span><span class="p">(</span><span class="n">energy_rating</span><span class="p">,</span><span class="w"> </span><span class="s2">"Unknown"</span><span class="p">),</span><span class="w">
    </span><span class="n">is_new_build</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">if_else</span><span class="p">(</span><span class="n">construction_year</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="m">2018</span><span class="p">,</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">,</span><span class="w"> </span><span class="kc">FALSE</span><span class="p">)</span><span class="w">
  </span><span class="p">)</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="visualizing-distributions">Visualizing distributions</h2>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight" tabindex="0"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="n">ggplot</span><span class="p">(</span><span class="n">housing</span><span class="p">,</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">price_per_m2</span><span class="p">,</span><span class="w"> </span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">property_type</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
  </span><span class="n">geom_histogram</span><span class="p">(</span><span class="n">binwidth</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">250</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
  </span><span class="n">scale_x_continuous</span><span class="p">(</span><span class="n">labels</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">label_dollar</span><span class="p">(</span><span class="n">prefix</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"€"</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
  </span><span class="n">facet_wrap</span><span class="p">(</span><span class="o">~</span><span class="n">property_type</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
  </span><span class="n">labs</span><span class="p">(</span><span class="w">
    </span><span class="n">title</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Distribution of price per square meter"</span><span class="p">,</span><span class="w">
    </span><span class="n">subtitle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Segmented by property type"</span><span class="p">,</span><span class="w">
    </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Price per m²"</span><span class="p">,</span><span class="w">
    </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Count"</span><span class="w">
  </span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
  </span><span class="n">theme_minimal</span><span class="p">(</span><span class="n">base_size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">14</span><span class="p">)</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="communicating-findings">Communicating findings</h2>

<ul>
  <li>Central Lisbon apartments average <strong>€5,100/m²</strong> with a right-skewed tail.</li>
  <li>New builds exhibit a 15% premium relative to comparable resale properties.</li>
  <li>Energy ratings remain missing for 32% of listings—prioritize data enrichment.</li>
</ul>

<h2 id="reproducibility-checklist">Reproducibility checklist</h2>

<ol>
  <li>Render the R Markdown document with <code class="language-plaintext highlighter-rouge">targets::tar_make()</code> to guarantee order.</li>
  <li>Publish companion notebooks via Netlify or GitHub Pages with <code class="language-plaintext highlighter-rouge">quarto publish</code>.</li>
  <li>Pin package versions using <code class="language-plaintext highlighter-rouge">renv::snapshot()</code> and commit the lockfile.</li>
</ol>

<p>Download the <a href="https://github.com/DiogoRibeiro7/urban-housing-eda">analysis repository</a>
or launch the interactive Observable notebook to explore alternative visual encodings.</p>]]></content><author><name>Diogo Ribeiro</name></author><category term="tutorials" /><category term="r" /><category term="exploratory-data-analysis" /><category term="ggplot2" /><summary type="html"><![CDATA[An R Markdown-inspired walkthrough of importing, transforming, and visualizing housing market data with tidyverse tools and reusable templates.]]></summary></entry><entry><title type="html">Python Data Wrangling Foundations</title><link href="https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2024/02/01/python-data-wrangling-foundations/" rel="alternate" type="text/html" title="Python Data Wrangling Foundations" /><published>2024-02-01T00:00:00+00:00</published><updated>2024-02-01T00:00:00+00:00</updated><id>https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2024/02/01/python-data-wrangling-foundations</id><content type="html" xml:base="https://diogoribeiro7.github.io/analytics-blog-jekyll/tutorials/2024/02/01/python-data-wrangling-foundations/"><![CDATA[<blockquote>
  <p>“Clean data is the foundation for every successful analysis.”</p>
</blockquote>

<h2 id="why-tidy-data-matters">Why tidy data matters</h2>

<ul>
  <li>Consistent column naming and typing enables reproducible pipelines.</li>
  <li>Explicit missing data handling prevents silent downstream errors.</li>
  <li>Vectorized operations in pandas deliver fast, readable transformations.</li>
</ul>

<h2 id="loading-and-inspecting-data">Loading and inspecting data</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight" tabindex="0"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="kn">import</span> <span class="n">pandas</span> <span class="k">as</span> <span class="n">pd</span>

<span class="k">def</span> <span class="nf">load_sales_data</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Load the monthly sales CSV and parse dates.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="n">pd</span><span class="p">.</span><span class="nf">read_csv</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">parse_dates</span><span class="o">=</span><span class="p">[</span><span class="sh">"</span><span class="s">order_date</span><span class="sh">"</span><span class="p">])</span>

<span class="n">sales</span> <span class="o">=</span> <span class="nf">load_sales_data</span><span class="p">(</span><span class="sh">"</span><span class="s">data/monthly_sales.csv</span><span class="sh">"</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">sales</span><span class="p">.</span><span class="nf">head</span><span class="p">())</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">load_sales_data</code> helper enforces date parsing and sets the tone for reusable
functions.</p>

<h2 id="cleaning-column-names">Cleaning column names</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight" tabindex="0"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="kn">import</span> <span class="n">janitor</span>

<span class="n">sales</span> <span class="o">=</span> <span class="n">janitor</span><span class="p">.</span><span class="nf">clean_names</span><span class="p">(</span><span class="n">sales</span><span class="p">)</span>
<span class="n">sales</span><span class="p">.</span><span class="n">columns</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">pyjanitor.clean_names</code> standardizes casing and spacing. Track these helpers in
<code class="language-plaintext highlighter-rouge">utils/cleaning.py</code> to share with teammates.</p>

<h2 id="handling-missing-values">Handling missing values</h2>

<ol>
  <li>Use <code class="language-plaintext highlighter-rouge">DataFrame.info()</code> to surface unexpected null columns.</li>
  <li>Apply domain-driven imputations when appropriate.</li>
  <li>Preserve the original column when imputing to maintain auditability.</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight" tabindex="0"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="kn">from</span> <span class="n">sklearn.impute</span> <span class="kn">import</span> <span class="n">SimpleImputer</span>
<span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>

<span class="n">imputer</span> <span class="o">=</span> <span class="nc">SimpleImputer</span><span class="p">(</span><span class="n">strategy</span><span class="o">=</span><span class="sh">"</span><span class="s">median</span><span class="sh">"</span><span class="p">)</span>
<span class="n">sales</span><span class="p">[</span><span class="sh">"</span><span class="s">discount_filled</span><span class="sh">"</span><span class="p">]</span> <span class="o">=</span> <span class="n">imputer</span><span class="p">.</span><span class="nf">fit_transform</span><span class="p">(</span><span class="n">sales</span><span class="p">[[</span><span class="sh">"</span><span class="s">discount</span><span class="sh">"</span><span class="p">]])</span>
<span class="n">sales</span><span class="p">[</span><span class="sh">"</span><span class="s">discount_was_missing</span><span class="sh">"</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="n">sales</span><span class="p">[</span><span class="sh">"</span><span class="s">discount</span><span class="sh">"</span><span class="p">].</span><span class="nf">isna</span><span class="p">(),</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="deriving-tidy-features">Deriving tidy features</h2>

<p>Create narrow columns that answer single analytical questions.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight" tabindex="0"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="n">sales</span> <span class="o">=</span> <span class="p">(</span>
    <span class="n">sales</span><span class="p">.</span><span class="nf">assign</span><span class="p">(</span>
        <span class="n">revenue</span><span class="o">=</span><span class="k">lambda</span> <span class="n">df</span><span class="p">:</span> <span class="n">df</span><span class="p">.</span><span class="n">quantity</span> <span class="o">*</span> <span class="n">df</span><span class="p">.</span><span class="n">unit_price</span><span class="p">,</span>
        <span class="n">order_month</span><span class="o">=</span><span class="k">lambda</span> <span class="n">df</span><span class="p">:</span> <span class="n">df</span><span class="p">.</span><span class="n">order_date</span><span class="p">.</span><span class="n">dt</span><span class="p">.</span><span class="nf">to_period</span><span class="p">(</span><span class="sh">"</span><span class="s">M</span><span class="sh">"</span><span class="p">),</span>
    <span class="p">)</span>
    <span class="p">.</span><span class="nf">query</span><span class="p">(</span><span class="sh">"</span><span class="s">status == </span><span class="sh">'</span><span class="s">completed</span><span class="sh">'"</span><span class="p">)</span>
    <span class="p">.</span><span class="nf">rename</span><span class="p">(</span><span class="n">columns</span><span class="o">=</span><span class="p">{</span><span class="sh">"</span><span class="s">customer_segment</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">segment</span><span class="sh">"</span><span class="p">})</span>
<span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h2 id="validating-assumptions-with-tests">Validating assumptions with tests</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight" tabindex="0"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="kn">import</span> <span class="n">pytest</span>

<span class="k">def</span> <span class="nf">test_only_completed_orders</span><span class="p">():</span>
    <span class="k">assert</span> <span class="n">sales</span><span class="p">.</span><span class="n">status</span><span class="p">.</span><span class="nf">unique</span><span class="p">().</span><span class="nf">tolist</span><span class="p">()</span> <span class="o">==</span> <span class="p">[</span><span class="sh">"</span><span class="s">completed</span><span class="sh">"</span><span class="p">]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Automated data tests catch regressions when upstream schemas drift.</p>

<h2 id="takeaways">Takeaways</h2>

<ul>
  <li>Encapsulate IO, cleaning, and feature engineering in composable functions.</li>
  <li>Version notebooks alongside unit tests to guard scientific integrity.</li>
  <li>Document design decisions inline so collaborators understand trade-offs.</li>
</ul>

<p>Open the companion notebook through Binder to explore the exercises hands-on.</p>]]></content><author><name>Diogo Ribeiro</name></author><category term="tutorials" /><category term="python" /><category term="pandas" /><category term="data-wrangling" /><summary type="html"><![CDATA[Step-by-step walkthrough of loading, cleaning, transforming, and validating datasets with pandas for analytics-ready pipelines.]]></summary></entry></feed>