<?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>xboard.dev</title>
<link>https://www.xboard.dev/</link>
<atom:link href="https://www.xboard.dev/index.xml" rel="self" type="application/rss+xml"/>
<description>Everything data and programming.</description>
<generator>quarto-1.7.32</generator>
<lastBuildDate>Thu, 27 Jul 2023 03:00:00 GMT</lastBuildDate>
<item>
  <title>Tip: set depends_on_past=True in Airflow when creating a forecasting model pipeline</title>
  <dc:creator>Flavio Regis de Arruda</dc:creator>
  <link>https://www.xboard.dev/posts/2023_07_27_tip_set_dependsonpast_in_airflow_when_creating_forecasting_model_pipeline/</link>
  <description><![CDATA[ 






<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>When creating forecasting model pipeline in Airflow set <code>depends_on_past=True</code>.</p>
</div>
</div>
<section id="why" class="level2">
<h2 class="anchored" data-anchor-id="why">Why?</h2>
<p>Forecasting models help us predict future data based on patterns and trends observed in historical data. These models output inherently <strong>depend on past</strong> observations/data, hence any deviation from the expected sequence can affect their accuracy.</p>
<p>One way to ensure the integrity of the sequence of data while creating forecasting models in Apache Airflow is to set the <code>depends_on_past</code> argument to ‘True’. This way each subsequent task in the DAG will only run once its preceding task has completed successfully. This approach guarantees that the forecasting model is fed with the correct inputs in the correct order and that the historical data is correctly sequenced.</p>
<p>If you don’t set <code>depends_on_past=True</code> and you have a problem with one of the partitions of the data used by your model, one of two things will happen in the following days:</p>
<ul>
<li><p>Worst case scenario: your workflow will run without any issues being reported. This is a sign that you forgot to add sensors to test the availability of historical data and, chances are, your features are using incomplete data, to say the least.</p></li>
<li><p>Alternatively, subsequent executions of your workflow will also fail, bombarding your on call colleague’s PagerDuty with messages. And when the problem is finally fixed, you still have to remember to clear and restart all the previous failed executions.</p></li>
</ul>
</section>
<section id="how" class="level2">
<h2 class="anchored" data-anchor-id="how">How?</h2>
<p>For a specific task, most probably a sensor:</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1">task <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SomeSensor(</span>
<span id="cb1-2">    task_id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'task'</span>,</span>
<span id="cb1-3">    depends_on_past<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,</span>
<span id="cb1-4">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ...</span></span>
<span id="cb1-5">)</span></code></pre></div>
<p>or in your dag <code>default_args</code> to enable <code>depends_on_past</code> for all your tasks</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1">default_args <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb2-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'depends_on_past'</span>: <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,</span>
<span id="cb2-3">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ...</span></span>
<span id="cb2-4">}</span>
<span id="cb2-5"></span>
<span id="cb2-6">dag <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DAG(</span>
<span id="cb2-7">    dag_id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"time_series_pipeline"</span>,</span>
<span id="cb2-8">    default_args<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>default_args,</span>
<span id="cb2-9">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ...</span></span>
<span id="cb2-10">)</span></code></pre></div>


</section>

 ]]></description>
  <category>airflow</category>
  <category>data engineering</category>
  <guid>https://www.xboard.dev/posts/2023_07_27_tip_set_dependsonpast_in_airflow_when_creating_forecasting_model_pipeline/</guid>
  <pubDate>Thu, 27 Jul 2023 03:00:00 GMT</pubDate>
  <media:content url="https://source.unsplash.com/Em2hPK55o8g" medium="image"/>
</item>
<item>
  <title>Using pip-tools to manage project dependencies in Python</title>
  <dc:creator>Flavio Regis de Arruda</dc:creator>
  <link>https://www.xboard.dev/posts/2023_07_20_using_pip_tools_to_manage_python_project_dependencies/</link>
  <description><![CDATA[ 






<section id="improve-your-python-dependency-management-with-pip-tools" class="level2">
<h2 class="anchored" data-anchor-id="improve-your-python-dependency-management-with-pip-tools">Improve Your Python Dependency Management with pip-tools</h2>
<p>As an engineer who loves to solve problems using Python and creates tens of projects by year, keeping track of different packages and their versions can be complex. I often have to test and deploy my projects in different environments (development/testing/production machines) and on different Cloud or PaaS providers and need to be sure that all of them will use exactly the same Python packages and versions as I have used in the development, to be sure no problems were introduced by an unexpected package upgrade.</p>
<p>A naive approach would be to install the packages you need using <code>pip</code> and at the end generate a <code>requirements.txt</code> file with</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip</span> freeze <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> requirements.txt</span></code></pre></div>
<p>to persist all dependencies (with their versions) that got installed.We can later install into an empty virtual environment using that requirements file gets us the same packages and versions.</p>
<p>But this approch is problematic beause is virtually impossible to know which packages are needed by our application and which were pulled in as dependencies:</p>
<ul>
<li><p>suppose I choose to switch from <code>pandas</code> to <code>polars</code> in my project. In that scenario, the <code>requirements.txt</code> file may have many <code>pandas</code> dependencies that are superfluous to <code>polars</code>. Unfortunately, we are uncertain of who they are.</p></li>
<li><p>if you need to upgrade some of the packages (i.e <code>Django</code> version from <code>3.2</code> to <code>4.2</code>), which <code>Django</code> dependencies need to be upgrated and to which version? Which new dependencies the new <code>Django</code> version have?</p></li>
</ul>
<p>That is why I use the <a href="https://pypi.org/project/pip-tools/" target="_blank">pip-tools</a> project to simplify the process of package dependency management. In this blog post, we will discuss what <code>pip-tools</code> does, the problem it solves and why developers should consider using it, and provide five examples using <code>pip-tools</code> for managing Python project dependencies. Additionally, we will explore some alternatives to <code>pip-tools</code>.</p>
</section>
<section id="what-is-pip-tools" class="level2">
<h2 class="anchored" data-anchor-id="what-is-pip-tools">What is pip-tools?</h2>
<p><code>pip-tools</code> is an open-source project created to simplify the requirements files management used in Python projects. It takes a project’s dependencies and recursively generates pinned version requirement files.</p>
<p>Moreover, <code>pip-tools</code> allows you to easily manage your project dependencies with minimum effort and ensures you have a reproducible development environment. It allows other developers that are working on the same project to have identical dependencies to yours, with no version conflicts.</p>
<p>This can help reduce time spent debugging issues related to package conflicts and ensure that code runs consistently across different environments.</p>
<ul>
<li>It streamlines the generation and maintenance of requirements files</li>
<li>It ensures that all packages are pinned to a specific version to avoid version conflicts</li>
<li>It provides an easier way to manage different environments, like production, development, and testing</li>
<li>It permits simple package updating and upgrading as new versions become available</li>
</ul>
</section>
<section id="example-of-using-pip-tools" class="level2">
<h2 class="anchored" data-anchor-id="example-of-using-pip-tools">Example of using <code>pip-tools</code></h2>
<p>Here are five examples of how developers can use p<code>pip-tools</code> to manage the package requirements of their Python projects:</p>
<section id="basic-usage-of-pip-tools-with-requirements-files" class="level3">
<h3 class="anchored" data-anchor-id="basic-usage-of-pip-tools-with-requirements-files">Basic usage of pip-tools with requirements files</h3>
<p>Developers can use pip-tools to manage their project dependencies by creating a <code>requirements.in</code> file with the required packages and their respective versions.</p>
<div id="lst-requirements.in" class="txt listing quarto-float quarto-figure quarto-figure-left anchored">
<figure class="quarto-float quarto-float-lst figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-lst" id="lst-requirements.in-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Listing&nbsp;1: requirements.in
</figcaption>
<div aria-describedby="lst-requirements.in-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode txt code-with-copy"><code class="sourceCode default"><span id="cb2-1">pandas&gt;=2.0</span>
<span id="cb2-2">scikit-learn</span>
<span id="cb2-3">xgboost==1.7.6</span></code></pre></div>
</div>
</figure>
</div>
<p>Developers can then run the following command to generate the required <code>requirements.txt</code> file:</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">$</span> pip-compile requirements.in</span></code></pre></div>
<p>This generates a pinned version requirement file with all the packages and their respective dependencies:</p>
<div id="lst-requirements.txt" class="txt listing quarto-float quarto-figure quarto-figure-left anchored">
<figure class="quarto-float quarto-float-lst figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-lst" id="lst-requirements.txt-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Listing&nbsp;2: Generated requirements.txt
</figcaption>
<div aria-describedby="lst-requirements.txt-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode txt code-with-copy"><code class="sourceCode default"><span id="cb4-1">#</span>
<span id="cb4-2"># This file is autogenerated by pip-compile with Python 3.10</span>
<span id="cb4-3"># by the following command:</span>
<span id="cb4-4">#</span>
<span id="cb4-5">#    pip-compile requirements.in</span>
<span id="cb4-6">#</span>
<span id="cb4-7">joblib==1.3.1</span>
<span id="cb4-8">    # via scikit-learn</span>
<span id="cb4-9">numpy==1.25.1</span>
<span id="cb4-10">    # via</span>
<span id="cb4-11">    #   pandas</span>
<span id="cb4-12">    #   scikit-learn</span>
<span id="cb4-13">    #   scipy</span>
<span id="cb4-14">    #   xgboost</span>
<span id="cb4-15">pandas==2.0.3</span>
<span id="cb4-16">    # via -r requirements.in</span>
<span id="cb4-17">python-dateutil==2.8.2</span>
<span id="cb4-18">    # via pandas</span>
<span id="cb4-19">pytz==2023.3</span>
<span id="cb4-20">    # via pandas</span>
<span id="cb4-21">scikit-learn==1.3.0</span>
<span id="cb4-22">    # via -r requirements.in</span>
<span id="cb4-23">scipy==1.11.1</span>
<span id="cb4-24">    # via</span>
<span id="cb4-25">    #   scikit-learn</span>
<span id="cb4-26">    #   xgboost</span>
<span id="cb4-27">six==1.16.0</span>
<span id="cb4-28">    # via python-dateutil</span>
<span id="cb4-29">threadpoolctl==3.2.0</span>
<span id="cb4-30">    # via scikit-learn</span>
<span id="cb4-31">tzdata==2023.3</span>
<span id="cb4-32">    # via pandas</span>
<span id="cb4-33">xgboost==1.7.6</span>
<span id="cb4-34">    # via -r requirements.in</span></code></pre></div>
</div>
</figure>
</div>
</section>
<section id="pip-tools-with-multiple-environments" class="level3">
<h3 class="anchored" data-anchor-id="pip-tools-with-multiple-environments">pip-tools with multiple environments</h3>
<p>We can define several files with libraries to use in multiple environments, such as development, production, and testing. We can create corresponding <code>dev-requirements.in</code>, <code>prod-requirements.in</code>, and <code>test-requirements.in</code> files and then use the following commands to generate their respective files:</p>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">$</span> pip-compile dev-requirements.in</span>
<span id="cb5-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">$</span> pip-compile prod-requirements.in</span>
<span id="cb5-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">$</span> pip-compile test-requirements.in</span></code></pre></div>
<p>These commands will generate <code>dev-requirements.txt</code>, <code>prod-requirements.txt</code>, and <code>test-requirements.txt</code> files with the corresponding dependencies.</p>
</section>
<section id="pip-tools-with-custom-package-indexes" class="level3">
<h3 class="anchored" data-anchor-id="pip-tools-with-custom-package-indexes">pip-tools with custom package indexes</h3>
<p>We can also use pip-tools with package indexes different from the official PyPI index. To do this, we can specify a custom index in their <code>requirements.in</code> file, like this:</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb6-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">--index-url</span> https://custompackageindex.com/</span>
<span id="cb6-2"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">django</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>=3.2.5</span></code></pre></div>
<p>Then, running <code>pip-compile requirements.in</code> will output a <code>requirements.txt</code> file with the packages pinned to versions on the custom package index.</p>
</section>
<section id="pip-tools-with-hash-dependencies" class="level3">
<h3 class="anchored" data-anchor-id="pip-tools-with-hash-dependencies">pip-tools with hash dependencies</h3>
<p>If you want to pin your dependencies to an specific binary wheel compilation hash (and not only to a package-version) you can use following command:</p>
<div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb7-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">$</span> pip-compile <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--generate-hashes</span> requirements.in</span></code></pre></div>
<p>This will add a hash value to each package in the requirements file, including the transitive dependencies. This is usefull to increase security as PyPI has “made the <a href="https://github.com/pypa/packaging-problems/issues/75#issuecomment-347739479" target="_blank">deliberate choice</a> to allow wheel files to be added to old releases”</p>
<details>
<summary>
Show <code>requirements.txt</code> file with generated hashes
</summary>
<div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode default code-with-copy"><code class="sourceCode default"><span id="cb8-1"></span>
<span id="cb8-2"># This file is autogenerated by pip-compile with Python 3.10</span>
<span id="cb8-3"># by the following command:</span>
<span id="cb8-4">#</span>
<span id="cb8-5">#    pip-compile --generate-hashes requirements.in</span>
<span id="cb8-6">#</span>
<span id="cb8-7">joblib==1.3.1 \</span>
<span id="cb8-8">    --hash=sha256:1f937906df65329ba98013dc9692fe22a4c5e4a648112de500508b18a21b41e3 \</span>
<span id="cb8-9">    --hash=sha256:89cf0529520e01b3de7ac7b74a8102c90d16d54c64b5dd98cafcd14307fdf915</span>
<span id="cb8-10">    # via scikit-learn</span>
<span id="cb8-11">numpy==1.25.1 \</span>
<span id="cb8-12">    --hash=sha256:012097b5b0d00a11070e8f2e261128c44157a8689f7dedcf35576e525893f4fe \</span>
<span id="cb8-13">    --hash=sha256:0d3fe3dd0506a28493d82dc3cf254be8cd0d26f4008a417385cbf1ae95b54004 \</span>
<span id="cb8-14">    --hash=sha256:0def91f8af6ec4bb94c370e38c575855bf1d0be8a8fbfba42ef9c073faf2cf19 \</span>
<span id="cb8-15">    --hash=sha256:1a180429394f81c7933634ae49b37b472d343cccb5bb0c4a575ac8bbc433722f \</span>
<span id="cb8-16">    --hash=sha256:1d5d3c68e443c90b38fdf8ef40e60e2538a27548b39b12b73132456847f4b631 \</span>
<span id="cb8-17">    --hash=sha256:20e1266411120a4f16fad8efa8e0454d21d00b8c7cee5b5ccad7565d95eb42dd \</span>
<span id="cb8-18">    --hash=sha256:247d3ffdd7775bdf191f848be8d49100495114c82c2bd134e8d5d075fb386a1c \</span>
<span id="cb8-19">    --hash=sha256:35a9527c977b924042170a0887de727cd84ff179e478481404c5dc66b4170009 \</span>
<span id="cb8-20">    --hash=sha256:38eb6548bb91c421261b4805dc44def9ca1a6eef6444ce35ad1669c0f1a3fc5d \</span>
<span id="cb8-21">    --hash=sha256:3d7abcdd85aea3e6cdddb59af2350c7ab1ed764397f8eec97a038ad244d2d105 \</span>
<span id="cb8-22">    --hash=sha256:41a56b70e8139884eccb2f733c2f7378af06c82304959e174f8e7370af112e09 \</span>
<span id="cb8-23">    --hash=sha256:4a90725800caeaa160732d6b31f3f843ebd45d6b5f3eec9e8cc287e30f2805bf \</span>
<span id="cb8-24">    --hash=sha256:6b82655dd8efeea69dbf85d00fca40013d7f503212bc5259056244961268b66e \</span>
<span id="cb8-25">    --hash=sha256:6c6c9261d21e617c6dc5eacba35cb68ec36bb72adcff0dee63f8fbc899362588 \</span>
<span id="cb8-26">    --hash=sha256:77d339465dff3eb33c701430bcb9c325b60354698340229e1dff97745e6b3efa \</span>
<span id="cb8-27">    --hash=sha256:791f409064d0a69dd20579345d852c59822c6aa087f23b07b1b4e28ff5880fcb \</span>
<span id="cb8-28">    --hash=sha256:9a3a9f3a61480cc086117b426a8bd86869c213fc4072e606f01c4e4b66eb92bf \</span>
<span id="cb8-29">    --hash=sha256:c1516db588987450b85595586605742879e50dcce923e8973f79529651545b57 \</span>
<span id="cb8-30">    --hash=sha256:c40571fe966393b212689aa17e32ed905924120737194b5d5c1b20b9ed0fb171 \</span>
<span id="cb8-31">    --hash=sha256:d412c1697c3853c6fc3cb9751b4915859c7afe6a277c2bf00acf287d56c4e625 \</span>
<span id="cb8-32">    --hash=sha256:d5154b1a25ec796b1aee12ac1b22f414f94752c5f94832f14d8d6c9ac40bcca6 \</span>
<span id="cb8-33">    --hash=sha256:d736b75c3f2cb96843a5c7f8d8ccc414768d34b0a75f466c05f3a739b406f10b \</span>
<span id="cb8-34">    --hash=sha256:e8f6049c4878cb16960fbbfb22105e49d13d752d4d8371b55110941fb3b17800 \</span>
<span id="cb8-35">    --hash=sha256:f76aebc3358ade9eacf9bc2bb8ae589863a4f911611694103af05346637df1b7 \</span>
<span id="cb8-36">    --hash=sha256:fd67b306320dcadea700a8f79b9e671e607f8696e98ec255915c0c6d6b818503</span>
<span id="cb8-37">    # via</span>
<span id="cb8-38">    #   pandas</span>
<span id="cb8-39">    #   scikit-learn</span>
<span id="cb8-40">    #   scipy</span>
<span id="cb8-41">    #   xgboost</span>
<span id="cb8-42">pandas==2.0.3 \</span>
<span id="cb8-43">    --hash=sha256:04dbdbaf2e4d46ca8da896e1805bc04eb85caa9a82e259e8eed00254d5e0c682 \</span>
<span id="cb8-44">    --hash=sha256:1168574b036cd8b93abc746171c9b4f1b83467438a5e45909fed645cf8692dbc \</span>
<span id="cb8-45">    --hash=sha256:1994c789bf12a7c5098277fb43836ce090f1073858c10f9220998ac74f37c69b \</span>
<span id="cb8-46">    --hash=sha256:258d3624b3ae734490e4d63c430256e716f488c4fcb7c8e9bde2d3aa46c29089 \</span>
<span id="cb8-47">    --hash=sha256:32fca2ee1b0d93dd71d979726b12b61faa06aeb93cf77468776287f41ff8fdc5 \</span>
<span id="cb8-48">    --hash=sha256:37673e3bdf1551b95bf5d4ce372b37770f9529743d2498032439371fc7b7eb26 \</span>
<span id="cb8-49">    --hash=sha256:3ef285093b4fe5058eefd756100a367f27029913760773c8bf1d2d8bebe5d210 \</span>
<span id="cb8-50">    --hash=sha256:5247fb1ba347c1261cbbf0fcfba4a3121fbb4029d95d9ef4dc45406620b25c8b \</span>
<span id="cb8-51">    --hash=sha256:5ec591c48e29226bcbb316e0c1e9423622bc7a4eaf1ef7c3c9fa1a3981f89641 \</span>
<span id="cb8-52">    --hash=sha256:694888a81198786f0e164ee3a581df7d505024fbb1f15202fc7db88a71d84ebd \</span>
<span id="cb8-53">    --hash=sha256:69d7f3884c95da3a31ef82b7618af5710dba95bb885ffab339aad925c3e8ce78 \</span>
<span id="cb8-54">    --hash=sha256:6a21ab5c89dcbd57f78d0ae16630b090eec626360085a4148693def5452d8a6b \</span>
<span id="cb8-55">    --hash=sha256:81af086f4543c9d8bb128328b5d32e9986e0c84d3ee673a2ac6fb57fd14f755e \</span>
<span id="cb8-56">    --hash=sha256:9e4da0d45e7f34c069fe4d522359df7d23badf83abc1d1cef398895822d11061 \</span>
<span id="cb8-57">    --hash=sha256:9eae3dc34fa1aa7772dd3fc60270d13ced7346fcbcfee017d3132ec625e23bb0 \</span>
<span id="cb8-58">    --hash=sha256:9ee1a69328d5c36c98d8e74db06f4ad518a1840e8ccb94a4ba86920986bb617e \</span>
<span id="cb8-59">    --hash=sha256:b084b91d8d66ab19f5bb3256cbd5ea661848338301940e17f4492b2ce0801fe8 \</span>
<span id="cb8-60">    --hash=sha256:b9cb1e14fdb546396b7e1b923ffaeeac24e4cedd14266c3497216dd4448e4f2d \</span>
<span id="cb8-61">    --hash=sha256:ba619e410a21d8c387a1ea6e8a0e49bb42216474436245718d7f2e88a2f8d7c0 \</span>
<span id="cb8-62">    --hash=sha256:c02f372a88e0d17f36d3093a644c73cfc1788e876a7c4bcb4020a77512e2043c \</span>
<span id="cb8-63">    --hash=sha256:ce0c6f76a0f1ba361551f3e6dceaff06bde7514a374aa43e33b588ec10420183 \</span>
<span id="cb8-64">    --hash=sha256:d9cd88488cceb7635aebb84809d087468eb33551097d600c6dad13602029c2df \</span>
<span id="cb8-65">    --hash=sha256:e4c7c9f27a4185304c7caf96dc7d91bc60bc162221152de697c98eb0b2648dd8 \</span>
<span id="cb8-66">    --hash=sha256:f167beed68918d62bffb6ec64f2e1d8a7d297a038f86d4aed056b9493fca407f \</span>
<span id="cb8-67">    --hash=sha256:f3421a7afb1a43f7e38e82e844e2bca9a6d793d66c1a7f9f0ff39a795bbc5e02</span>
<span id="cb8-68">    # via -r requirements.in</span>
<span id="cb8-69">python-dateutil==2.8.2 \</span>
<span id="cb8-70">    --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \</span>
<span id="cb8-71">    --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9</span>
<span id="cb8-72">    # via pandas</span>
<span id="cb8-73">pytz==2023.3 \</span>
<span id="cb8-74">    --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \</span>
<span id="cb8-75">    --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb</span>
<span id="cb8-76">    # via pandas</span>
<span id="cb8-77">scikit-learn==1.3.0 \</span>
<span id="cb8-78">    --hash=sha256:0e8102d5036e28d08ab47166b48c8d5e5810704daecf3a476a4282d562be9a28 \</span>
<span id="cb8-79">    --hash=sha256:151ac2bf65ccf363664a689b8beafc9e6aae36263db114b4ca06fbbbf827444a \</span>
<span id="cb8-80">    --hash=sha256:1d54fb9e6038284548072df22fd34777e434153f7ffac72c8596f2d6987110dd \</span>
<span id="cb8-81">    --hash=sha256:3a11936adbc379a6061ea32fa03338d4ca7248d86dd507c81e13af428a5bc1db \</span>
<span id="cb8-82">    --hash=sha256:436aaaae2c916ad16631142488e4c82f4296af2404f480e031d866863425d2a2 \</span>
<span id="cb8-83">    --hash=sha256:552fd1b6ee22900cf1780d7386a554bb96949e9a359999177cf30211e6b20df6 \</span>
<span id="cb8-84">    --hash=sha256:6a885a9edc9c0a341cab27ec4f8a6c58b35f3d449c9d2503a6fd23e06bbd4f6a \</span>
<span id="cb8-85">    --hash=sha256:7617164951c422747e7c32be4afa15d75ad8044f42e7d70d3e2e0429a50e6718 \</span>
<span id="cb8-86">    --hash=sha256:79970a6d759eb00a62266a31e2637d07d2d28446fca8079cf9afa7c07b0427f8 \</span>
<span id="cb8-87">    --hash=sha256:850a00b559e636b23901aabbe79b73dc604b4e4248ba9e2d6e72f95063765603 \</span>
<span id="cb8-88">    --hash=sha256:8be549886f5eda46436b6e555b0e4873b4f10aa21c07df45c4bc1735afbccd7a \</span>
<span id="cb8-89">    --hash=sha256:981287869e576d42c682cf7ca96af0c6ac544ed9316328fd0d9292795c742cf5 \</span>
<span id="cb8-90">    --hash=sha256:9877af9c6d1b15486e18a94101b742e9d0d2f343d35a634e337411ddb57783f3 \</span>
<span id="cb8-91">    --hash=sha256:998d38fcec96584deee1e79cd127469b3ad6fefd1ea6c2dfc54e8db367eb396b \</span>
<span id="cb8-92">    --hash=sha256:9d953531f5d9f00c90c34fa3b7d7cfb43ecff4c605dac9e4255a20b114a27369 \</span>
<span id="cb8-93">    --hash=sha256:ae80c08834a473d08a204d966982a62e11c976228d306a2648c575e3ead12111 \</span>
<span id="cb8-94">    --hash=sha256:c470f53cea065ff3d588050955c492793bb50c19a92923490d18fcb637f6383a \</span>
<span id="cb8-95">    --hash=sha256:c7e28d8fa47a0b30ae1bd7a079519dd852764e31708a7804da6cb6f8b36e3630 \</span>
<span id="cb8-96">    --hash=sha256:ded35e810438a527e17623ac6deae3b360134345b7c598175ab7741720d7ffa7 \</span>
<span id="cb8-97">    --hash=sha256:ee04835fb016e8062ee9fe9074aef9b82e430504e420bff51e3e5fffe72750ca \</span>
<span id="cb8-98">    --hash=sha256:fd6e2d7389542eae01077a1ee0318c4fec20c66c957f45c7aac0c6eb0fe3c612</span>
<span id="cb8-99">    # via -r requirements.in</span>
<span id="cb8-100">scipy==1.11.1 \</span>
<span id="cb8-101">    --hash=sha256:08d957ca82d3535b3b9ba6c8ff355d78fe975271874e2af267cb5add5bd78625 \</span>
<span id="cb8-102">    --hash=sha256:249cfa465c379c9bb2c20123001e151ff5e29b351cbb7f9c91587260602c58d0 \</span>
<span id="cb8-103">    --hash=sha256:366a6a937110d80dca4f63b3f5b00cc89d36f678b2d124a01067b154e692bab1 \</span>
<span id="cb8-104">    --hash=sha256:39154437654260a52871dfde852adf1b93b1d1bc5dc0ffa70068f16ec0be2624 \</span>
<span id="cb8-105">    --hash=sha256:396fae3f8c12ad14c5f3eb40499fd06a6fef8393a6baa352a652ecd51e74e029 \</span>
<span id="cb8-106">    --hash=sha256:3b9963798df1d8a52db41a6fc0e6fa65b1c60e85d73da27ae8bb754de4792481 \</span>
<span id="cb8-107">    --hash=sha256:3e8eb42db36526b130dfbc417609498a6192381abc1975b91e3eb238e0b41c1a \</span>
<span id="cb8-108">    --hash=sha256:512fdc18c65f76dadaca139348e525646d440220d8d05f6d21965b8d4466bccd \</span>
<span id="cb8-109">    --hash=sha256:aec8c62fbe52914f9cf28d846cf0401dd80ab80788bbab909434eb336ed07c04 \</span>
<span id="cb8-110">    --hash=sha256:b41a0f322b4eb51b078cb3441e950ad661ede490c3aca66edef66f4b37ab1877 \</span>
<span id="cb8-111">    --hash=sha256:b4bb943010203465ac81efa392e4645265077b4d9e99b66cf3ed33ae12254173 \</span>
<span id="cb8-112">    --hash=sha256:b588311875c58d1acd4ef17c983b9f1ab5391755a47c3d70b6bd503a45bfaf71 \</span>
<span id="cb8-113">    --hash=sha256:ba94eeef3c9caa4cea7b402a35bb02a5714ee1ee77eb98aca1eed4543beb0f4c \</span>
<span id="cb8-114">    --hash=sha256:be8c962a821957fdde8c4044efdab7a140c13294997a407eaee777acf63cbf0c \</span>
<span id="cb8-115">    --hash=sha256:cce154372f0ebe88556ed06d7b196e9c2e0c13080ecb58d0f35062dc7cc28b47 \</span>
<span id="cb8-116">    --hash=sha256:d51565560565a0307ed06fa0ec4c6f21ff094947d4844d6068ed04400c72d0c3 \</span>
<span id="cb8-117">    --hash=sha256:e866514bc2d660608447b6ba95c8900d591f2865c07cca0aa4f7ff3c4ca70f30 \</span>
<span id="cb8-118">    --hash=sha256:fb5b492fa035334fd249f0973cc79ecad8b09c604b42a127a677b45a9a3d4289 \</span>
<span id="cb8-119">    --hash=sha256:ffb28e3fa31b9c376d0fb1f74c1f13911c8c154a760312fbee87a21eb21efe31</span>
<span id="cb8-120">    # via</span>
<span id="cb8-121">    #   scikit-learn</span>
<span id="cb8-122">    #   xgboost</span>
<span id="cb8-123">six==1.16.0 \</span>
<span id="cb8-124">    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \</span>
<span id="cb8-125">    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254</span>
<span id="cb8-126">    # via python-dateutil</span>
<span id="cb8-127">threadpoolctl==3.2.0 \</span>
<span id="cb8-128">    --hash=sha256:2b7818516e423bdaebb97c723f86a7c6b0a83d3f3b0970328d66f4d9104dc032 \</span>
<span id="cb8-129">    --hash=sha256:c96a0ba3bdddeaca37dc4cc7344aafad41cdb8c313f74fdfe387a867bba93355</span>
<span id="cb8-130">    # via scikit-learn</span>
<span id="cb8-131">tzdata==2023.3 \</span>
<span id="cb8-132">    --hash=sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a \</span>
<span id="cb8-133">    --hash=sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda</span>
<span id="cb8-134">    # via pandas</span>
<span id="cb8-135">xgboost==1.7.6 \</span>
<span id="cb8-136">    --hash=sha256:127cf1f5e2ec25cd41429394c6719b87af1456ce583e89f0bffd35d02ad18bcb \</span>
<span id="cb8-137">    --hash=sha256:1c527554a400445e0c38186039ba1a00425dcdb4e40b37eed0e74cb39a159c47 \</span>
<span id="cb8-138">    --hash=sha256:281c3c6f4fbed2d36bf95cd02a641afa95e72e9abde70064056da5e76233e8df \</span>
<span id="cb8-139">    --hash=sha256:4c34675b4d2678c624ddde5d45361e7e16046923e362e4e609b88353e6b87124 \</span>
<span id="cb8-140">    --hash=sha256:59b4b366d2cafc7f645e87d897983a5b59be02876194b1d213bd8d8b811d8ce8 \</span>
<span id="cb8-141">    --hash=sha256:b1d5db49b199152d62bd9217c98760207d3de86d2b9d243260c573ffe638f80a</span>
<span id="cb8-142">    # via -r requirements.in</span>
<span id="cb8-143"></span></code></pre></div>
</details>
</section>
<section id="pip-tools-to-update-dependencies" class="level3">
<h3 class="anchored" data-anchor-id="pip-tools-to-update-dependencies">pip-tools to update dependencies</h3>
<p>Finally, pip-tools can also help developers manage package updates easily. They can run the following command to generate a <code>requirements.txt</code> file with the new versions of the packages:</p>
<div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb9-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">$</span> pip-compile <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--upgrade</span> requirements.in </span></code></pre></div>
<p>This command will identify the available updates and upgrade the packages listed in the requirements file.</p>
</section>
</section>
<section id="pip-sync" class="level2">
<h2 class="anchored" data-anchor-id="pip-sync">pip-sync</h2>
<p><code>pip-sync</code> is a tool provided by <code>pip-tools</code> that ensures your virtual environment only contains the packages you have explicitly listed in your <code>requirements.txt</code> file. This is useful because it prevents conflicts between versions of packages in your virtual environment and ensures you only install the packages necessary for your project removing any previously installed packages that are not needed anymore.</p>
<p>Using <code>pip-sync</code> is a good practice to ensure your project dependencies are isolated from other projects on your development machine. It prevents conflicts between different versions of packages, making your project more reliable and robust.</p>
<p>Once you have your <code>requirements.txt</code> file, run the command:</p>
<div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb10-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">$</span> pip-sync</span></code></pre></div>
<p>This command will install only the packages listed in <code>requirements.txt</code> and their dependencies, and remove any packages that are not listed. This ensures that you have an isolated environment with only the packages required by your project.</p>
<section id="example-replacing-pandas-with-polars" class="level3">
<h3 class="anchored" data-anchor-id="example-replacing-pandas-with-polars">Example: replacing pandas with polars</h3>
<p>If we decide to move from <code>pandas</code> to <code>polars</code> we update our requirement.in file:</p>
<div id="lst-requirements.in.polars" class="txt listing quarto-float quarto-figure quarto-figure-left anchored">
<figure class="quarto-float quarto-float-lst figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-lst" id="lst-requirements.in.polars-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Listing&nbsp;3: requirements.in after replacing pandas with polars
</figcaption>
<div aria-describedby="lst-requirements.in.polars-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode txt code-with-copy"><code class="sourceCode default"><span id="cb11-1">polars</span>
<span id="cb11-2">scikit-learn</span>
<span id="cb11-3">xgboost==1.7.6</span></code></pre></div>
</div>
</figure>
</div>
<p>and then run:</p>
<div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb12-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip-compile</span></span>
<span id="cb12-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip-sync</span></span></code></pre></div>
<p>we will observe <code>pip-sinc</code> doing its magic:</p>
<div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode txt code-with-copy"><code class="sourceCode default"><span id="cb13-1">Found existing installation: pandas 2.0.3</span>
<span id="cb13-2">Uninstalling pandas-2.0.3:</span>
<span id="cb13-3">  Successfully uninstalled pandas-2.0.3</span>
<span id="cb13-4">Found existing installation: python-dateutil 2.8.2</span>
<span id="cb13-5">Uninstalling python-dateutil-2.8.2:</span>
<span id="cb13-6">  Successfully uninstalled python-dateutil-2.8.2</span>
<span id="cb13-7">Found existing installation: pytz 2023.3</span>
<span id="cb13-8">Uninstalling pytz-2023.3:</span>
<span id="cb13-9">  Successfully uninstalled pytz-2023.3</span>
<span id="cb13-10">Found existing installation: six 1.16.0</span>
<span id="cb13-11">Uninstalling six-1.16.0:</span>
<span id="cb13-12">  Successfully uninstalled six-1.16.0</span>
<span id="cb13-13">Found existing installation: tzdata 2023.3</span>
<span id="cb13-14">Uninstalling tzdata-2023.3:</span>
<span id="cb13-15">  Successfully uninstalled tzdata-2023.3</span>
<span id="cb13-16">Collecting polars==0.18.9 (from -r /tmp/tmpwq_lrber (line 1))</span>
<span id="cb13-17">  Obtaining dependency information for polars==0.18.9 from https://files.pythonhosted.org/packages/32/b7/bb1faf1741235f1147408322d1cd845e29d195e2e4dc636a3dea8b4ea119/polars-0.18.9-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata</span>
<span id="cb13-18">  Using cached polars-0.18.9-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (14 kB)</span>
<span id="cb13-19">Using cached polars-0.18.9-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (19.3 MB)</span>
<span id="cb13-20">Installing collected packages: polars</span>
<span id="cb13-21">Successfully installed polars-0.18.9</span></code></pre></div>
<p>Notice how it removed all packages required only by <code>pandas</code> (see Listing&nbsp;2) and then installed <code>polars</code>.</p>
</section>
</section>
<section id="alternatives-to-pip-tools" class="level2">
<h2 class="anchored" data-anchor-id="alternatives-to-pip-tools">Alternatives to pip-tools</h2>
<p>While pip-tools is a popular and powerful tool for managing dependencies, developers can also use alternatives such as <a href="https://python-poetry.org/" target="_blank">Poetry</a>, <a href="https://pipenv.pypa.io/" target="_blank">Pipenv</a>, <a href="https://docs.conda.io/en/latest/" target="_blank">conda</a>, and <a href="https://setuptools.pypa.io/en/latest/" target="_blank">setuptools</a>. These tools all have slightly different approaches to the problem of managing package dependencies in Python projects but <code>pip-tools</code> has the advantage of being simpler and more lightweight while for instance <code>poetry</code> is preferable if you also want a more complete set of features for managing not only package dependencies, but also virtual environments, package building, and publishing.</p>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>pip-tools provides developers with an elegant and straightforward way to manage package dependencies in their Python projects. With its advantages such as generating pinned versions, managing multiple environments, and identifying available package updates, it simplifies the work of maintaining Python projects. By using pip-tools with different commands like <code>pip-compile</code> and <code>pip-sync</code>, developers can effectively solve the problem of managing their project dependencies.</p>


</section>

 ]]></description>
  <category>software development</category>
  <category>tools</category>
  <category>python</category>
  <guid>https://www.xboard.dev/posts/2023_07_20_using_pip_tools_to_manage_python_project_dependencies/</guid>
  <pubDate>Thu, 20 Jul 2023 03:00:00 GMT</pubDate>
  <media:content url="https://source.unsplash.com/s8OO2-t-HmQ" medium="image"/>
</item>
<item>
  <title>Migrating my blog from fastpages to Quarto</title>
  <dc:creator>Flavio Regis de Arruda</dc:creator>
  <link>https://www.xboard.dev/posts/2023_07_17_migrating_from_fastpages_to_quarto/</link>
  <description><![CDATA[ 






<section id="why-migrate" class="level2">
<h2 class="anchored" data-anchor-id="why-migrate">Why migrate?</h2>
<p>In a <a href="https://forums.fast.ai/t/fastpages-deprecating-fastpages-in-favor-of-quarto/99095" target="_blank">post published on September 3, 2022</a>, <a href="https://hamel.dev/" target="_blank">Hamel Husain</a> announced that he has rebuilt <a href="https://nbdev.fast.ai/" target="_blank">nbdev</a> on top of <a href="https://quarto.org" target="_blank">Quarto</a>. In the blog post, he explained that there have been new pieces of technology like <a href="https://jupyterbook.org/" target="_blank">Jupyter Book</a> and <a href="https://quarto.org" target="_blank">Quarto</a>, which are both fabulous. Husain explained that he ended up using Quarto for nbdev, because of its shared vision with nbdev and the fantastic ongoing support from <a href="https://www.rstudio.com/authors/j.j.-allaire/" target="_blank">JJ Allaire</a> and the rest of the <a href="https://posit.co/" target="_blank">Posit</a> team. He also recommended that people trying to blog with notebooks should be using Quarto, instead of <a href="https://github.com/fastai/fastpages" target="_blank">Fastpages</a>.</p>
</section>
<section id="what-is-quarto" class="level2">
<h2 class="anchored" data-anchor-id="what-is-quarto">What is Quarto?</h2>
<p><a href="https://quarto.org" target="_blank">Quarto</a> is an open-source, web-based platform designed to simplify the creation and publication of scientific documents, including data-driven reports, technical articles, and more, with features such as:</p>
<ul>
<li>Compatibility with a wide range of programming languages, including R, Python, and Julia;</li>
<li>Integration with popular web publishing platforms such as GitHub pages, Netlify among <a href="https://quarto.org/docs/publishing/" target="_blank">others</a>;</li>
<li>Support for a broad range of document outputs, including LaTeX, PDF, and HTML;</li>
<li>Extensive customizability with built-in templates and reusable components; and</li>
<li>Built-in support for code snippets and data visualizations.</li>
</ul>
</section>
<section id="installing-quarto" class="level2">
<h2 class="anchored" data-anchor-id="installing-quarto">Installing Quarto</h2>
<p>Go to the <a href="https://quarto.org/docs/get-started/">get started</a> page on the quarto website to download the installer file. I’m on Ubuntu, so for me that’s a .deb file. I install it from the command line:</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sudo</span> dpkg <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-i</span> quarto-1.3.433-linux-amd64.deb</span></code></pre></div>
<p>Create my blog project, called <code>quarto-blog</code>:</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb2-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">quarto</span> create-project quarto-blog <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--type</span> website:blog</span></code></pre></div>
<p>then enter the project and preview it:</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">cd</span> quarto-blog/</span>
<span id="cb3-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">quarto</span> preview quarto-blog</span></code></pre></div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://www.xboard.dev/posts/2023_07_17_migrating_from_fastpages_to_quarto/images/default-quarto-screen.png" class="img-fluid figure-img"></p>
<figcaption>Generated quarto blog preview</figcaption>
</figure>
</div>
</section>
<section id="migrating-fastpagess-posts-to-quarto" class="level2">
<h2 class="anchored" data-anchor-id="migrating-fastpagess-posts-to-quarto">Migrating fastpages’s posts to Quarto</h2>
<p>Follow instructions in nbdev’s <a href="https://nbdev.fast.ai/tutorials/blogging.html#migrating-from-fastpages" target="_blank">Migrating from Fastpages</a> tutorial.</p>
<p>In my case:</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">cd</span> quarto-blog</span>
<span id="cb4-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cp</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-r</span> ../fastpages-blog/_notebooks/<span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">*</span> posts</span>
<span id="cb4-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cp</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-r</span> ../fastpages-blog/_posts/<span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">*</span> posts</span>
<span id="cb4-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cp</span> ../fastpages-blog/images/<span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">*</span> posts</span>
<span id="cb4-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cp</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-r</span> ../fastpages-blog/images/copied_from_nb/<span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">*</span> posts</span>
<span id="cb4-6"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">nbdev_migrate</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--path</span> posts</span></code></pre></div>
</section>
<section id="setup-general-blog-configuration" class="level2">
<h2 class="anchored" data-anchor-id="setup-general-blog-configuration">Setup general blog configuration</h2>
<p>Rename blog title, description and add <code>favicon</code></p>
<p>Edited section website in file <code>_quarto.yml</code> updating title and description and then adding site-url, favicon and google analytics configuration:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>_quarto.yml</strong></pre>
</div>
<div class="sourceCode" id="cb5" data-filename="_quarto.yml" style="background: #f1f3f5;"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">website</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb5-2"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">title</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xboard.dev"</span></span>
<span id="cb5-3"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">favicon</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> favicon.ico</span></span>
<span id="cb5-4"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">site-url</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> https://xboard.dev</span></span>
<span id="cb5-5"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">description</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Everything data and programming."</span></span>
<span id="cb5-6"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">google-analytics</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"G-5FL5R0TTQ6"</span></span></code></pre></div>
</div>
<section id="setup-navigation-menu-and-footer" class="level3">
<h3 class="anchored" data-anchor-id="setup-navigation-menu-and-footer">Setup navigation menu and footer</h3>
<p>Maintained About page and added github, twitter and rss buttons in the right section of the navigation bar and centered content license in the footer.</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>_quarto.yml</strong></pre>
</div>
<div class="sourceCode" id="cb6" data-filename="_quarto.yml" style="background: #f1f3f5;"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">website</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb6-2"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">navbar</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb6-3"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">right</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb6-4"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> about.qmd</span></span>
<span id="cb6-5"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">icon</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> github</span></span>
<span id="cb6-6"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">href</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> https://github.com/xboard</span></span>
<span id="cb6-7"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">icon</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> twitter</span></span>
<span id="cb6-8"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">href</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> https://twitter.com/xboard_</span></span>
<span id="cb6-9"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">icon</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> rss</span></span>
<span id="cb6-10"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">href</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> index.xml</span></span>
<span id="cb6-11"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page-footer</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb6-12"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">    center</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">: </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">|</span></span>
<span id="cb6-13">      Made with Data, ❤️, 🐍 and [Quarto](https://quarto.org). License: [CC BY-SA 2.0](https://creativecommons.org/licenses/by-sa/2.0/).</span></code></pre></div>
</div>
</section>
<section id="setup-social-metadata" class="level3">
<h3 class="anchored" data-anchor-id="setup-social-metadata">Setup social metadata</h3>
<p>To enables richer sharing of links to articles on the web improving the previews of my content when a link to it is pasted into applications like Twitter, Slack, Discord, Facebook, Linkedin, and more.</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>_quarto.yml</strong></pre>
</div>
<div class="sourceCode" id="cb7" data-filename="_quarto.yml" style="background: #f1f3f5;"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">website</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb7-2"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">twitter-card</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb7-3"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">creator</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"@xboard_"</span></span>
<span id="cb7-4"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">card-style</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> summary_large_image</span></span>
<span id="cb7-5"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">open-graph</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">true</span></span></code></pre></div>
</div>
</section>
</section>
<section id="setup-themes-for-light-and-dark-mode" class="level2">
<h2 class="anchored" data-anchor-id="setup-themes-for-light-and-dark-mode">Setup themes for light and dark mode</h2>
<p>After playing a bit with some of the default themes available I have chosen litera and superhero for light and dark modes respectively.</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>_quarto.yml</strong></pre>
</div>
<div class="sourceCode" id="cb8" data-filename="_quarto.yml" style="background: #f1f3f5;"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb8-2"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">light</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> litera</span></span>
<span id="cb8-3"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dark</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> superhero</span></span>
<span id="cb8-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">css</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> styles.css</span></span></code></pre></div>
</div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://www.xboard.dev/posts/2023_07_17_migrating_from_fastpages_to_quarto/images/themed-screen-part1.png" class="img-fluid figure-img"></p>
<figcaption>Light mode with litera theme</figcaption>
</figure>
</div>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://www.xboard.dev/posts/2023_07_17_migrating_from_fastpages_to_quarto/images/themed-screen-dark_mode.png" class="img-fluid figure-img"></p>
<figcaption>Dark mode with superhero theme</figcaption>
</figure>
</div>
</section>
<section id="adding-a-robots.txt-policy-file" class="level2">
<h2 class="anchored" data-anchor-id="adding-a-robots.txt-policy-file">Adding a <code>robots.txt</code> policy file</h2>
<p>My final <code>robots.txt</code> file ended up as below:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>robots.txt</strong></pre>
</div>
<div class="sourceCode" id="cb9" data-filename="robots.txt" style="background: #f1f3f5;"><pre class="sourceCode txt code-with-copy"><code class="sourceCode default"><span id="cb9-1">User-Agent: *</span>
<span id="cb9-2">Allow: /</span>
<span id="cb9-3"></span>
<span id="cb9-4"></span>
<span id="cb9-5">User-agent: GPTBot</span>
<span id="cb9-6">Disallow: /</span>
<span id="cb9-7"></span>
<span id="cb9-8"></span>
<span id="cb9-9">User-agent: ChatGPT-User</span>
<span id="cb9-10">Disallow: /</span>
<span id="cb9-11"></span>
<span id="cb9-12">Sitemap: https://www.xboard.dev/sitemap.xml</span></code></pre></div>
</div>
<p>It advise Open AI to not copy my site into their text database product and provide a reference to where other crawlers can find my generated sitemap.</p>
</section>
<section id="adding-canonical-tag-into-the-head-section" class="level2">
<h2 class="anchored" data-anchor-id="adding-canonical-tag-into-the-head-section">Adding <code>canonical</code> tag into the <code>&lt;head&gt;</code> section</h2>
<p>I have followed <a href="https://github.com/quarto-dev/quarto-cli/discussions/3976#discussioncomment-6376014" target="_blank">this post</a> from <a href="https://github.com/mcb00" target="_blank">Matt Bowers</a> adding the following python script:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>add-canonicals.py</strong></pre>
</div>
<div class="sourceCode" id="cb10" data-filename="add-canonicals.py" style="background: #f1f3f5;"><pre class="sourceCode py code-with-copy"><code class="sourceCode python"><span id="cb10-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""</span></span>
<span id="cb10-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">This script adds canonical url tags to pages in a Quarto website.</span></span>
<span id="cb10-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">Place the script in the root of the project and run it post render.</span></span>
<span id="cb10-4"></span>
<span id="cb10-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">author: Matt Bowers - https://github.com/mcb00</span></span>
<span id="cb10-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">from https://github.com/quarto-dev/quarto-cli/discussions/3976#discussioncomment-6376014</span></span>
<span id="cb10-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">"""</span></span>
<span id="cb10-8"></span>
<span id="cb10-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> xml.dom.minidom <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> parse</span>
<span id="cb10-10"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> urllib.parse <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> urlparse</span>
<span id="cb10-11"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> warnings</span>
<span id="cb10-12"></span>
<span id="cb10-13">site_dir <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'_site'</span></span>
<span id="cb10-14">sitemap_file <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'sitemap.xml'</span></span>
<span id="cb10-15"></span>
<span id="cb10-16">document <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> parse(site_dir <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'/'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> sitemap_file)</span>
<span id="cb10-17">locs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> document.getElementsByTagName(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'loc'</span>)</span>
<span id="cb10-18">urls <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [l.firstChild.nodeValue <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> locs]</span>
<span id="cb10-19"></span>
<span id="cb10-20"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> url <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> urls:</span>
<span id="cb10-21">    </span>
<span id="cb10-22">    path <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> site_dir <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> urlparse(url).path</span>
<span id="cb10-23">    canonical_tag <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'&lt;link rel="canonical" href="</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>url<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;">" /&gt;'</span></span>
<span id="cb10-24"></span>
<span id="cb10-25">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Read in the file</span></span>
<span id="cb10-26">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">with</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">open</span>(path, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>) <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">file</span> :</span>
<span id="cb10-27">      filedata <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;">file</span>.read()</span>
<span id="cb10-28"></span>
<span id="cb10-29">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> filedata.<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;">'&lt;link rel="canonical"'</span>):</span>
<span id="cb10-30">        warnings.warn(<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>path<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;"> already contains canonical tag. Skipping this file.'</span>)</span>
<span id="cb10-31">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span>:</span>
<span id="cb10-32">        <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>path<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;"> adding canonical tag.'</span>)</span>
<span id="cb10-33">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Replace the target string</span></span>
<span id="cb10-34">        filedata <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> filedata.replace(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'&lt;/head&gt;'</span>, canonical_tag <span 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;">&lt;/head&gt;'</span>)</span>
<span id="cb10-35"></span>
<span id="cb10-36">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Write the file out again</span></span>
<span id="cb10-37">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">with</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">open</span>(path, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'w'</span>) <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">file</span>:</span>
<span id="cb10-38">          <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">file</span>.write(filedata)</span></code></pre></div>
</div>
<p>and them add a <code>post-render</code> configuration pointing to this script in my project:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>_quarto.yml</strong></pre>
</div>
<div class="sourceCode" id="cb11" data-filename="_quarto.yml" style="background: #f1f3f5;"><pre class="sourceCode yml code-with-copy"><code class="sourceCode yaml"><span id="cb11-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb11-2"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">post-render</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb11-3"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"python add-canonicals.py"</span></span></code></pre></div>
</div>
</section>
<section id="gitgithub" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="gitgithub">Git/Github</h2>
<section id="create-.gitignore-file" class="level3">
<h3 class="anchored" data-anchor-id="create-.gitignore-file">Create <code>.gitignore</code> file</h3>
<p>Created <code>.gitignore</code> file with the following content:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>.gitignore</strong></pre>
</div>
<div class="sourceCode" id="cb12" data-filename=".gitignore" style="background: #f1f3f5;"><pre class="sourceCode txt code-with-copy"><code class="sourceCode default"><span id="cb12-1">/.quarto/</span>
<span id="cb12-2">/_site/</span>
<span id="cb12-3">/_book/</span>
<span id="cb12-4">/_freeze/</span>
<span id="cb12-5">.venv/</span></code></pre></div>
</div>
</section>
<section id="initialize-git-and-upload-to-repository-in-github" class="level3">
<h3 class="anchored" data-anchor-id="initialize-git-and-upload-to-repository-in-github">Initialize Git and upload to repository in Github</h3>
<p>Initialize local repository:</p>
<div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb13-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">git</span> init</span>
<span id="cb13-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">git</span> add .</span>
<span id="cb13-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">git</span> commit <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-m</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Migrated blog: first commit"</span></span></code></pre></div>
<p>Then go to <a href="https://github.com/" target="_blank">Github</a> and create a new public repository named <code>quarto-blog</code> and in your local repository directory type in the terminal:</p>
<div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb14-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">git</span> remote add origin https://github.com/xboard/quarto-blog.git</span>
<span id="cb14-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">git</span> push <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-u</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-f</span> origin master</span></code></pre></div>
</section>
<section id="setup-github-pages" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="setup-github-pages">Setup github pages</h3>
<p>I have followed this <a href="hhttps://quarto.org/docs/publishing/github-pages.html#publish-command" target="_blank">article</a> from the official quarto documentation on how to publish you content to a gh-pages branch.</p>

<div class="no-row-height column-margin column-container"><div class="">
<p>My old blog was running in github-pages and I want to keep using it.</p>
</div></div></section>
<section id="add-custom-domain-to-github-pages" class="level3">
<h3 class="anchored" data-anchor-id="add-custom-domain-to-github-pages">Add custom domain to github pages</h3>
<p>First remove the domain in repository <a href="https://github.com/xboard/fastpages-blog" target="_blank">fastpages-blog</a></p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://www.xboard.dev/posts/2023_07_17_migrating_from_fastpages_to_quarto/images/remove_domain_from_old_repo.png" class="img-fluid figure-img"></p>
<figcaption>Remove domain from old blog repository</figcaption>
</figure>
</div>
<p>then add domain to <a href="https://github.com/xboard/quarto-blog" target="_blank">quarto-blog repository</a> github page.</p>
</section>
<section id="publish-to-github-pages" class="level3">
<h3 class="anchored" data-anchor-id="publish-to-github-pages">Publish to github pages</h3>
<p>Just type in project root:</p>
<div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb15-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">quarto</span> publish gh-pages <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--no-prompt</span></span></code></pre></div>
<p>This will render your blog’s html in folder <code>_site</code> and publish its content into github pages. The <code>--no-prompt</code> option prevents it from asking for confirmation.</p>
<p>After the publish command succeeds deploying to github-pages it opens the browser to view your blog.</p>
</section>
</section>
<section id="creating-condas-environment" class="level2">
<h2 class="anchored" data-anchor-id="creating-condas-environment">Creating Conda’s environment</h2>
<p>Quarto supports executable Python code blocks within markdown. This allows you to create fully reproducible documents and reports—the Python code required to produce your output is part of the document itself, and is automatically re-run whenever the document is rendered.</p>
<p>Therefore it is crucial to have a reproducible Python execution environment and for such I have chosen <a href="https://docs.conda.io/en/latest/miniconda.html" target="_blank">Miniconda</a>. This are the steps I did to create my virtual environment and to save its configuration in github.</p>
<ol type="1">
<li>Create and activate the environment</li>
</ol>
<div class="sourceCode" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb16-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">conda</span> create <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-n</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'quarto_env'</span></span>
<span id="cb16-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">conda</span> activate quarto_env</span></code></pre></div>
<ol start="2" type="1">
<li>Install data-science libraries</li>
</ol>
<div class="sourceCode" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb17-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">conda</span> install pandas seaborn matplotlib plotly pip scrapy statsmodels jupyter jupyterlab xgboost scikit-learn seaborn lightgbm <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pymc&gt;=5"</span> jax<span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">cpu</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> tsfresh sktime prophet gradio plotly  scipy statsmodels arviz xarray pytorch fastai  streamlit lime shap interpret yellowbrick pypdf langchain accelerate bitsandbytes transformers scrapy  </span></code></pre></div>
<ol start="3" type="1">
<li>Export all libraries installed in environment to <code>environment.yml</code> file</li>
</ol>
<div class="sourceCode" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb18-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">conda</span> env export <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--name</span> quarto_env <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--file</span> environment.yml</span></code></pre></div>
<ol start="4" type="1">
<li>Add and push to github</li>
</ol>
<div class="sourceCode" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb19-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">git</span> add environment.yml</span>
<span id="cb19-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">git</span> commit <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-m</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Add conda environment.yml'</span></span></code></pre></div>
<p>You can see the generated <code>environment.yml</code> file in github <a href="https://github.com/xboard/quarto-blog/blob/main/environment.yml" target="_blank">here</a>.</p>
</section>
<section id="default-configuration-for-blog-posts" class="level2">
<h2 class="anchored" data-anchor-id="default-configuration-for-blog-posts">Default configuration for blog posts</h2>
<p>This setup properties that will be inherited by all posts.</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>posts/_metadata.yml</strong></pre>
</div>
<div class="sourceCode" id="annotated-cell-20" data-filename="posts/_metadata.yml" style="background: #f1f3f5;"><pre class="sourceCode yaml code-annotation-code code-with-copy code-annotated"><code class="sourceCode yaml"><span id="annotated-cell-20-1"></span>
<span id="annotated-cell-20-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># options specified here will apply to all posts in this folder</span></span>
<span id="annotated-cell-20-3"></span>
<span id="annotated-cell-20-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># freeze computational output</span></span>
<span id="annotated-cell-20-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># (see https://quarto.org/docs/projects/code-execution.html#freeze)</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-20" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="annotated-cell-20-6" class="code-annotation-target"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">freeze</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">true</span></span>
<span id="annotated-cell-20-7"></span>
<span id="annotated-cell-20-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Enable banner style title blocks</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-20" data-target-annotation="2" onclick="event.preventDefault();">2</a><span id="annotated-cell-20-9" class="code-annotation-target"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">title-block-banner</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">true</span></span>
<span id="annotated-cell-20-10"></span>
<span id="annotated-cell-20-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Default for table of contents</span></span>
<span id="annotated-cell-20-12"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toc</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">true</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-20" data-target-annotation="3" onclick="event.preventDefault();">3</a><span id="annotated-cell-20-13" class="code-annotation-target"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toc-title</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Contents</span></span>
<span id="annotated-cell-20-14"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toc-location</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> left</span></span>
<span id="annotated-cell-20-15"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toc-expand</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="annotated-cell-20-16"></span>
<span id="annotated-cell-20-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Default author</span></span>
<span id="annotated-cell-20-18"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">author</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="annotated-cell-20-19"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Flavio Regis de Arruda</span></span>
<span id="annotated-cell-20-20"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">url</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> https://xboard.dev</span></span>
<span id="annotated-cell-20-21"></span>
<span id="annotated-cell-20-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Default fields for citation</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-20" data-target-annotation="4" onclick="event.preventDefault();">4</a><span id="annotated-cell-20-23" class="code-annotation-target"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">citation</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">false</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div>
</div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-20" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-20" data-code-lines="6" data-code-annotation="1">computational documents should never be re-rendered during a global project render</span>
</dd>
<dt data-target-cell="annotated-cell-20" data-target-annotation="2">2</dt>
<dd>
<span data-code-cell="annotated-cell-20" data-code-lines="9" data-code-annotation="2">create a banner style <a href="https://quarto.org/docs/authoring/title-blocks.html#title-banners" target="_blank">title block</a></span>
</dd>
<dt data-target-cell="annotated-cell-20" data-target-annotation="3">3</dt>
<dd>
<span data-code-cell="annotated-cell-20" data-code-lines="13" data-code-annotation="3">table of content title</span>
</dd>
<dt data-target-cell="annotated-cell-20" data-target-annotation="4">4</dt>
<dd>
<span data-code-cell="annotated-cell-20" data-code-lines="23" data-code-annotation="4">do not show <a href="https://quarto.org/docs/reference/metadata/citation.html" target="_blank">citation metadata</a>.</span>
</dd>
</dl>
</section>
<section id="enabling-commenting" class="level2">
<h2 class="anchored" data-anchor-id="enabling-commenting">Enabling commenting</h2>
<p>I have chosen <a href="https://quarto.org/docs/reference/projects/websites.html#giscus" target="_blank">Giscus app</a> to leverage <a href="https://docs.github.com/en/discussions" target="_blank">Github Discussions</a> as commenting platform in my posts.</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>_quarto.yml</strong></pre>
</div>
<div class="sourceCode" id="annotated-cell-21" data-filename="_quarto.yml" style="background: #f1f3f5;"><pre class="sourceCode yaml code-annotation-code code-with-copy code-annotated"><code class="sourceCode yaml"><span id="annotated-cell-21-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">website</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="annotated-cell-21-2"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">comments</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="annotated-cell-21-3"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">giscus</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-21" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="annotated-cell-21-4" class="code-annotation-target"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">repo</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> xboard/quarto-blog</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-21" data-target-annotation="2" onclick="event.preventDefault();">2</a><span id="annotated-cell-21-5" class="code-annotation-target"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">repo-id</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> R_kgDOJ7r2SQ</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-21" data-target-annotation="3" onclick="event.preventDefault();">3</a><span id="annotated-cell-21-6" class="code-annotation-target"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">category</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Announcements</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-21" data-target-annotation="4" onclick="event.preventDefault();">4</a><span id="annotated-cell-21-7" class="code-annotation-target"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">category-id</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> DIC_kwDOJ7r2Sc4CX95f</span></span>
<span id="annotated-cell-21-8"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loading</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> lazy</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div>
</div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-21" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-21" data-code-lines="4" data-code-annotation="1">the Github repo that will be used to store comments.</span>
</dd>
<dt data-target-cell="annotated-cell-21" data-target-annotation="2">2</dt>
<dd>
<span data-code-cell="annotated-cell-21" data-code-lines="5" data-code-annotation="2">found using <a href="https://giscus.app/" target="_blank">https://giscus.app/</a></span>
</dd>
<dt data-target-cell="annotated-cell-21" data-target-annotation="3">3</dt>
<dd>
<span data-code-cell="annotated-cell-21" data-code-lines="6" data-code-annotation="3">discussion category in Github Discussions</span>
</dd>
<dt data-target-cell="annotated-cell-21" data-target-annotation="4">4</dt>
<dd>
<span data-code-cell="annotated-cell-21" data-code-lines="7" data-code-annotation="4">found using <a href="https://giscus.app/" target="_blank">https://giscus.app/</a></span>
</dd>
</dl>
<p>after this at the bottom of every post you will see the Giscus integration in action:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://www.xboard.dev/posts/2023_07_17_migrating_from_fastpages_to_quarto/images/post_comments.png" class="img-fluid figure-img"></p>
<figcaption>Giscus widget for commenting and reactions</figcaption>
</figure>
</div>
</section>
<section id="setup-footer" class="level2">
<h2 class="anchored" data-anchor-id="setup-footer">Setup footer</h2>
<p>Footer message to be displayed (centered) in all my pages:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>_quarto.yml</strong></pre>
</div>
<div class="sourceCode" id="cb20" data-filename="_quarto.yml" style="background: #f1f3f5;"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb20-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">website</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb20-2"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">page-footer</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">:</span></span>
<span id="cb20-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">    center</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">: </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">|</span></span>
<span id="cb20-4">      Made with Data, ❤️, 🐍 and [Quarto](https://quarto.org). License: [CC BY-SA 2.0](https://creativecommons.org/licenses/by-sa/2.0/).</span></code></pre></div>
</div>
</section>
<section id="vscode" class="level2">
<h2 class="anchored" data-anchor-id="vscode">VSCode</h2>
<p>I love to use <a href="https://code.visualstudio.com/" target="_blank">Visual Studio Code</a> to write my blogs posts and I was very pleased to discover it has an excellent <a href="https://quarto.org/docs/tools/vscode.html" target="_blank">Quarto extension</a>.</p>
<section id="installing-vs-code-quarto-extension" class="level3">
<h3 class="anchored" data-anchor-id="installing-vs-code-quarto-extension">Installing VS Code Quarto extension</h3>
<p>To install the <a href="https://marketplace.visualstudio.com/items?itemName=quarto.quarto" target="_blank">Quarto extension</a> type (Ctrl+P), type:</p>
<div class="sourceCode" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode txt code-with-copy"><code class="sourceCode default"><span id="cb21-1">ext install quarto.quarto</span></code></pre></div>
<p>and press enter.</p>
<p>Some of the features this extensions includes:</p>
<ul>
<li>Integrated render and preview for Quarto documents.</li>
<li>Syntax highlighting for markdown and embedded languages</li>
<li>Completion and diagnostics for YAML options</li>
<li>Completion for embedded languages (e.g.&nbsp;Python, R, Julia, etc.)</li>
<li>Commands and key-bindings for running cells and selected lines.</li>
<li>Live preview for LaTeX math as well as Mermaid and Graphviz diagrams</li>
</ul>
</section>
<section id="adding-snippet" class="level3">
<h3 class="anchored" data-anchor-id="adding-snippet">Adding snippet</h3>
</section>
<section id="enabling-inline-suggestion" class="level3">
<h3 class="anchored" data-anchor-id="enabling-inline-suggestion">Enabling inline suggestion</h3>
<p>Set <code>Snippet suggestions</code> to <code>inline</code> as recommended <a href="https://stackoverflow.com/a/74339599/483157" target="_blank">here</a>.</p>
</section>
<section id="adding-spell-checker" class="level3">
<h3 class="anchored" data-anchor-id="adding-spell-checker">Adding spell checker</h3>
<p>Installed <a href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker" target="_blank">Code Spell checker</a>.</p>
<p>and them after clicking the spell button at the button at the editor bottom right I enabled its support to Quarto on my workspace.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://www.xboard.dev/posts/2023_07_17_migrating_from_fastpages_to_quarto/images/code_spell_checker_quarto.png" class="img-fluid figure-img"></p>
<figcaption>Enabling Quarto for Code Spell Checker</figcaption>
</figure>
</div>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>In summary, Quarto provides me with a powerful and versatile platform to write my technical blog posts as a Data Scientist and Python programmer. Its integration with Jupyter notebooks, support for multiple programming languages, customization options, collaboration features, and rendering capabilities make it the ideal choice for me to create high-quality, detailed, and engaging technical articles. With Quarto, I can focus on delivering content while enjoying a seamless and efficient writing experience.</p>
<p>In this post I have described in details all the steps that I did to migrated my posts from fastpages and how I configured Quarto to support the blog you are reading now.</p>
<p>If you were also using fastpages and intend to migrate, I hope it not only helps you in your decision process but also speeds up the setup of your new Quarto blog.</p>


</section>

 ]]></description>
  <category>meta</category>
  <category>quarto</category>
  <guid>https://www.xboard.dev/posts/2023_07_17_migrating_from_fastpages_to_quarto/</guid>
  <pubDate>Mon, 17 Jul 2023 03:00:00 GMT</pubDate>
  <media:content url="https://source.unsplash.com/npxXWgQ33ZQ" medium="image"/>
</item>
<item>
  <title>Interrupted Time Series (ITS) in Python</title>
  <dc:creator>Flavio Regis de Arruda</dc:creator>
  <link>https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/</link>
  <description><![CDATA[ 






<p><picture> <source type="image/webp" srcset="its-card.webp"> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/its-card.png" alt="Interrupted Time Series Analysis example" width="100%"> </picture></p>
<section id="when-ab-test-is-not-an-option" class="level2">
<h2 class="anchored" data-anchor-id="when-ab-test-is-not-an-option">When A/B test is not an option</h2>
<p>The gold standard for statistically asserting the effectiveness of an intervention is the randomized controlled experiment and its simplified online variant: the A/B test.</p>
<hr>
<p>📝 During an A/B test there are two almost identical versions of a product, simultaneously running, that only differ by the hypothesis you want to test ( i.e can a red call to action button convert more than a blue one? ). Users are <strong>randomly</strong> chosen to experience one (and only one) of the two versions while the experiment is active.</p>
<hr>
<p>They are easy to understand, easy to setup (great free <a href="https://optimize.google.com/optimize/home/">tools</a> easily available) and when correctly designed they rule out any covariate differences between the groups.</p>
<p>However, sometimes it’s just not possible to set up an A/B test:</p>
<ul>
<li><p>Technical difficulties. Sometimes a change is so widespread and complex that it would be technically impossible to keep two different versions running simultaneously.</p></li>
<li><p>Business strategy. A new feature rollout will be available first to some countries and later for others.</p></li>
<li><p>Ethical concerns. Having a subset of customers having access to a feature or bug fix that gives them a competitive advantage over others that don’t.</p></li>
<li><p>Legal or regulatory requirements. A change in regulations becomes mandatory ( i.e.&nbsp;GPDR compliance ) and should be applied to all your customers of a given country at the same time.</p></li>
<li><p>Temporal infeasibility. You want to analyze an event that has already happened ( i.e.&nbsp;How last <a href="https://moz.com/google-algorithm-change">Google’s search algorithm update</a> impacted your sales funnel? ).</p></li>
</ul>
</section>
<section id="quasi-experiments" class="level2">
<h2 class="anchored" data-anchor-id="quasi-experiments">Quasi Experiments</h2>
<p><picture> <source type="image/webp" srcset="the-gold-standard-meme.webp"> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/the-gold-standard-meme.jpg" class="lazyload" alt="gold standard meme" width="67%"> </picture></p>
<p>If you can’t do an A/B test then the second to best alternative are quasi experiments <a name="ref-1" href="https://shopify.engineering/using-quasi-experiments-counterfactuals" target="blank" rel="noopener">[1]</a>.</p>
<p>In a quasi experiment, your treatment and control group are not divided by a completely random process but by a natural process (i.e.&nbsp;time, location, etc) therefore there is a much larger chance for imbalance due to skewness and heterogeneous differences. The results of a quasi-experiment won’t be as precise as an A/B, but if carefully conducted could be considered close enough to compute estimates.</p>
<p>There are some scenarios, like some described in the previous section, where having a control group in parallel to a test group is just not possible, and this is when Interrupted Times Series comes in very handy.</p>
</section>
<section id="interrupted-time-series-its" class="level2">
<h2 class="anchored" data-anchor-id="interrupted-time-series-its">Interrupted Time Series (ITS)</h2>
<p>Interrupted time series (ITS) is a method of statistical analysis involving tracking a period before and after a intervention at a known point in time to assess the intervention’s effects <em>within a single group/population</em>. The time series refers to the data over the period, while the interruption is the intervention, which is a controlled external influence or set of influences. Effects of the intervention are evaluated by changes in the level and slope of the time series and statistical significance of the intervention parameters <a name="ref-2" href="https://en.wikipedia.org/wiki/Interrupted_time_series" target="blank" rel="noopener">[2]</a>. The more observations you have before and after the intervention, the more robust your model will be (typically). Because the evaluation is based on observing a single population over time, the ITS design is free from problems due to between-group difference but are susceptible to time-varying confounders like other interventions occurring around the time of the intervention that may also affect the outcome <a name="ref-3" href="https://scholar.google.com/scholar_lookup?title=Experimental%20and%20Quasi-experimental%20Designs%20for%20Research&amp;author=DT%20Campbell&amp;author=JC%20Stanley&amp;publication_year=1963&amp;book=Experimental%20and%20Quasi-experimental%20Designs%20for%20Research" target="blank" rel="noopener">[3]</a>.</p>
<p><picture> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/its1.jpg" class="lazyload" alt="Interrupted Time Series analysis example" width="100%" style="box-shadow: 5px 5px 10px grey;"> </picture></p>
<hr>
<p>👍 <span style="text-decoration: underline">Strengths of Interrupted Time Series</span> include the ability to control for secular trends in the data (unlike a 2-period before-and-after <img src="https://latex.codecogs.com/png.latex?t">-test), ability to evaluate outcomes using population-level data, clear graphical presentation of results, ease of conducting stratified analyses, and ability to evaluate both intended and unintended consequences of interventions.</p>
<p>👎 <span style="text-decoration: underline">Limitations of Interrupted Time Series</span> include the need for a minimum of 8 time periods before and 8 after an intervention to evaluate changes statistically, difficulty in analyzing the independent impact of separate components of a program that are implemented close together in time, and existence of a suitable control population.</p>
<hr>
<p>In mathematical terms, it means that the time series equation <img src="https://latex.codecogs.com/png.latex?(1)"> includes four key coefficients:</p>
<p><span style="display: table; margin: 0 auto;"> <img src="https://latex.codecogs.com/png.latex?Y%20=%20b_0%20+%20b_1T%20+%20b_2D%20+%20b_3P%20+%20%5Cepsilon"> </span></p>
<p>Where:</p>
<p><img src="https://latex.codecogs.com/png.latex?Y"> is the outcome variable;</p>
<p><img src="https://latex.codecogs.com/png.latex?T"> is a continuous variable which indicates the time passed from start of the observational period;<br></p>
<p><img src="https://latex.codecogs.com/png.latex?D"> is a dummy variable indicating observation collected before (<img src="https://latex.codecogs.com/png.latex?D=0">) or after (<img src="https://latex.codecogs.com/png.latex?D=1">) the intervention;<br></p>
<p><img src="https://latex.codecogs.com/png.latex?P"> is a continuous variable indicating time passed since the intervention has occurred (before intervention has occurred <img src="https://latex.codecogs.com/png.latex?P">is equal to <img src="https://latex.codecogs.com/png.latex?0">);<br></p>
<p>With <img src="https://latex.codecogs.com/png.latex?%5Cepsilon"> representing a zero centered gaussian random error.</p>
<section id="counterfactual" class="level3">
<h3 class="anchored" data-anchor-id="counterfactual">Counterfactual</h3>
<picture> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/matrix-red-blue-pill.png" class="lazyload" alt="matrix blue/red pill choice of reality" width="100%"> </picture>
<figcaption>
<i>What would have happened had Neo chosen the blue pill?</i>
</figcaption>
<p>In an ITS it is important to understand the counterfactual. The counterfactual refers to what it would have occurred to Y, had the policy intervention not happened.</p>
<hr>
<p>📝Counterfactuals are simply ways of comparing what happens given a change, versus what should have happened had some change not occurred in the first place.</p>
<hr>
<p>In a randomized trial or A/B test we know the counterfactual average outcome because the experiment withheld the intervention from the control group (which by randomization is somewhat the same as the intervention group). A critical assumption in ITS is that the outcome of interest trend would remain unchanged in the absence of intervention.</p>
</section>
</section>
<section id="a-practical-example" class="level2">
<h2 class="anchored" data-anchor-id="a-practical-example">A practical example</h2>
<p>Bob runs a large and successful blog on personal finance. During a webinar he learns that making his web content load faster could reduce its <a href="https://en.wikipedia.org/wiki/Bounce_rate">bounce rate</a> and therefore decides to sign up for a <a href="https://en.wikipedia.org/wiki/Content_delivery_network">CDN</a> service. It’s been 6 months since he added a CDN to his blog and he wants to know if the investiment he did reduced the bounce rate.</p>
<section id="dataset" class="level3">
<h3 class="anchored" data-anchor-id="dataset">Dataset</h3>
<p>Bob provides us with <a href="raw_data.csv">💾 24 weeks of data</a> before adding the CDN and 24 weeks after it (intervention). Therefore, weeks 1 to 24 have a bouncing rate before intervention and weeks 25 to 48 after it.</p>
<p align="center">
<picture> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/data_viz1.svg" class="lazyload" alt="ploting data collected" width="100%" style="box-shadow: 5px 5px 10px grey;"> </picture>
</p>
<p>Visually, it looks like after enabling the CDN the bounce rate decreased, but by how much, and does it have statistical significance? To answer this question using interrupted time series analysis, we first need to prepare our data.</p>
</section>
<section id="dataset-preparation" class="level3">
<h3 class="anchored" data-anchor-id="dataset-preparation">Dataset preparation</h3>
<p>Using equation (1) notation we <a href="enriched_data.csv">💾 enrich this data</a> with values for columns <img src="https://latex.codecogs.com/png.latex?D"> (<img src="https://latex.codecogs.com/png.latex?0"> = before intervention, <img src="https://latex.codecogs.com/png.latex?1"> after) and <img src="https://latex.codecogs.com/png.latex?P"> (number of weeks since intervention started):</p>
<table class="caption-top table">
<colgroup>
<col style="width: 28%">
<col style="width: 17%">
<col style="width: 27%">
<col style="width: 26%">
</colgroup>
<thead>
<tr class="header">
<th style="text-align: center;">Bouncing rate<br>(Y)</th>
<th style="text-align: center;">Week <br>(T)</th>
<th style="text-align: center;">Intervention<br>(D)</th>
<th style="text-align: center;">Intervention week<br>(P)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: center;">12.92</td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">0</td>
<td style="text-align: center;">0</td>
</tr>
<tr class="even">
<td style="text-align: center;">13.03</td>
<td style="text-align: center;">2</td>
<td style="text-align: center;">0</td>
<td style="text-align: center;">0</td>
</tr>
<tr class="odd">
<td style="text-align: center;">13.06</td>
<td style="text-align: center;">3</td>
<td style="text-align: center;">0</td>
<td style="text-align: center;">0</td>
</tr>
<tr class="even">
<td style="text-align: center;">13.17</td>
<td style="text-align: center;">4</td>
<td style="text-align: center;">0</td>
<td style="text-align: center;">0</td>
</tr>
<tr class="odd">
<td style="text-align: center;">…</td>
<td style="text-align: center;">…</td>
<td style="text-align: center;">…</td>
<td style="text-align: center;">…</td>
</tr>
<tr class="even">
<td style="text-align: center;">12.04</td>
<td style="text-align: center;">45</td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">21</td>
</tr>
<tr class="odd">
<td style="text-align: center;">12.45</td>
<td style="text-align: center;">46</td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">22</td>
</tr>
<tr class="even">
<td style="text-align: center;">12.74</td>
<td style="text-align: center;">47</td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">23</td>
</tr>
<tr class="odd">
<td style="text-align: center;">12.57</td>
<td style="text-align: center;">48</td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">24</td>
</tr>
</tbody>
</table>
</section>
</section>
<section id="naive-solution" class="level2">
<h2 class="anchored" data-anchor-id="naive-solution">Naive solution</h2>
<p>Let’s implement an ordinary least squares (OLS) regression using <code>statsmodels</code> to measure the impact of our intervention:</p>
<div class="sourceCode" 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> statsmodels.api <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sm</span>
<span id="cb1-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> statsmodels.formula.api <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> smf</span>
<span id="cb1-4"></span>
<span id="cb1-5">df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.read_csv(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"enriched_data.csv"</span>)</span>
<span id="cb1-6"></span>
<span id="cb1-7">model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> smf.ols(formula<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Y ~ T + D + P'</span>, data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df)</span>
<span id="cb1-8">res <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> model.fit()</span>
<span id="cb1-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(res.summary())</span></code></pre></div>
<p><span id="ols-output">With output:</span></p>
<pre>                            OLS Regression Results                            
==============================================================================
Dep. Variable:                      Y   R-squared:                       0.666
Model:                            OLS   Adj. R-squared:                  0.643
Method:                 Least Squares   F-statistic:                     29.18
Date:                Tue, 28 Dec 2021   Prob (F-statistic):           1.52e-10
Time:                        14:33:50   Log-Likelihood:                 4.8860
No. Observations:                  48   AIC:                            -1.772
Df Residuals:                      44   BIC:                             5.713
Df Model:                           3                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P&gt;|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept     12.9100      0.096    134.225      0.000      12.716      13.104
T              0.0129      0.007      1.920      0.061      -0.001       0.026
D             -0.5202      0.132     -3.942      0.000      -0.786      -0.254
P             -0.0297      0.010     -3.115      0.003      -0.049      -0.010
==============================================================================
Omnibus:                        3.137   Durbin-Watson:                   0.665
Prob(Omnibus):                  0.208   Jarque-Bera (JB):                1.995
Skew:                           0.279   Prob(JB):                        0.369
Kurtosis:                       2.172   Cond. No.                         125.
==============================================================================

</pre>
<p>The model estimates that the bounce rate decreased 🔻 0.52% and this effect is statistically significant (<img src="https://latex.codecogs.com/png.latex?P%3E%7Ct%7C"> is virtually zero).</p>
<p>It is also noteworth that the model estimates a small (on average 🔻 0.0297%) but with statistical significance trend of a decrease in bounce rate each week after intervention, which is unexpected since the CDN serves the whole website just a few hours after activation.</p>
<p>The figure below depicts how the model fits before and after intervention and how it project a counterfactual would be:</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"></span>
<span id="cb2-2">start <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span></span>
<span id="cb2-3">end <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">48</span></span>
<span id="cb2-4">beta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> res.params</span>
<span id="cb2-5"></span>
<span id="cb2-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Get model predictions and 95% confidence interval</span></span>
<span id="cb2-7">predictions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> res.get_prediction(df)</span>
<span id="cb2-8">summary <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> predictions.summary_frame(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>)</span>
<span id="cb2-9"></span>
<span id="cb2-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># mean predictions</span></span>
<span id="cb2-11">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> predictions.predicted_mean</span>
<span id="cb2-12"></span>
<span id="cb2-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># countefactual assumes no interventions</span></span>
<span id="cb2-14">cf_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> df.copy()</span>
<span id="cb2-15">cf_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"D"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span></span>
<span id="cb2-16">cf_df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P"</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.0</span></span>
<span id="cb2-17"></span>
<span id="cb2-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># counter-factual predictions</span></span>
<span id="cb2-19">cf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> res.get_prediction(cf_df).summary_frame(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>)</span>
<span id="cb2-20"></span>
<span id="cb2-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plotting</span></span>
<span id="cb2-22">plt.style.use(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seaborn-whitegrid'</span>)</span>
<span id="cb2-23">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>))</span>
<span id="cb2-24"></span>
<span id="cb2-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot bounce rate data</span></span>
<span id="cb2-26">ax.scatter(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>], df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Y"</span>], facecolors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'none'</span>, edgecolors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bounce rate data"</span>, linewidths<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb2-27"></span>
<span id="cb2-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot model mean bounce rate prediction</span></span>
<span id="cb2-29">ax.plot(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>][:start], y_pred[:start], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b-'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"model prediction"</span>)</span>
<span id="cb2-30">ax.plot(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>][start:], y_pred[start:], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b-'</span>)</span>
<span id="cb2-31"></span>
<span id="cb2-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot counterfactual mean bounce rate with 95% confidence interval</span></span>
<span id="cb2-33">ax.plot(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>][start:], cf[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean'</span>][start:], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k.'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"counterfactual"</span>)</span>
<span id="cb2-34">ax.fill_between(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>][start:], cf[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean_ci_lower'</span>][start:], cf[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean_ci_upper'</span>][start:], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"counterfactual 95% CI"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-35"></span>
<span id="cb2-36"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot line marking intervention moment</span></span>
<span id="cb2-37">ax.axvline(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">24.5</span>, color <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>, label <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'intervention'</span>)</span>
<span id="cb2-38"></span>
<span id="cb2-39">ax.legend(loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'best'</span>)</span>
<span id="cb2-40">plt.ylim([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>])</span>
<span id="cb2-41">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Weeks"</span>)</span>
<span id="cb2-42">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bounce rate (%)"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div>
<p align="center">
<picture> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/data_trends1.png" class="lazyload" alt="Interrupted Time Series using OLS with counterfactual and pos-intervention plots" width="100%" style="box-shadow: 5px 5px 10px grey;"> </picture>
</p>
<section id="problems-with-naive-approach" class="level3">
<h3 class="anchored" data-anchor-id="problems-with-naive-approach">Problems with naive approach</h3>
<p align="center">
<picture> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/autocorrelation_future_meme.jpg" class="lazyload" alt="predicts the future forgets temporal autocorrelation meme" width="67%"> </picture>
</p>
<p>OLS (Ordinary Least Squares) regression has <a href="https://www.datasciencecentral.com/profiles/blogs/7-classical-assumptions-of-ordinary-least-squares-ols-linear">seven main assumptions</a> but for brevity in this article we will focus on two only:</p>
<ul>
<li>Individual observations are <em>independent</em>.</li>
<li>Residuals follow a normal distribution.</li>
</ul>
<section id="lets-first-check-for-the-normality-of-residuals" class="level4">
<h4 class="anchored" data-anchor-id="lets-first-check-for-the-normality-of-residuals">Let’s first check for the normality of residuals:</h4>
<p>We can apply the <a href="https://en.wikipedia.org/wiki/Jarque%E2%80%93Bera_test">Jarque-Bera test</a> on residuals to checks whether their skewness and kurtosis match a normal distribution (<img src="https://latex.codecogs.com/png.latex?H_0">: residual distribution follows a normal distribution). Our <code>statsmodels</code> OLS summary output shows a <code>Prob(JB): 0.369</code> which for a standard <img src="https://latex.codecogs.com/png.latex?%5Calpha"> level of 0.05 doesn’t allow us discard null hypothesis (<img src="https://latex.codecogs.com/png.latex?H_0">).</p>
<p><span id="ols-residuals-kde">Let’s plot the distribution of residuals:</span></p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1">    res.resid.plot(kind<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"kde"</span>)</span></code></pre></div>
<p align="center">
<picture> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/ols_res_kde.png" class="lazyload" alt="ols residual distribution plot" width="80%" style="box-shadow: 5px 5px 10px grey;"> </picture>
</p>
<p>Which for a small dataset (less than 50 points) looks sufficiently gaussian.</p>
<p>Overall, the assumption of normality of residuals can’t be convincingly refuted. ✅</p>
</section>
<section id="checking-independence-of-observations" class="level4">
<h4 class="anchored" data-anchor-id="checking-independence-of-observations">Checking independence of observations:</h4>
<p>The <a href="https://en.wikipedia.org/wiki/Durbin%E2%80%93Watson_statistic">Durbin-Watson statistic</a> test if the residuals are correlated with its immediate predecessor, that is, if they have an autocorrelation at lag 1 or <img src="https://latex.codecogs.com/png.latex?AR(1)">. Its value ranges from 0 to 4 and values smaller than 1.5 indicate a positive autocorrelation, while values greater than 2.5 signal a negative autocorrelation.</p>
<p>If we take a look again at our OLS summary output we will observe that the Durbin-Watson statistic has a value of 0.665 which signals a strong positive <img src="https://latex.codecogs.com/png.latex?AR(1)">.</p>
<p><span id="ols-residuals-plot">Let’s plot the residuals to see if we can observe this autocorrelation:</span></p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> altair <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> alt</span>
<span id="cb4-2"></span>
<span id="cb4-3">rules <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> alt.Chart(pd.DataFrame({</span>
<span id="cb4-4">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'residuals'</span>: [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>],</span>
<span id="cb4-5">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'color'</span>: [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'black'</span>]</span>
<span id="cb4-6">})).mark_rule().encode(</span>
<span id="cb4-7">  y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'residuals'</span>,</span>
<span id="cb4-8">  color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>alt.Color(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'color:N'</span>, scale<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>)</span>
<span id="cb4-9">)</span>
<span id="cb4-10"></span>
<span id="cb4-11">residual_plot <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> alt.Chart(res_df).mark_point().encode(</span>
<span id="cb4-12">    x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>alt.X(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Weeks'</span>),</span>
<span id="cb4-13">    y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>alt.Y(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'residuals'</span>)</span>
<span id="cb4-14">)</span>
<span id="cb4-15"></span>
<span id="cb4-16">rules <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> residual_plot </span></code></pre></div>
<p align="center">
<picture> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/data_viz_residuals.svg" class="lazyload" alt="ols visualization of residuals" width="100%" style="box-shadow: 5px 5px 10px grey;"> </picture>
</p>
<p>Notice how residuals above/below zero have most points temporally close to it also above/below zero as well, which goes against the independence of observations assumption of OLS ❌.</p>
<hr>
<p>📝In practice when analyzing time series data the presence of autocorrelation is the rule instead of the exception since in general the factors that contributed to a given observation tend to persist for a while.</p>
<hr>
</section>
</section>
</section>
<section id="autoregressive-model-solution" class="level2">
<h2 class="anchored" data-anchor-id="autoregressive-model-solution">Autoregressive model solution</h2>
<p>The autoregressive model specifies that each observation depends linearly on previous observations.</p>
<p>Thus, an autoregressive model of order <img src="https://latex.codecogs.com/png.latex?p"> (<img src="https://latex.codecogs.com/png.latex?AR(p)">) can be written as</p>
<p><span style="display: table; margin: 0 auto;"> <img src="https://latex.codecogs.com/png.latex?y_t%20=%20c%20+%20%5Cphi_1%20y_%7Bt-1%7D+%20%5Cdots%20+%20%5Cphi_p%20y_%7Bt-p%7D%20+%20%5Cepsilon_t"> </span></p>
<p>Where:</p>
<p><img src="https://latex.codecogs.com/png.latex?y_t">: observation at time <img src="https://latex.codecogs.com/png.latex?t">,</p>
<p><img src="https://latex.codecogs.com/png.latex?y_%7Bt-i%7D">: observation at time <img src="https://latex.codecogs.com/png.latex?t%20-%20i">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cphi_i">: coefficient of how much observation <img src="https://latex.codecogs.com/png.latex?y_%7Bt%20-%20i%7D"> correlates to <img src="https://latex.codecogs.com/png.latex?y_t">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cepsilon_t">: white noise ( <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BN%7D(0,%20%5Csigma%C2%B2)"> ) at time <img src="https://latex.codecogs.com/png.latex?t">.</p>
<section id="autocorrelation" class="level4">
<h4 class="anchored" data-anchor-id="autocorrelation">Autocorrelation</h4>
<p>To assess how much an observation correlates with past observations it is useful to do an autocorrelation plot as shown below:</p>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1">sm.graphics.tsa.plot_acf(res.resid, lags<span 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="cb5-2">plt.show()</span></code></pre></div>
<p align="center">
<picture> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/autocorrelation.png" class="lazyload" alt="autocorrelation plot" width="100%" style="box-shadow: 5px 5px 10px grey;"> </picture>
</p>
</section>
<section id="partial-autocorrelation" class="level4">
<h4 class="anchored" data-anchor-id="partial-autocorrelation">Partial Autocorrelation</h4>
<p>The partial autocorrelation at lag <img src="https://latex.codecogs.com/png.latex?p"> is the correlation that results after removing the effect of any correlations due to the terms at shorter lags.</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">sm.graphics.tsa.plot_pacf(res.resid, lags<span 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="cb6-2">plt.show()   </span></code></pre></div>
<p align="center">
<picture> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/partial_autocorrelation.png" class="lazyload" alt="partial autocorrelation plot" width="100%" style="box-shadow: 5px 5px 10px grey;"> </picture>
</p>
</section>
<section id="model-selection" class="level3">
<h3 class="anchored" data-anchor-id="model-selection">Model selection</h3>
<p>The theory states that in an autoregressive model its autocorrelation plot should depict an exponential decay and the number of lags <img src="https://latex.codecogs.com/png.latex?p"> should be taken from the partial autocorrelation chart using its <img src="https://latex.codecogs.com/png.latex?p"> most relevant lags. Applying the theory to our plots above, we conclude that our model is autoregressive of lag 1 also known as AR(1).</p>
</section>
<section id="arima" class="level3">
<h3 class="anchored" data-anchor-id="arima">ARIMA</h3>
<p>In statistics <a href="https://en.wikipedia.org/wiki/Autoregressive_integrated_moving_average">ARIMA</a> stands for <strong>autoregressive integrated moving average</strong> model and as can be inferred by the name AR models are as especial case of ARIMA therefore AR(1) is equivalent to ARIMA(1,0,0).</p>
<p>We can model an AR(1) process to our dataset using <code>statsmodels</code> ARIMA as below:</p>
<div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.tsa.arima.model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> ARIMA</span>
<span id="cb7-2"></span>
<span id="cb7-3">arima_results <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ARIMA(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Y"</span>], df[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"D"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"P"</span>]], order<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)).fit()</span>
<span id="cb7-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(arima_results.summary())</span></code></pre></div>
<p>Output:</p>
<pre><code>                               SARIMAX Results                                
==============================================================================
Dep. Variable:                      Y   No. Observations:                   48
Model:                 ARIMA(1, 0, 0)   Log Likelihood                  18.574
Date:                Thu, 30 Dec 2021   AIC                            -25.148
Time:                        01:51:46   BIC                            -13.921
Sample:                             0   HQIC                           -20.905
                                 - 48                                         
Covariance Type:                  opg                                         
==============================================================================
                 coef    std err          z      P&gt;|z|      [0.025      0.975]
------------------------------------------------------------------------------
const         12.9172      0.279     46.245      0.000      12.370      13.465
T              0.0121      0.016      0.767      0.443      -0.019       0.043
D             -0.5510      0.273     -2.018      0.044      -1.086      -0.016
P             -0.0238      0.021     -1.155      0.248      -0.064       0.017
ar.L1          0.6635      0.138      4.803      0.000       0.393       0.934
sigma2         0.0267      0.006      4.771      0.000       0.016       0.038
===================================================================================
Ljung-Box (L1) (Q):                   1.00   Jarque-Bera (JB):                 0.15
Prob(Q):                              0.32   Prob(JB):                         0.93
Heteroskedasticity (H):               1.44   Skew:                            -0.05
Prob(H) (two-sided):                  0.47   Kurtosis:                         3.25
===================================================================================</code></pre>
<p>The autoregressive model estimates that the bounce rate decreased 🔻 0.55% on average and this effect is statistically significant (<img src="https://latex.codecogs.com/png.latex?P%3E%7Ct%7C%20=%204.4%5C%25">, less than our <img src="https://latex.codecogs.com/png.latex?%5Calpha%20=%205%5C%25">).</p>
<p>However, unlike the previous OLS model, the autoregressive model does not estimate a statistical significance trend of a decrease in bounce rate each week after intervention, which is in line with our expectations.</p>
<p>The models estimates (with counterfactual projections) can be seen in the chart below:</p>
<div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"></span>
<span id="cb9-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.tsa.arima.model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> ARIMA</span>
<span id="cb9-3"></span>
<span id="cb9-4">start <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span></span>
<span id="cb9-5">end <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">48</span></span>
<span id="cb9-6"></span>
<span id="cb9-7">predictions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> arima_results.get_prediction(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, end<span 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="cb9-8">summary <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> predictions.summary_frame(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>)</span>
<span id="cb9-9"></span>
<span id="cb9-10">arima_cf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ARIMA(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Y"</span>][:start], df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>][:start], order<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)).fit()</span>
<span id="cb9-11"></span>
<span id="cb9-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Model predictions means</span></span>
<span id="cb9-13">y_pred <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> predictions.predicted_mean</span>
<span id="cb9-14"></span>
<span id="cb9-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Counterfactual mean and 95% confidence interval</span></span>
<span id="cb9-16">y_cf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> arima_cf.get_forecast(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>, exog<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>][start:]).summary_frame(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>)</span>
<span id="cb9-17"></span>
<span id="cb9-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot section</span></span>
<span id="cb9-19">plt.style.use(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'seaborn-whitegrid'</span>)</span>
<span id="cb9-20">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>))</span>
<span id="cb9-21"></span>
<span id="cb9-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot bounce rate data</span></span>
<span id="cb9-23">ax.scatter(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>], df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Y"</span>], facecolors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'none'</span>, edgecolors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'steelblue'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bounce rate data"</span>, linewidths<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb9-24"></span>
<span id="cb9-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot model mean bounce prediction</span></span>
<span id="cb9-26">ax.plot(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>][:start], y_pred[:start], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b-'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"model prediction"</span>)</span>
<span id="cb9-27">ax.plot(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>][start:], y_pred[start:], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b-'</span>)</span>
<span id="cb9-28"></span>
<span id="cb9-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot counterfactual mean bounce rate with 95% confidence interval</span></span>
<span id="cb9-30">ax.plot(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>][start:], y_cf[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mean"</span>], <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k.'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"counterfactual"</span>)</span>
<span id="cb9-31">ax.fill_between(df[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"T"</span>][start:], y_cf[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean_ci_lower'</span>], y_cf[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mean_ci_upper'</span>], color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'k'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"counterfactual 95% CI"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-32"></span>
<span id="cb9-33"></span>
<span id="cb9-34"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot line marking intervention moment</span></span>
<span id="cb9-35">ax.axvline(x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">24.5</span>, color <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>, label <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'intervention'</span>)</span>
<span id="cb9-36"></span>
<span id="cb9-37">ax.legend(loc<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'best'</span>)</span>
<span id="cb9-38">plt.ylim([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>])</span>
<span id="cb9-39">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Weeks"</span>)</span>
<span id="cb9-40">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Bounce rate (%)"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div>
<p align="center">
<picture> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/data_trends2.png" class="lazyload" alt="arima pre and post intervention modeling with counterfactual" width="100%" style="box-shadow: 5px 5px 10px grey;"> </picture>
</p>
<p>We can clearly see that the ARIMA(1, 0, 0) model fits our dataset better than the OLS model.</p>
</section>
<section id="arima-residual-analysis" class="level3">
<h3 class="anchored" data-anchor-id="arima-residual-analysis">ARIMA residual analysis</h3>
<p>The summary of our autoregressive model shows a <code>Prob(JB): 0.93</code> which is compatible with the null-hypothesis of normaly distributed residuals. ✅</p>
<p>The <a href="https://en.wikipedia.org/wiki/Ljung%E2%80%93Box_test">Ljung-Box Q test</a> verifies whether the residuals are independently distributed (they exhibit no serial autocorrelation) as <img src="https://latex.codecogs.com/png.latex?H_0"> (null-hypothesis). As the <code>Prob(Q): 0.32</code> is way above the standard <img src="https://latex.codecogs.com/png.latex?%5Calpha%20=%200.05"> there is no evidence of serial autocorrelation in the ARIMA residuals. ✅</p>
<p>Let’s now take a look at residuals <a href="https://data.library.virginia.edu/understanding-q-q-plots/">qqplot</a> to check if they follow a normal distribution:</p>
<div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"></span>
<span id="cb10-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> scipy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sp</span>
<span id="cb10-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> statsmodels.graphics.gofplots <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> qqplot</span>
<span id="cb10-4"></span>
<span id="cb10-5">fig, (ax1, ax2) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(<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;">2</span>, figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>))</span>
<span id="cb10-6">sm.qqplot(res.resid, sp.stats.t, fit<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>, line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"45"</span>, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ax1)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-7">ax1.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OLS qqplot"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-8"></span>
<span id="cb10-9">sm.qqplot(arima_results.resid, sp.stats.t, fit<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>, line<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"45"</span>, ax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ax2)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-10">ax2.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ARIMA qqplot"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-11">plt.show()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div>
<p align="center">
<picture> <img src="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/qqplot-sidebyside.png" class="lazyload" alt="qqplots" width="80%" style="box-shadow: 5px 5px 10px grey;"> </picture>
</p>
<p>We may observe that the ARIMA(1,0,0) model residuals not only are in general normally distributed as they fit better than the OLS model the theoretical quantiles. ✅</p>
</section>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>A/B tests are a the most powerful and trustworthy method to do measure the impact of modifications/changes even before they are fully implemented, which is why they are so widely used.</p>
<p>However, there are some scenarios where A/B tests are not feasible and this is when the knowledge of quasi-experiments becomes valuable to get statistically sound measurements of change impact.</p>
<p>In this post we have shown why an ordinary least square (OLS) linear regression is not a good modeling approach for time series data since they usualy present non-negligible autocorrelation that violates some assumptions of OLS.</p>
<p>We demonstrated with an example how to use python (<code>statsmodels</code>, <code>matplotlib</code>, <code>altair</code> and <code>pandas</code>) to visualize residuals and plot autocorrelation and partial autocorrelations charts to figure out the lag of an autoregressive model and then implemented a ARIMA model using <code>statsmodels</code> to observed a more accurate and precise analysis and how to interpret <code>statsmodels</code> model output for OLS and ARIMA.</p>
<p>We also showed how to plot in a single chart the models estimates (mean and 95% confidence interval) for the time periods before and after intervention and its respective counterfactual.</p>
<p><span id="chegou-no-fim"></span></p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p><a name="ref-1" href="https://shopify.engineering/using-quasi-experiments-counterfactuals" target="blank" rel="noopener">[1] Shopify Engineering: How to Use Quasi-experiments and Counterfactuals to Build Great Products.</a></p>
<p><a name="ref-2" href="https://en.wikipedia.org/wiki/Interrupted_time_series" target="blank" rel="noopener">[2] Wikipedia: Interrupted Time Series.</a></p>
<p><a name="ref-3" href="https://scholar.google.com/scholar_lookup?title=Experimental%20and%20Quasi-experimental%20Designs%20for%20Research&amp;author=DT%20Campbell&amp;author=JC%20Stanley&amp;publication_year=1963&amp;book=Experimental%20and%20Quasi-experimental%20Designs%20for%20Research" target="blank" rel="noopener">[3] Campbell DT, Stanley JC. Experimental and Quasi-experimental Designs for Research. Boston, MA: Houghton Mifflin, 1963.</a></p>


</section>

 ]]></description>
  <category>data science</category>
  <category>causal inference</category>
  <category>python</category>
  <guid>https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/</guid>
  <pubDate>Sat, 01 Jan 2022 09:00:00 GMT</pubDate>
  <media:content url="https://www.xboard.dev/posts/2020_01_01_interrupted-time-series-python-part-I/its-card2.jpg" medium="image" type="image/jpeg"/>
</item>
</channel>
</rss>
